机械学习算法入门02

贝叶斯分类算法

一种先验概率计算后验概率的算法,什么是先验概率,啥是后验概率?

emmmmm,先走起来再找路,我先给出公式,然后再慢慢解释

P(AB)=P(A)P(BA)P(B)P(A|B)=\frac {P(A)*P(B|A)}{P(B)}

首先一个简单的问题,帮我们推导一下这个公式结果,

一所学校里面60%的男生,40%的女生.男生总是穿长裤,女生则一半穿长裤一半穿裙子

  1. 迎面走来一个人,这个人是男生的概率? %60 (这叫正向概率)

  2. 迎面走来一人,你高度近视,看不清楚男女,但是知道这个人穿的长裤,那么这个人是女生的概率 (这叫逆向概率)

第一个问题,通过统计可以直接的出,但第二个不能直接统计,而是根据已有的统计数据计算出来的

其解题思路如下 :

(假设学生总数为U)

计算出学校有多少人穿长裤

U60U\ast60\\%+U\ast40\\%\ast50\\%=0.8U

女生中,在总人数中穿长裤的人数

U40U\ast40\\%\ast50\\%=0.2U

穿长裤中女生的概率就是

女生的概率*女生中穿长裤的概率/总数中穿长裤的概率

P(女生长裤)=UP(女生)P(长裤女生)UP(长裤)P(女生|长裤)=\frac {U\ast P(女生)\ast P(长裤|女生)}{U\ast P(长裤)}

最后计算得出穿长裤情况下是女生的概率为0.25.

如果我们把女生替换成A,把长裤替换为B,公式如下

P(AB)=P(A)P(BA)P(B)P(A|B)=\frac{P(A)\ast P(B|A)}{P(B)}

这就是我们的贝叶斯公式,等号前面为后验概率,后面为先验概率

贝叶斯公式有很多相关的应用,比如接下来要聊的

通过验证邮件里的关键字来计算是垃圾邮件的概率.

比如说我们经过统计,邮件数据如下

邮件demo

总共一百封邮件

spam => 垃圾邮件

ham => 正常邮件

Viagra => 伟哥

我们可以计算出,

关键词出现的概率 P(Viagra)=5/100=0.05

垃圾邮件的概率P(spam)=20/100=0.2

垃圾邮件下关键词的概率P(Viagra|spam)=4/20=0.2

那么关键词出现情况下垃圾邮件的概率为

P(spamViagra)=P(spam)P(Viagraspam)P(Viagra)P(spam|Viagra)=\frac {P(spam)\ast P(Viagra \vert spam)}{P(Viagra)}

=0.20.20.05=\frac{0.2*0.2}{0.05}

=0.8=0.8

最后计算得出垃圾邮件的概率为0.8

这是一个简单的应用,如果邮件当中有多个关键字怎么计算呢?

比如说一封邮件当中有四个关键字,viagra,money,groceries,unsubscribe,以下是四个关键字的统计数据:

email02

有了这样的数据,我们就可以计算出任意关键字出现的概率,不过中间有些坑需要解决.

首先我们计算一下W_1和W_4(关键字太长,用括号里的代号代指)出现后是垃圾邮件的概率,那么就将概率代入到公式当中,不过有个坑就是我们W_1和W_4出现了,我们是否要把非W_2和非W_3的概率一起代入到公式的当中…

这个是当然的了,计算概率最需要的就是把所有的情况都考虑完全.

所以这样的话,我们的公式应该长这样子

P(spamW1W2W3W4)=P(spam)P(W1W2W3W4spam)P(W1W2W3W4)P(spam|W_1 \cap \overline {W_2} \cap \overline {W_3} \cap {W_4})= \frac {P(spam) \ast P(W_1 \cap \overline {W_2} \cap \overline {W_3} \cap W_4|spam)}{P(W_1 \cap \overline {W_2} \cap \overline {W_3} \cap W_4)}

