贝叶斯分类器(3)朴素贝叶斯分类器

根据贝叶斯分类器(1)贝叶斯决策论概述、贝叶斯和频率、概率和似然,我们对贝叶斯分类器所要解决的问题、问题的求解方法做了概述,将贝叶斯分类问题转化成了求解P(x|c)的问题,在上一篇贝叶斯分类器(2)极大似然估计、MLE与MAP
中,我们分析了第一个求解方法:极大似然估计。在本篇中,我们来介绍一个更加简单的P(x|c)求解方法,并在此基础上讲讲常用的一个贝叶斯分类器的实现:朴素贝叶斯分类器(Naive Bayes classifier)。

1 朴素贝叶斯分类原理

1.1 分类问题回顾

我们的目标是通过对样本的学习来得到一个分类器,以此来对未知数据进行分类,即求后验概率P(c|x)。在贝叶斯分类器(1)贝叶斯决策论概述、贝叶斯和频率、概率和似然中,我们描述了贝叶斯分类器是以生成式模型的思路来处理这个问题的,如下面的公式所示,贝叶斯分类器通过求得联合概率P(x,c)来计算P(c|x),并将联合概率P(x,c)转化成了计算类先验概率P(c)、类条件概率P(x|c)、证据因子P(x)

h^*(x)=\argmax_{c\in Y} P(c|x)=\argmax_{c\in Y} \frac{P(x,c)}{P(x)}=\argmax_{c\in Y} \frac{P(c)*P(x|c)}{P(x)}

其中的难点是类条件概率P(x|c)的计算,因为样本x本身就是其所有属性的联合概率,各种属性随意组合,变幻莫测,要计算其中某一种组合出现的概率真的是太难了,而朴素贝叶斯的出现就是为了解决这个问题的。

要想计算联合概率P(a,b),我们肯定是希望事件a与事件b是相互独立的,可以简单粗暴的P(a,b)=P(a)P(b),多想对着流星许下心愿:让世界上复杂的联合概率都变成简单的连乘!

1.2 朴素贝叶斯

朴素贝叶斯实现了我们的梦想!朴素贝叶斯中的朴素就是对多属性的联合分布做了一个大胆的假设,即xn个维度之间相互独立:

P([x_1,x_2,...,x_n]|c)=P(x_1|c)P(x_2|c)...P(x_1|c)

朴素贝叶斯通过这一假设大大简化了P(x|c)的计算,当然,使用这个假设是有代价的,一般情况下,大量样本的特征之间独立这个条件是弱成立的,毕竟哲学上说联系是普遍的,所以我们使用朴素贝叶斯会降低一些准确性;如果实际问题中的事件的各个属性非常不独立的话,甚至是无法使用朴素贝叶斯的。总的来说,朴素贝叶斯大大简化了计算,同时牺牲了一些结果的准确性,具体要不要使用、怎么使用就看我们在实际问题中的权衡了。

在朴素贝叶斯的思想下再看回分类问题,事件xm个属性,可将分类问题按下式转化:

只需要计算出上式不同类别c下的值,令值最大的类别c_i即为分类结果。

其中,根据大数定律,P(c)=\frac{N_c}{N}P(x_i|c)是类别c下的后验概率,其计算要取决于先验x,这里需要分为X是离散或连续两种情况:

1.2.1 特征/属性是离散型随机变量

  • 1)先验服从多项式分布:假设x的特征取值服从多项式分布,那么同样根据大数定律,可通过频率来计算P(x_i|c)

P(x_i=x_{i*}|c)=\frac{N_{ci*}}{N_c}

N_c为样本中类别为c的频数,N_{ci*}为类别为c的样本中,第i个属性中i*出现的频数。
不过有些出现的概率比较低的属性,在我们的样本中不一定会出现,即频数为0,如果不作处理的话会导致其P(x_i|c)为0,会导致包含这个属性的样本永远都不会被分类到类别c,而现实不一定是这样,因此我们需要对没出现的情况做平滑处理,比如常见的拉普拉斯平滑,给分子i*的频数加上一个定值\lambda,而分母加上a*\lambda,表示为第i个属性中的每一种取值的频数都加定值\lambda

P(x_i=x_{i*}|c)=\frac{N_{ci*}+\lambda}{N_c+a*\lambda}

举例:垃圾邮件判断
朴素贝叶斯分类在垃圾邮件的判断上有不错的实践效果,这是一个二分类问题,c\in[垃圾邮件,正常邮件],假设c_0为垃圾邮件,c_1为正常邮件,统计出:

P(c_0)=0.2,P(c_1)=0.8

