朴素贝叶斯法学习笔记
前言
最近开始学习《统计学习方法》中的朴素贝叶斯,朴素贝叶斯是在贝叶斯的基础上为了简化问题而做出的一种朴素假设。因此,想要理解朴素二字的含义必须先明白什么是贝叶斯。在看了两篇博文和书中的章节后,对贝叶斯产生了一种发自内心的敬仰之心,它的思想无处不在,一时半会是很难hold住这背后的贝叶斯哲学。参考的两篇博文为数学之美番外篇:平凡而又神奇的贝叶斯方法及算法杂货铺——分类算法之朴素贝叶斯分类(Naive Bayesian classification),个人首推第一篇博文,作者阅读之广,思考之深,令人佩服。当然第二篇属于贝叶斯的实际应用,也有一定的参考价值,但博文中有些例子个人觉得不太恰当,会在自己的学习记录过程中指出。
思考
- 贝叶斯提出的问题背景是什么?
- 贝叶斯是根据什么而推导出来的?
- 贝叶斯在统计学习中的应用
无处不在的贝叶斯
首先我们先给出贝叶斯公式,方便我们代号入座。
该公式是什么含义呢?如果单纯理解公式的话,它的意思是说在已知A的概率和B的概率,和在A发生的条件下B的概率,那么我们就能求得在B条件下A发生的概率。贝叶斯的公式在于,使得 P(B|A)和P(A|B) 建立起了桥梁。为何需要这桥梁呢?这背后的哲学就太深了,我们慢慢来阐述。
提到了贝叶斯公式,不能不提贝叶斯公式提出的问题背景,以下例子参考数学之美番外篇:平凡而又神奇的贝叶斯方法。
问题背景
所谓的贝叶斯方法源于他生前为解决一个“逆概”问题写的一篇文章,而这篇文章是在他死后才由他的一位朋友发表出来的。在贝叶斯写这篇文章之前,人们已经能够计算“正向概率”,如“假设袋子里面有N个白球,M个黑球,你伸手进去摸一把,摸出黑球的概率是多大”。而一个自然而然的问题是反过来:“如果我们事先并不知道袋子里面黑白球的比例,而是闭着眼睛摸出一个(或好几个)球,观察这些取出来的球的颜色之后,那么我们可以就此对袋子里面的黑白球的比例作出什么样的推测”。这个问题,就是所谓的逆概问题。
这个问题应该如何进行理论建模并且求解该参数呢?其实如果学过最大似然估计的话,这个问题就是经典的似然估计问题。而贝叶斯公式就把经典的求解最大似然估计方法和求解逆概问题建立起了一座桥梁。让这个参数求解问题便得不再遥不可及。这也是贝叶斯公式在统计学的重大应用。当然,这个例子还不够具体,我们再来看看更加直观具体的例子,来推导出贝叶斯公式,有了贝叶斯公式以及背后的思考哲学,我们再来求解这个问题。
一所学校里面有 60% 的男生,40% 的女生。男生总是穿长裤,女生则一半穿长裤一半穿裙子。有了这些信息之后我们可以容易地计算“随机选取一个学生,他(她)穿长裤的概率和穿裙子的概率是多大”,这个就是前面说的“正向概率”的计算。然而,假设你走在校园中,迎面走来一个穿长裤的学生(很不幸的是你高度近似,你只看得见他(她)穿的是否长裤,而无法确定他(她)的性别),你能够推断出他(她)是男生的概率是多大吗?
观察下这个问题与上个问题的区别在哪?其实很明显,上个问题中,我们并没有给出黑白球的比例,也就是我们要求解的参数,且我们只能观察到在随机取
n
次后,黑白球的比例。这是参数估计的问题,而在这个问题中男女生的比例已知,男生女生穿长裤的比例已知,给定这么多已知条件,只是由于我们高度近视,走在我们面前的人不知是男女,却知道是否穿长裤。我们对该问题进行建模,
1. 设是否穿长裤 paint =穿长裤
2. 设是否为男孩 boy = 男孩,girl = 女孩
3. 设在穿长裤条件下是男孩女孩的概率分别为 P(boy | paint) 和P(girl | paint)
4. 已知条件:P(boy) =0.6,P(girl) =0.4,P(paint | boy) =1,P(paint | girl) =0.5
5. 我们要求 P(boy | paint) or P(girl | paint)
这是个非常简单的初中数学题,假设我们并不知道贝叶斯公式。设学校总人数为M,那么男生穿长裤的总人数为
这里条件概率为何相乘,属于概率论中的相关知识,这里不再做理论解释,分子分母都有M,可以化简,其次男生穿长裤+女生穿长裤,即为穿长裤的总人数。所以该式即得
更一般的,我们把girl用A代替,paint = B代替,即
则就有了贝叶斯公式。
上述简单的概率论问题得到了求解,以后遇到类似的问题,我们均可以直接使用贝叶斯公式,而不必再慢慢推导其过程。你会想了,这不就是一个简单的求解概率论问题的过程嘛,只是省略了中间过程,让我们可以一步得出结论,何必把贝叶斯公式夸的那么高上大呢?没错,在这个问题中,我们只是利用概率论的知识进行求解,甚至不需要贝叶斯公式。那假设等式的左边无法用初等概率论进行求解,那么我们该怎么办呢?
回过头来,我们再来看看经典黑白球逆概问题,同样地,我们对问题进行建模。
1. 我们已知摸出的
n
个球中的黑白比例 即我们记随机变量x =黑球个数/n
2. 求袋子中黑白球的真实比例值
3. 求解
P(θ|x)
就这个问题,我们如何求解?已知的条件太少了,我们只知道每次实验取出
n
个球中黑球的概率,难不成我们直接把黑球占总数的概率当作我们的
公式左边称为后验概率,在这里公式的含义就是说,我们想要知道在给定观察结果x的情况下,后验概率最大。这个参数 θ 可以猜测为0.5,0.1,甚至是1,whaterver,只要在你的各种假设中,后验概率最大即可,表象背后的模型最符合真实情况即可!所谓透过现象看本质,深刻的揭示了贝叶斯哲学,透过现象看本质,谁是本质,参数 θ 是本质,所以在贝叶斯公式的右端,我们需要根据本质进行建模,来观察现象出现的概率,这种抽象在统计学中是有一一对应的模型的,即 P(x|θ) ,人们对它做了很多系统的研究的,因为它本质上是抽象的,所以抽象的东西往往能总结出一套数学模型,如黑白球占比问题,概率分布是满足二项式分布的,即在给定实验次数 n 和观察的黑球个数m,我们有关于
n,m 在给定的观察数据中是已知的,只有 θ 未知,很显然求解 P(θ|x) 的极大值,即求解 P(θ)P(x|θ) 的极大, P(x) 对与每个参数 θ 是常量,所以完全可以省略。即贝叶斯公式得到进一步简化
所以说,左式正比于右式。因此在求解过程中,我们完全可以通过求解右式来等效替代求解左式,由于我们已经知道了黑白球的本质其实二项式分布函数,所以求解该概率分布在观察数据给定条件下的极值即可,求极值问题就转为数学中的求导问题。那么我们就很容易求出我们的 θ 了,但别忘了,我们还有一个概率 P(θ) ,它是什么样的实际含义呢,这又得提到贝叶斯的思考哲学,即我们对模型的假设,还受模型本身先验概率的影响,如在抛硬币过程中,某厂制造硬币的种类抛出正面的概率 θ 是已知的,当然,考虑硬币的质地和制作工艺等多种因素,可能使得 P(θ=0.5) 本身的概率在某个点附近活动,如在0.9附近范围内摇摆。不过,某厂非常的神奇,制造的硬币抛出正面的概率为1,那么作为参数 θ=1 的情况, P(θ=1) 本身出现也有一定的概率,可能为整体样本的0.1,由此 P(θ) 整体反映了该模型在所有可能的求解问题中所占的比重,不仅仅只有 P(x|θ) 决定。换句话说,我们考虑黑白球问题时,对各种参数 θ 的分布情况也需要考虑进去,只不过我们在解决一些特定问题时,参数 θ 多数满足均匀分布,那么贝叶斯公式就得到了最终版。
这种情况下求解条件概率,或者说求解参数估计问题时,我们通过贝叶斯公式转换到求解抽象模型的参数估计问题,所谓透过现象看本质,贝叶斯他做到了。
实际应用
实际应用中博文数学之美番外篇:平凡而又神奇的贝叶斯方法列举了很多例子,如拼写纠正,中文分词,统计机器翻译,EM算法与基于模型的聚类等等,这些例子都能帮助我们进一步理解贝叶斯定理,加深印象。由于本文的目的在于在理解贝叶斯的基础上,去学习朴素贝叶斯,因此,我们举一个中文分词的技术来阐述贝叶斯哲学和朴素贝叶斯所做的假设,从而有一个良好的过渡。
中文分词
分词问题的描述为:给定一个句子(字串),如:
南京市长江大桥
如何对这个句子进行分词(词串)才是最靠谱的。例如:
1. 南京市/长江大桥
2. 南京/市长/江大桥
这两个分词,到底哪个更靠谱呢?
我们用贝叶斯公式来形式化地描述这个问题,令 X 为字串(句子),Y 为词串(一种特定的分词假设)。我们就是需要寻找使得 P(Y|X) 最大的 Y ,使用一次贝叶斯可得:
用自然语言来说就是 这种分词方式(词串)的可能性 乘以 这个词串生成我们的句子的可能性。我们进一步容易看到:可以近似地将 P(X|Y) 看作是恒等于 1 的,因为任意假想的一种分词方式之下生成我们的句子总是精准地生成的(只需把分词之间的分界符号扔掉即可)。于是,我们就变成了去最大化 P(Y) ,也就是寻找一种分词使得这个词串(句子)的概率最大化。而如何计算一个词串:
的可能性呢?我们知道,根据联合概率的公式展开: P(W1,W2,W3,W4...)=P(W1)∗P(W2|W1)∗P(W3|W2,W1)∗P(W4|W1,W2,W3)∗... 于是我们可以通过一系列的条件概率(右式)的乘积来求整个联合概率。然而不幸的是随着条件数目的增加 P(Wn|Wn−1,Wn−2,..,W1) 的条件有 n-1 个,数据稀疏问题也会越来越严重,即便语料库再大也无法统计出一个靠谱的 P(Wn|Wn−1,Wn−2,..,W1) 来。为了缓解这个问题,计算机科学家们一如既往地使用了“天真”假设: 我们假设句子中一个词的出现概率只依赖于它前面的有限的 k 个词(k 一般不超过 3,如果只依赖于前面的一个词,就是2元语言模型(2-gram),同理有 3-gram 、 4-gram 等),这个就是所谓的“有限地平线”假设。虽然这个假设很傻很天真,但结果却表明它的结果往往是很好很强大的,后面要提到的朴素贝叶斯方法使用的假设跟这个精神上是完全一致的,我们会解释为什么像这样一个天真的假设能够得到强大的结果。目前我们只要知道,有了这个假设,刚才那个乘积就可以改写成: P(W1)∗P(W2|W1)∗P(W3|W2)∗P(W4|W3)... (假设每个词只依赖于它前面的一个词)。而统计 P(W2|W1) 就不再受到数据稀疏问题的困扰了。对于我们上面提到的例子“南京市长江大桥”,如果按照自左到右的贪婪方法分词的话,结果就成了“南京市长/江大桥”。但如果按照贝叶斯分词的话(假设使用 3-gram),由于“南京市长”和“江大桥”在语料库中一起出现的频率为 0 ,这个整句的概率便会被判定为 0 。 从而使得“南京市/长江大桥”这一分词方式胜出。
上文通过贝叶斯定理映射到了如何求解
P(Y)
的概率问题上,而
P(Y)
是由一系列的单个单词组成,因此要求得它的概率就必须写出当前单词与前n-1个单词的条件概率,这在计算上是没法做到的,因为每当要计算第n个单词时,我们就要进行大量的统计,我们都知道“你好,妈妈,我想你了”的概率一定小于“你好,妈妈”的概率小于“你好”的概率,对于词串也是,词串一长,数据变得非常稀疏,即便我们有本事统计成千上问的词库,这些概率也都趋近于0,显然就失去了统计意义。因此,在对中文分词进行统计时,我们假设了当前单词只跟前一个单词,或前k个单词有关。ok,这还不是朴素贝叶斯的假设,但基本上接近了,朴素贝叶斯简化的更加彻底,即当前单词跟前一个单词完美没有任何关系,即单词与单词之间相互独立,是不是更加简单了?因为此时
P(Y=W1,W2,...,Wn)
的求解公式就变为了
朴素贝叶斯方法的条件独立假设看上去很傻很天真,为什么结果却很好很强大呢?就拿一个句子来说,我们怎么能鲁莽地声称其中任意一个单词出现的概率只受到它前面的 3 个或 4 个单词的影响呢?别说 3 个,有时候一个单词的概率受到上一句话的影响都是绝对可能的。那么为什么这个假设在实际中的表现却不比决策树差呢?有人对此提出了一个理论解释,并且建立了什么时候朴素贝叶斯的效果能够等价于非朴素贝叶斯的充要条件,这个解释的核心就是:有些独立假设在各个分类之间的分布都是均匀的所以对于似然的相对大小不产生影响;即便不是如此,也有很大的可能性各个独立假设所产生的消极影响或积极影响互相抵消,最终导致结果受到的影响不大。具体的数学公式请参考这篇 paper 。
好了,回到《统计学习方法》,朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入
x
,利用贝叶斯定理求出后验概率最大的输出
在博文算法杂货铺——分类算法之朴素贝叶斯分类(Naive Bayesian classification)中,在解释朴素贝叶斯时,用到了这样一个例子。原文如下
通俗来说,就好比这么个道理,你在街上看到一个黑人,我问你你猜这哥们哪里来的,你十有八九猜非洲。为什么呢?因为黑人中非洲人的比率最高,当然人家也可能是美洲人或亚洲人,但在没有其它可用信息下,我们会选择条件概率最大的类别,这就是朴素贝叶斯的思想基础。
这个例子对朴素贝叶斯的解释是错误的,黑人种非洲人的比例最高,说的不就是贝叶斯等式的左边嘛,用左边解释左边显然是不可取的。且朴素贝叶斯是在贝叶斯的思想哲学下,作基于各特征向量中每一个随机变量的独立假设,街上看到黑人,我们需要假设一种模型或者说某个参数,使得在接上看到黑人的概率最大,那么依据贝叶斯的原理,我们可以反过来求解 在非洲,黑人的概率和非洲人在我们街上出现的概率,即我们的先验概率。P(黑|非) * P(非),当然我们可以猜测是美洲人,但P(美)P(黑|美) 的联合概率就不一定比非洲人出现在我们街上的概率大了。因为虽然美洲人可能在亚洲的可能性大,但在美洲人中黑人的占比或许是非常小的。所以整体联合概率就小了,P(非|黑) = P(黑|非) P(非) /P(黑) ,这是经典的贝叶斯公式。
朴素贝叶斯的学习与分类
接下来的内容部分来自于书本《统计学习方法》以及博文朴素贝叶斯法 码农场。
在讲解贝叶斯公式时,举到了很多实际的应用,如黑白球逆概求救问题,中文分词等,它们借助贝叶斯公式把原本无法直接求解的问题转换到对应的模型上进行求解,这些求解问题可以归结为对模型进行数学建模,通过极大似然估计方法来进行求解。如常见的EM算法,隐马尔可夫模型,它们只是借助贝叶斯来寻求等价问题从而进行参数估计,得到的模型再来预测输入向量 x 。而在书本中介绍的朴素贝叶斯,本身是基于概率论来直接对离散数据进行统计,它并没有求解任何未知参数问题,而是基于大数据的统计,背后的模型便是朴素贝叶斯,用到的统计手段也是最简单的极大似然估计方法。
例子
由下表的训练数据学习一个朴素贝叶斯分类器并确定
x=(2,S)T 的类标 y 。表中X(1),X(1) 为特征,取值的集合分别为 A1={1,2,3},A2={S,M,L},Y 为类标记。 Y∈C={1,−1} .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 X(1) 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 X(1) S M M S S S M M L L L M M L L Y -1 -1 1 1 -1 -1 -1 1 1 1 1 1 1 1 -1 问题有了,我们怎么进行求解呢,那我们必须知道要求什么!题目是说给定 x=(2,S)T ,我们要求对应的类标 y ,由此我们得到条件概率为
P(Y=ck|X=x) ,由贝叶斯定理我们知道,条件概率是可以相互转换的,于是有
P(Y=ck|X=x)=P(X=x|Y=ck)P(Y=ck)P(X=x)
对后验概率的求解转换到了求解先验概率,哈哈哈,统计呗,咱们一步步来。
1. 求解概率 P(Y=ck) ,这是分类的先验概率,由极大似然估计得
P(Y=ck)=∑Ni=1I(yi=ck)N,k=1,2,...,K
其中, I 为指示函数,即I 中条件成立则值为1,反之值为0,N为数据样本的总数。于是得P(Y=1)=915,P(Y=−1)=615
2.求解概率 P(X=x|Y=ck) ,由于X属于 n 维的特征向量 ,所以上式可以写成
P(X=x|Y=ck)=P(X(1)=x(1),X(2)=x(2),...,X(n)=x(n)|Y=ck),k=1,2,...,K
x(n) 表示某一样本数据第n维上的随机变量。这里朴素贝叶斯假设派上了用场,数据样本X的每个维度的变量是相互独立的,因此上述公式就等于
P(X=x|Y=ck)=∏j=1nP(X(j)=x(j)|Y=ck)
这不就是说,我们可以单独的去统计在 ck 分类的条件下, X(j) 的概率嘛,再进行累乘就可以了,于是有P(X(1)=1|Y=1)=29,P(X(1)=2|Y=1)=39,P(X(1)=3|Y=1)=49
P(X(2)=S|Y=1)=19,P(X(2)=M|Y=1)=49,P(X(2)=L|Y=1)=49
P(X(1)=1|Y=−1)=36,P(X(1)=2|Y=−1)=26,P(X(1)=3|Y=−1)=16
P(X(2)=S|Y=−1)=36,P(X(2)=M|Y=−1)=26,P(X(2)=L|Y=−1)=16
3.求解 P(X=x) ,等下,有求解它的必要嘛,我们只是想要找到在特定输入X下最有可能的分类结果 ck ,而不管是哪种分类, P(X=x) 的概率始终是一样的,因此我们完全没有必要对它进行求解。所以也就有了书中(4.7)的公式
y=argmaxckP(Y=ck)∏j=1nP(X(j)=x(j)|Y=ck)
于是,对于给定的 x=(2,S)T 计算:P(Y=1)P(X(1)=2|Y=1)P(X(2)=S|Y=1)=915⋅39⋅19=145
P(Y=−1)P(X(1)=2|Y=−1)P(X(2)=S|Y=−1)=615⋅26⋅369=115
所以根据计算结果,我们预测 x=(2,S)T ,属于类标-1。
Laplace校准
试想一下,如果某个维度并没有对应的数据点会出现什么情况?那么在该维度上 P(X(n)=x(n)|Y=ck) 的概率就为0,这会使得当 Y=ck 进行概率计算时,直接输出为0,即分类效果骤减,输入任何向量X,都不会预测到 ck 这个类别。于是在采用极大似然估计方法时,我们采用拉普拉斯平滑手段来解决上述问题。即在求解条件概率时,我们加入了系数 λ
Pλ(X(j)=ajl|Y=ck)=∑Ni=1I(x(j)i=ajl,yi=ck)+λ∑Ni=1I(yi=ck)+Sjλ
Pλ(Y=ck)=∑Ni=1I(yi=ck)+λN+Kλ朴素贝叶斯分类流程
以下内容摘自博文算法杂货铺——分类算法之朴素贝叶斯分类(Naive Bayesian classification)。
朴素贝叶斯分类的流程可以由下图表示(暂时不考虑验证):
可以看到,整个朴素贝叶斯分类分为三个阶段:
第一阶段——准备工作阶段,这个阶段的任务是为朴素贝叶斯分类做必要的准备,主要工作是根据具体情况确定特征属性,并对每个特征属性进行适当划分,然后由人工对一部分待分类项进行分类,形成训练样本集合。这一阶段的输入是所有待分类数据,输出是特征属性和训练样本。这一阶段是整个朴素贝叶斯分类中唯一需要人工完成的阶段,其质量对整个过程将有重要影响,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定。
第二阶段——分类器训练阶段,这个阶段的任务就是生成分类器,主要工作是计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率估计,并将结果记录。其输入是特征属性和训练样本,输出是分类器。这一阶段是机械性阶段,根据前面讨论的公式可以由程序自动计算完成。
第三阶段——应用阶段。这个阶段的任务是使用分类器对待分类项进行分类,其输入是分类器和待分类项,输出是待分类项与类别的映射关系。这一阶段也是机械性阶段,由程序完成。
Code Time
调用实例:
from matplotlib import pyplot as plt import numpy as np from math import log,exp class LaplaceEstimate(object): """ 拉普拉斯平滑处理的贝叶斯估计 """ def __init__(self): self.d ={} # [词-词频]的map self.total = 0.0 self.none =1 def exists(self,key): return key in self.d def getsum(self): return self.total def get(self,key): if not self.exists(key): return False,self.none return True,self.d[key] # 计算P(x | y) def getprob(self,key): return float(self.get(key)[1]) /self.total def samples(self): """ 获取全部样本 :return: """ return self.d.keys() def add(self,key,value): self.total +=value # map {key:value} ={'好':2} if not self.exists(key): self.d[key] =1 self.total +=1 self.d[key] +=value class Bayes(object): def __init__(self): self.d ={} self.total = 0 # 参数计算 def train(self,data): for d in data: c =d[1] # 对每个分类进行统计 建立map d[pos] 和 d[neg] if c not in self.d: self.d[c] = LaplaceEstimate() # 生成拉普拉斯平滑 # 对特征向量中每个随机变量进行统计 for word in d[0]: self.d[c].add(word,1) self.total = sum(map(lambda x: self.d[x].getsum(),self.d.keys())) def classify(self,x): tmp ={} # 循环每一个分类标签 for c in self.d: tmp[c] = log(self.d[c].getsum()) - log(self.total) for word in x: tmp[c] += log(self.d[c].getprob(word)) ret,prob = 0,0 for c in self.d: now =0 try: for otherc in self.d: now += exp(tmp[otherc] - tmp[c]) now = 1 / now except OverflowError: now =0 if now > prob: ret,prob = c,now return (ret,prob) class Sentiment(object): def __init__(self): self.classifier = Bayes() def segment(self,sent): words = sent.split(' ') return words def train(self,neg_docs,pos_docs): data = [] # 合并特征向量和分类标签 for sent in neg_docs: data.append([self.segment(sent),u'neg']) for sent in pos_docs: data.append([self.segment(sent),u'pos']) self.classifier.train(data) def classify(self,sent): return self.classifier.classify(self.segment(sent)) s = Sentiment() s.train([u'糟糕', u'好 差劲'], [u'优秀', u'很 好']) # 空格分词 print (s.classify(u"好 优秀")) max_dimensionality =10 ax = plt.axes(xlim =(0,max_dimensionality),ylim=(0, 1 / (0.01 ** max_dimensionality))) x = np.linspace(0,max_dimensionality,1000) y = 1 / (0.01 ** x) plt.plot(x,y,lw =2) plt.show()
输出:
(u'pos', 0.6666666666666665)
说明“好优秀”这句话具有正能量的概率是66%,虽然“好”这个词语也存在于负极性的语句中,但是分类器还是准确地区分了它。
上面的贝叶斯分类器使用了拉布拉斯平滑处理策略,在进行条件概率的时候,不是连乘,而是取对数相加,最后逐差取指数,这个过程会发生归一化,得出一个概率出来。
参考文献
- 数学之美番外篇:平凡而又神奇的贝叶斯方法
- 算法杂货铺——分类算法之朴素贝叶斯分类(Naive Bayesian classification)
- 李航. 统计学习方法[M]. 北京:清华大学出版社,2012
- 朴素贝叶斯法 码农场。