然后问题又来了,我们这部分应该如何计算

P(W1W2W3W4)P(W_1 \cap \overline {W_2} \cap \overline {W_3} \cap W_4)

即,同时发生W1非W2非W3和W4的概率

其实,在贝叶斯算法中我们可以假设这四个是独立事件,所以直接概率相乘即可,这是贝叶斯公式的优点,也是贝叶斯的缺点(不准确,可能独立事件之间有联系)

那上面的分母我们也可以这么拆开

P(W1W2W3W4spam)=P(W1spam)P(W2spam)P(W3spam)P(W4spam)P(W_1 \cap \overline {W_2} \cap \overline {W_3} \cap W_4\vert spam) =P(W_1\vert spam) \ast P(\overline {W_2}|spam) \ast P({\overline W_3}\vert spam) \ast P(W_4\vert spam)

所以我们可以通过算法计算出

P(spamW1W2W3W4)P(spam|W_1 \cap \overline {W_2} \cap \overline {W_3} \cap {W_4})

的概率

,转换一下思想我们可以还可以通过算出

P(hamW1W2W3W4)=P(ham)P(W1W2W3W4ham)P(W1W2W3W4)P(ham|W_1 \cap \overline {W_2} \cap \overline {W_3} \cap {W_4})=\frac {P(ham) * P(W_1 \cap \overline {W_2} \cap \overline {W_3} \cap W_4|ham)}{P(W_1 \cap \overline {W_2} \cap \overline {W_3} \cap W_4)}

即正常邮件的中这种情况出现的概率,两者相除将分母约掉,来减少我们假设的独立事件对我们整个概率计算的影响

即,设W1,非W2,非W3和W4同时出现,垃圾邮件出现的概率为x,正常邮件出现的概率为y,

则会得出x+y=1,而通过x/y计算两者的分子得出值,两者的分子计算得出分别是0.012和0.002