现在收到一封邮件包含一些关键词:【中奖,笔记本电脑,特朗普,大选,...】,根据大量的数据可以统计出这些词出现的频数,除以类别中所有词的总频数得到其出现的后验概率,在垃圾邮件中:

P(中奖|c_0)=0.7,P(笔记本电脑|c_0)=0.5,P(特朗普|c_0)=0.3,P(大选|c_0)=0.4

在正常邮件中:

P(中奖|c_1)=0.1,P(笔记本电脑|c_1)=0.2,P(特朗普|c_1)=0.1,P(大选|c_1)=0.2

可以计算得到:

P(c_0)\cdot\prod_{} P(x_{i}|c_0)=0.2*0.7*0.5*0.3*0.4=0.0084

P(c_1)\cdot\prod_{} P(x_{i}|c_1)=0.8*0.1*0.2*0.1*0.2=0.00032

c=c_0时的值是c=c_1时值的26倍,所以判断此邮件是垃圾邮件。

我们判断西瓜好坏的问题也可以转化成离散型随机变量的分类问题,过程与上面类似。

  • 2)先验服从伯努利分布:x的属性是离散型随机变量的分类问题中,如果一个属性只关注其出现或者不出现,而不关注其在一个样本内出现的次数,也就是其取值只有0和1,那么我们可以假设这个属性是服从伯努利分布的(注意:不要求属性为伯努利分布,只要业务需要,我们可以把它变成伯努利分布,比如对于销量,我们让小于100的都是0,大于100的为1)。其后验概率的计算为:

P(x_{i*} \mid c) = P(x_{i*} \mid c) *x_{i*} + (1 - P(x_{i*}\mid c)) *(1 - x_{i*})

比如垃圾邮件的例子,在多项式朴素贝叶斯中:

P(x_{i*}=中奖|c=垃圾邮件)=\frac{垃圾邮件中“中奖”词频+\lambda}{垃圾邮件中总词频+词数*\lambda}

如果我们只关心“中奖”出现与否,不管词频,则在伯努利朴素贝叶斯中:

P(x_{i*}=中奖|c=垃圾邮件)=\frac{垃圾邮件中含有“中奖”的邮件数 +α }{垃圾邮件数 + α*邮件类别数}

1.2.2 特征/属性是连续型随机变量

  • 连续变量离散化,使用多项式分布或伯努利分布:x的属性是连续型随机变量时,如果我们对取值的业务理解较好,一些情况下可以选择将连续变量离散化,比如在一个商品的分类中,我们根据业务理解把低于100块的映射到“便宜”,100到200块的映射到“一般”,高于100块的映射到“好贵”,这样就可以转化为离散变量的问题,这是比较简单的处理方式,不过对业务理解的要求比较高,而且要求样本的量不能太少,要保证每个区间有一定的样本量。

  • 假设x的连续型属性服从某种分布,比如正态分布: 假设P(x_i|c)服从正态分布,其中参数\mu通过类别为c的所有样本中属性x_i的各种取值的平均得到,参数\sigma同理,通过样本的标准差得到,以此概率密度函数来计算P(x_i=x_{i*}|c)

举例:性别判断
下面是一组人类身体特征的统计资料。

有人身高6英尺、体重130磅,脚掌8英寸,判断此人性别:

各属性为连续变量,假设男性和女性的身高、体重、脚掌都是正态分布,通过样本计算出均值和方差。男性的身高是均值5.855、方差0.035的正态分布。所以,例如男性的身高为6英尺的概率的相对值等于1.5789(密度函数的值,并不是概率,只用来反映各个值的相对可能性)。

分布确定后,就可以计算性别的分类了:

P(身高=6|男) * P(体重=130|男) * P(脚掌=8|男) * P(男) = 6.1984 * 10^{-9}

P(身高=6|女) * P(体重=130|女) * P(脚掌=8|女) * P(女) = 5.3778 *10^{-4}

女性的概率比男性要高出将近10000倍,所以判断该人为女性。

1.3 朴素贝叶斯分类的平滑方法

在前文1.2.1小节中我们已经提过平滑处理,主要针对于那些在样本中没有出现过的词,它们的概率是0,导致在分类中完全没有存在感,所以要对这些进行平滑处理。

平滑处理的方法也有很多种,包括我们上面说过的拉普拉斯平滑,除此之外还有古德图灵平滑,线性插值法,回退法(K-Z回退)等,不过这些方法在自然语言处理中比较常用,我们暂时先不多介绍了,还是聚焦在朴素贝叶斯上,下面我们看看朴素贝叶斯在sklearn中的实现。

