机器学习算法总结之朴素贝叶斯法
写在前面
贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。而朴素朴素贝叶斯分类是贝叶斯分类中最简单,也是常见的一种分类方法。它是基于贝叶斯定理和特征条件独立假设分类方法。对于给定训练集,首先基于特征条件独立性的假设,学习输入/输出联合概率(计算出先验概率和条件概率,然后求出联合概率)。然后基于此模型,给定输入x,利用贝叶斯概率定理求出最大的后验概率作为输出y。朴素贝叶斯法实现简单,学习和预测效率都很高,是一种常用的分类方法。
1. 朴素贝叶斯相关的统计学知识
贝叶斯学派的思想可以概括为先验概率+数据=后验概率。也就是说我们在实际问题中需要得到的后验概率,可以通过先验概率和数据一起综合得到。数据大家好理解,被频率学派攻击的是先验概率,一般来说先验概率就是我们对于数据所在领域的历史经验,但是这个经验常常难以量化或者模型化,于是贝叶斯学派大胆的假设先验分布的模型,比如正态分布,beta分布等。这个假设一般没有特定的依据,因此一直被频率学派认为很荒谬。虽然难以从严密的数学逻辑里推出贝叶斯学派的逻辑,但是在很多实际应用中,贝叶斯理论很好用,比如垃圾邮件分类,文本分类。
几个基本常用的贝叶斯公式(更具体可参见Bayes' theorem——Wiki)
- 条件独立公式
- 条件概率公式
- 全概率公式
其中
- 贝叶斯公式
2. 朴素贝叶斯模型
假设我们有训练数据集如下:
即有m个样本,每个样本有n个特征,特征输出有K个类型,定义为C1、C2、... CK。
于是,从样本中可以得出朴素贝叶斯的先验分布:
接着学习到条件概率分布:
然后根据贝叶斯公式就可以得到XY的联合分布:
朴素贝叶斯模型假设X的n个维度之间相互独立,则有:
回到我们需要解决的问题:判断给定测试集的一个新样本属于哪个类型?
当然作为朴素贝叶斯法进行分类,它是经过学习给定x的模型特征计算后延概率分布,将后验概率最大的类作为X的输出类。

3.朴素贝叶斯的参数估计
在朴素贝叶斯中,学习意味着估计 和
对于先验概率,可以简单地用极大似然估计得出,即样本类别Ck出现的次数Mk除以样本总数M。
对于条件概率分布,取决于先验条件:
(1)如果是离散分布:
- 若采用极大似然估计,则:
其中mk为样本类别Ck出现的次数,而分子为样本Ck中,第j维特征出现的次数。
- 但是在某些时候,用极大似然估计会出现所要估计的概率值为0的情况,这时可考虑在随机变量各个取值的频数上赋予一个大于0的整数lambda,称为贝叶斯估计。常取lambda = 1,这时称为拉普拉斯平滑(Laplace smoothing)
(2)如果数据是非常稀疏的离散值,即各个特征出现概率很低,这时我们可以假设Xj符合伯努利分布,即特征Xj出现记为1,不出现记为0。即只要Xj出现即可,我们不关注Xj的次数。这样得到P(Xj=X(test)j|Y=Ck) 是在样本类别Ck中,X(test)j出现的频率。此时有:
(3)如果数据是连续值,我们通常取Xj的先验概率为正态分布,即在样本类别Ck中,Xj的值符合正态分布。这样P(Xj=X(test)j|Y=Ck)的概率分布是:
4.朴素贝叶斯算法

看完可能还比较模糊,附上一个例子:


5.朴素贝叶斯算法小结
朴素贝叶斯算法的主要原理基本已经做了总结,这里对朴素贝叶斯的优缺点做一个总结。
朴素贝叶斯的主要优点有:
1)朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。
2)对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。
3)对缺失数据不太敏感,算法也比较简单,常用于文本分类。
朴素贝叶斯的主要缺点有:
1) 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
2)需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。
3)由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。
4)对输入数据的表达形式很敏感。
6. 朴素贝叶斯实战
下面我们利用朴素贝叶斯模型来实现一个简单的文本分类任务。
首先我们定义一个NB分类器,当然也可以选择直接用sklearn中已经帮我们实现的
import math
from collections import defaultdict
class NBayes(object):
def __init__(self, trainSet):
self.data = trainSet
self.tags = defaultdict(int)
self.tagwords = defaultdict(int)
self.total = 0
def _tokenizer(self, sent):
return list(sent)
def train(self):
for tag, doc in self.data:
words = self._tokenizer(doc)
for word in words:
self.tags[tag] += 1
self.tagwords[(tag, word)] += 1
self.total += 1
def predict(self, inp):
words = self._tokenizer(inp)
tmp = {}
for tag in self.tags.keys():
tmp[tag] = math.log(self.tags[tag]) - math.log(self.total)
for word in words:
tmp[tag] += math.log(self.tagwords.get((tag, word), 1.0)) - math.log(self.tags[tag])
ret, score = 0, 0.0
for t in self.tags.keys():
cnt = 0.0
for tt in self.tags.keys():
cnt += math.exp(tmp[tt] - tmp[t])
cnt = 1.0 / cnt
if cnt > score:
ret, score = t, cnt
return ret
接着我们读入训练数据,这里我选的是2018BDCI汽车评论比赛的数据集,作了个简单的baseline
import pandas as pd
mydata = pd.DataFrame(pd.read_csv('F:/BDCI/train/train.csv'))
mydata = mydata[['content','sentiment_value']]
train = []
for i in range(len(mydata)):
train.append((mydata.iloc[i]['sentiment_value'], mydata.iloc[i]['content']))
train
训练数据是长这样的,标签+文本内容
[(0, '因为森林人即将换代,这套系统没必要装在一款即将换代的车型上,因为肯定会影响价格。'),
(-1, '四驱价格貌似挺高的,高的可以看齐XC60了,看实车前脸有点违和感。不过大众的车应该不会差。'),
(1, '斯柯达要说质量,似乎比大众要好一点,价格也低一些,用料完全一样。我听说过野帝,但没听说过你说这车。 '),
(-1, '这玩意都是给有钱任性又不懂车的土豪用的,这价格换一次我妹夫EP020可以换三锅了'),
(-1, '17价格忒高,估计也就是14-15左右。 '),
(1,
'我开始就是荣放2.5 \xa0森林人2.5二选一 \xa0 \xa0荣放主要是底盘质感不行 \xa0 太硬 \xa0其次是不能打开的天窗 \xa0和公主坟 \xa0 不过价格确实便宜 \xa0 \xa0少了5W块'),
(-1, '唉,这货的价格死硬死硬的,低配版优惠1万据说已经罕有了。 '),
(0, '价格的话只能说一般般吧,太仓前段时间定的比你便宜! '),
(-1, '听过,价格太贵,但一直念念不忘 '),
(1, '恭喜恭喜,这个优惠不错哦!'),
(1, '优惠幅度不小了,北京优惠八千'),
(1, '优惠可以了!购进吧!买了不会后悔的!时间可鉴! '),
(0, '现在 什么价 优惠多少'),
(0, '优惠一万一 送贴膜装甲脚垫 铁西庞大'),
(-1, '我也大连的,最近也考虑入手森林人,优惠太小了'),
(-1, '山东威海全系这才优惠3000,MD'),
(0, '下手了,豪导特供,优惠1.6万'),
(0, '优惠了8000,什么都不送。 '),
.....]
接下来就是对数据进行训练,数据集不大,还挺快的
clf = NBayes(train)
clf.train()
来看一下训练后分类器的预测结果:

至此我们一个简单的基于贝叶斯模型的分类器baseline就完成了。
参考资料:
带你搞懂朴素贝叶斯分类算法——这个里面例子比较形象
以上~
2018.04.21
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)