{x+y=1x/y=6\begin{cases} x+y=1 \\ x/y=6 \end{cases}

即垃圾邮件的概率为0.857

还有一个问题就是,假如我计算四个关键字都出现的概率,代入公式会发现,W3垃圾邮件出现的概率为0,那么代入公式后整个公式也会为0,这和我们的直接经验都不相符,那如何去解决呢?

我们可以使用拉普拉斯平滑定理,在我们目前的零概率事件,根据经验认为的给出一些数据

就像现在这种情况,我们多给出四封垃圾邮件,每封邮件各包含一个关键字,我们的数据就变成了这样

email03

这样我们就可以通过贝叶斯分类器进行计算了

KNN算法(K近邻)

我们直接上概念:

如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别

  1. 计算预测的样本与空间中所有样本的距离
  2. 去除与当前样本距离最近的K个样本
  3. 统计这个K样本中,大部分属于哪一个类别
  4. 大部分属于哪一个类别,那么这个就可以预测出属于这个类别

其中我们的距离就有很多的概念,例如:

  1. 经典的欧式距离,取空间中两个点的值线距离,公式如下

    d=(x1x2)2+(y1y2)2d = \sqrt {(x_1-x_2)^2+(y_1-y_2)^2}

  2. 平方欧式距离

    d=(x1x2)2+(y1y2)2d=(x_1-x_2)^2+(y_1-y_2)^2

  3. 曼哈顿距离(曼哈顿这个城市没有斜向的路,地图上看就像围棋格一样,所以计算两点的距离,直接去xy差的绝对值相加),公式如下

    d=x1x2+y1y2d=\vert x_1-x_2 \vert + \vert y_1 - y_2 \vert

  4. 余弦距离(常应用于文本相似度)

    cosθ=x1x2+y1y2x12+y12+x22+y22cos\theta = \frac {x_1x_2+y_1y_2}{\sqrt {x_1^2+y_1^2}+\sqrt{x_2^2+y_2^2}}

  5. 闵科夫基距离 对一组距离的定义

    d12=k=1nx1kx2kpd_12=\sqrt {\sum_{k=1}^{n}\vert x_{1k} - x_{2k} \vert^p}

案例

我们通过一个案例来解释K近邻算法,

这是我们的数据,这是一个女生所约会男生的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
40920	8.326976	0.953952	3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
38344 1.669788 0.134296 1
72993 10.141740 1.032955 1
35948 6.830792 1.213192 3
42666 13.276369 0.543880 3
67497 8.631577 0.749278 1
35483 12.273169 1.508053 3
50242 3.723498 0.831917 1
63275 8.385879 1.669485 1
.....

数据当中,第一列约会男生的每年的飞行公里数,第二列表示约会男生的玩游戏的时间占工作时间的比例,第三列表示每周吃甜品的克数

最后表示女生的感觉分别是:“没感觉”,“看着还行”,“极具魅力”

首先我们看这些数据有一个特点,他们之间的数值差距很大,飞行公里数上千,但是玩游戏时间占比最多到13,15这样子,所以在我们进行计算的时候,有个问题就是,我们计算距离的时候,三列计算出来的距离的数据差异很大,

所以我们要对数据进行归一化,即将数据范围缩小到0到1之间,我们先使用最简单的,最大最小值归一化

求出数据中的最大最小值,将所有数据减去最小值再除以最大最小值差值,以此来完成归一化

当然最大最小值归一化,有一个缺点就是如果有离群值,就会导致归一化的数据分布不均匀,抗噪声能力差.

归一化数据如下

1
2
3
4
5
6
7
8
9
10
11
[0.44832535 0.39805139 0.56233353]
[0.15873259 0.34195467 0.98724416]
[0.28542943 0.06892523 0.47449629]
[0.82320073 0.62848007 0.25248929]
[0.42010233 0.07982027 0.0785783 ]
[0.79972171 0.48480189 0.60896055]
[0.39385141 0.32652986 0.71533516]
[0.46745478 0.63464542 0.32031191]
[0.73950675 0.41261212 0.44153637]
[0.38875681 0.58668982 0.88936006]
[0.55045851 0.17799301 0.49030933]

之后如果来了新的数据,我们将数据进行归一化后,计算特征的欧式距离,什么?你还不会算?这样子,我们将这三列特征分别命名为x,y,z

然后新进来一条数据,我们将它与所有数据的特征进行距离的计算,公式就是这样

d=(x1x2)2+(y1y2)2+(z1z2)2d = \sqrt {(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2}

计算出所有数据的距离后,我们定一个K值,比如说4,我们找与新进来数据距离最小的四个点,看它的标签属于1,2,3哪个类别,找出数量最多的类别,我们就把这条数据分到这类.

K近邻算法有一个问题,这个问题就是

假如我们全量的数据总共有三类,A类数目众多,B类C类很少,那我们我们来一条数据大概率就会被划分到A类,那么我们A会被划分的越来越多,类别数据会越来越倾斜,这种问题怎么解决?

可以分配权重,最终由数量乘以权重来划分,比如A类最多,我们就给它设置一个最小的权重

最后我们使用KNN算法要谨记的一点就是,我们的数据是什么样的,我们的模型就是什么样,如果我们输入一堆描述字母的数据,那我们的模型就可以识别字母,但它识别不了数字,中文.所以在应用算法的时候注意训练的数据源.

K-Means算法

K-Means是属于聚类算法的一种,前面我们聊的线型回归,贝叶斯,KNN算法都是分类算法,而K-Means算法是属于聚类算法.

是给数据分出一个本来没有的类别,寻找个体之间的一些潜在的相似模式.

聚类算法我们不需要提前告知所划分的组应该是什么样的.因为我们甚至都可能不知道我们再寻找什么,所以聚类是用于知识发现而不是预测

官方话就说到这里,我们举一个通俗的例子,假如我们的数据如下:

k-means

我们看到三堆数据应该很好的能分成三类,但是如何通过算法实际的找出他们的边界呢?

首先我们随机选取三个中心点

k-means

像上面这样,然后计算所有周围数据到中心点的距离,将距离近的N个点分为这个中心点的类别,比如绿色区域内的点,到绿点的距离近,我们就把他分为绿类

分好类的之后,可能我们分的类效果不好,因为第一次是随机选择的中心点,

所以我们会计算同一类里所有点的之间的距离,取所有距离的平均数,根据这个距离平均数重新选择中心点,这个可能是一个虚的中心点,也就是很大可能不与原有样本的坐标重合

新的中心点选好后,我们将新的中心点与就中心点对比,坐标没重合,如果没有重合,再进行最近距离分类

重复以上两个步骤,直到我们的新的中心点与上一次中心点坐标重合为止,最后数据分好类就像下面这样

k-means

但是有两个问题,

  1. 我们举出的这个例子,中心点的数量是先定下来的,实际k-means算法是人工输入的,我们的点的维度不可能只有二维这么简单,可能有四维,六维,甚至十几个维度,这样点我们根本无法用坐标系表示,那么我们在如何不知道数据全貌的情况下选取数据的数量呢?

  2. 点的坐标是随机的,如果我随机选择的一些点坐标正好在同一类里,那么可能分类效果不理想,比如说这样

k-means

分类出来的效果就像下面

k-means

首先我们说第二个问题,关于k-means随机点可能分到一类的问题,换个说法应该就是选取的随机点之间的距离可能很近.对,距离太近导致随机点可能被选到一个类别里面,那么我们让随机生成的点变的远一点不就可以了?

于是有了k-means算法,k-means算法就是这样,第一个中心点是随机选取的,但是第二个点,会尽可能的将其放到距离第一个点远的地方.之后每次选点都会选择比原来那些点尽量远的距离

那么第一个问题,在不知道数据什么样子的情况下,怎么知道选取多少个中心点,才能保证聚类的效果比较好呢?

首先,聚类效果怎么才算好,有两个标准:

  1. 类与类之间的差异很大
  2. 类内部的相似性很高

既然有标准,那么我们就可以统计出来K值(k-means的k就是指中心点的数量,或者分类的数量)和聚类效果的统计图,就像下面这样

arm_method

这样一个类内部相似性和类之间的差异就出来了,看到这里我们会发现,k的数量越多,分类效果越好,那我们能不能有多少条数据就分多少类呢?

当然不行,抛开数据计算量极大不说, k数量越多,就越有总结,汇总的那个味道,而不是摸索出规律了,也就是我们所说的过拟合了,所以我们一般用到收益衰减大幅下降的一个值,在我们统计图中也就是3或4这个值,因为这个统计图选取点的地方很像我们的胳膊肘的部分,所以又叫肘部法

案例–微博精准营销

上面我们聊了k-means聚类算法的实现步骤,下面我们来应用一下k-means算法

假如你是九阳豆浆机的营销员,那么需要我们豆浆机推给相关微博的用户,我们把近期所有带九阳这个词的微博都收集起来,数据就像下面这样

1
2
3
4
5
6
7
8
3794122458250724	元旦快乐@初见花妖娆 @九阳 @灵珊妹子 @潞亼曱 @喵喵铱 @杉菜1991 @天天小熊0307 @仙仙当妈了 @小1妈妈 @小米渣渣ye @轩仔娘66 @777xu @2012年1103 http://t.cn/RZ45gP7
3794122471133129 我去 我小时候就活在她的阴影下… 我爸天天数落我 说她人美歌甜 我不如她… //@曹三儿:我擦我童年的偶像 好想问问偶像二十台九阳牌豆浆机都怎么处理了
3794122684813854 #九阳有礼 无需多滤#陷入被窝温柔乡,起床靠毅力?九阳免滤豆浆机C668SG耀世首发![鼓掌][鼓掌][鼓掌][鼓掌]@西瓜ID322 @郭河九元 @白其颜
3794122773430712 九阳免滤豆浆机C668SG耀世首发,生活也免滤了,活动太给力了,@桐桐宝宝爱妈咪 @专扣岩石 @我是逗逼小倪
3794123050110641 九阳免滤豆浆机C668SG耀世首发,生活也免滤了,活动太给力了,@桐桐宝宝爱妈咪 @专扣岩石 @我是逗逼小倪
3794123138333079 这是一个九阳萌大叔与梁山小萝莉的故事,没有悬疑,没有穿越,只有纯纯的爱哦@九阳
3794124047684211 [馋嘴]2015年崭新的开始,一个人的早餐。@九阳
3794165483969427 #共创致爱巧克力 世界吉尼斯#我最亲最爱的朋友,我已经支持了,你还在等什么?动动你的手指吧! @九阳股份官方招聘 @Lily-Q糖糖 @geng小川 http://t.cn/RzQoTyA

前面是用户ID,后面是九阳微博的具体内容,我们会发现,有些九阳是被@的用户名,有的是公司名做投资的.我们不可能一条条的去看,去理解主旨.

那么,我们可以用聚类算法,我们们将这些微博的数据主旨一致的聚到一个类别当中,然后我们只要看每个类别的第一条微博,就知道这整个类别的主旨了.k-means在这个方向的应用有了,我们还有个问题就是,

这是一串串字符串,我们怎么将这些做成可以代入我们算法的向量

我们可以做一个词集,将微博中所有的词映射到这个词袋向量中,举个例子,比如说我们对微博文章进行分词之后,变成这样

1
2
I love her but she don't love me.
I love her and she love me too.

分词去重之后,我们将所有的词向量化,形成一个词表,每位的数字代表词出现的次数

1
2
[I,love,her,but,she,don't,me,and,too]
[2,4,2,1,2,1,2,1,1]

然后我们就可以将数据向量化

1
2
I love her,but she don't love me.
[1,1,1,1,1,1,1,0,0]

所以词袋模型就是将我们的所有文章词组成一个词表,根据词表的索引位映射,这位词有为1,没有为0

,然后我们就可以将向量化的数据代入到k-means算法里,

但是我们的词集模型依然有问题,因为我们每个词的词性是不一样的,有些词,词性很轻比如,的,得,啊等这些冠词或语气词,他们对代表文章或段落的主旨的比重很低,所以我们不能单纯的使用词集模型就可以直接代入.

词集与词袋模型不同之处在于,词集不仅用数字表示词汇是否有,还用数字表示这个词出现的频率

比如,上面词袋的第二句话变成

1
[1,2,1,0,1,0,1,1,1]

但是好像并没有给我们的词有一个均衡的重要性的配比,词的使用率高并不能代表词就很重要,能代表主旨,就像我们每篇文章都有很多"的"这个词,但是对代表主旨并没有什么意义

所以我们的TF-IDF算法就出来了

我们可以这样想,假如一个词在其他的所有文章出现的频率很低,但是在自己的文章的词的频率很高,这个词就越能代表我们的文章主旨

我们TF-IDF算法就是遵循这样的思想,其中TF即我们的词频公式如下

TF=某个词在本文章中出现的次数文章的总词数TF=\frac {某个词在本文章中出现的次数}{文章的总词数}

而IDF即逆文本频率指数,如下,该值越大,代表本文主旨的权重就越大

IDF=log语料库的文章总数包含该词的文章总数+1IDF = \log{\frac {语料库的文章总数}{包含该词的文章总数+1}}

而TF-IDF,即TF*IDF,对两值相乘,来作为我们词的最终权重,这就是要做的特征工程

这样我们就能代入算法进行模型的训练,和聚类了.