2 朴素贝叶斯的sklearn实现

sklearn中有3种常用的不同类型的朴素贝叶斯:

1)高斯分布型朴素贝叶斯

sklearn.naive_bayes.GaussianNB(*, priors=None, var_smoothing=1e-09)

Parameters
priors:array-like of shape (n_classes,)
类别的先验概率,如果指定,则不再根据数据计算调整
var_smoothing:float, default=1e-9
Portion of the largest variance of all features that is added to variances for calculation stability.(不是很明白)

Gaussian NB的方法
>> import numpy as np
>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
>> Y = np.array([1, 1, 1, 2, 2, 2])
>> from sklearn.naive_bayes import GaussianNB
>> clf = GaussianNB()
>> clf.fit(X, Y)
GaussianNB()
>> print(clf.predict([[-0.8, -1]]))
[1]
>> clf_pf = GaussianNB()
>> clf_pf.partial_fit(X, Y, np.unique(Y))  # 增量训练
GaussianNB()
>> print(clf_pf.predict([[-0.8, -1]]))
[1]
>> clf.predict_proba(np.array([[2,2]]))   # 输出概率
array([[2.31952419e-16, 1.00000000e+00]])
>> clf.predict_log_proba(np.array([[2,2]]))    # 输出对数概率
array([[-35.99999941,   0.        ]])

2)多项式分布型朴素贝叶斯

sklearn.naive_bayes.MultinomialNB(*, alpha=1.0, fit_prior=True, class_prior=None)

Parameters
alpha:float, default=1.0
Additive (Laplace/Lidstone) smoothing parameter (0 for no smoothing).

fit_prior:bool, default=True
Whether to learn class prior probabilities or not. If false, a uniform prior will be used.

class_prior:array-like of shape (n_classes,), default=None
Prior probabilities of the classes. If specified the priors are not adjusted according to the data.

其常用函数与高斯型一样。

>> import numpy as np
>> rng = np.random.RandomState(1)
>> X = rng.randint(5, size=(6, 100))
>> y = np.array([1, 2, 3, 4, 5, 6])
>> from sklearn.naive_bayes import MultinomialNB
>> clf = MultinomialNB()
>> clf.fit(X, y)
MultinomialNB()
>> print(clf.predict(X[2:3]))
[3]

3)伯努利分布型朴素贝叶斯

sklearn.naive_bayes.BernoulliNB(*, alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)

Parameters
binarize:float or None, default=0.0
Threshold for binarizing (mapping to booleans) of sample features. If None, input is presumed to already consist of binary vectors.(用于设置二值化的阈值)

官方例子与多项式型的基本一样,而且也没有设置binarize,相当于默认使用binarize=0.0,根据源码 sklearn/preprocessing/_data.py
中的binarize(X, *, threshold=0.0, copy=True)函数可以发现,大于binarize的都赋值为1,其他为0。

>> import numpy as np
>> rng = np.random.RandomState(1)
>> X = rng.randint(5, size=(6, 100))
>> Y = np.array([1, 2, 3, 4, 4, 5])
>> from sklearn.naive_bayes import BernoulliNB
>> clf = BernoulliNB()
>> clf.fit(X, Y)   # X中各个特征的取值为[0,1,2,3,4],二值化后大于0的都为1
BernoulliNB()
>> print(clf.predict(X[2:3]))
[3]

3 朴素贝叶斯总结

优点

  • 朴素贝叶斯算法假设了数据集属性之间是相互独立的,因此算法的逻辑性十分简单,并且算法较为稳定,当数据呈现不同的特点时,朴素贝叶斯的分类性能不会有太大的差异;
  • 当数据集属性之间的关系相对比较独立时,朴素贝叶斯分类算法会有较好的效果;
  • 数据量要求不大,适合增量式训练,能直接处理多分类;
  • 算法简单直观,具有很好的可解释性,可以直接输出概率。

缺点

  • 属性独立性的条件也是朴素贝叶斯的不足之处,数据集属性的独立性在很多情况下很难满足;
  • 需要知道先验概率,且先验概率很多时候也是取决于假设,故对假设的合理性较为依赖。

可见,朴素贝叶斯的缺点很大程度来来源于其假设太强,对于其假设符合程度较低的问题会损失较多的准确性,因此,如果我们能把假设弱化一下,是不是就能提高朴素贝叶斯的性能呢?在接下来的篇章中我们来继续探索。



主要参考资料

《机器学习》周志华
《统计学习方法》 李航
scikit-learn Naive Bayes文档

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345