写在前面

贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。而朴素朴素贝叶斯分类是贝叶斯分类中最简单,也是常见的一种分类方法。它是基于贝叶斯定理和特征条件独立假设分类方法。对于给定训练集,首先基于特征条件独立性的假设,学习输入/输出联合概率(计算出先验概率和条件概率,然后求出联合概率)。然后基于此模型,给定输入x,利用贝叶斯概率定理求出最大的后验概率作为输出y。朴素贝叶斯法实现简单,学习和预测效率都很高,是一种常用的分类方法。

1. 朴素贝叶斯相关的统计学知识

贝叶斯学派的思想可以概括为先验概率+数据=后验概率。也就是说我们在实际问题中需要得到的后验概率,可以通过先验概率和数据一起综合得到。数据大家好理解,被频率学派攻击的是先验概率,一般来说先验概率就是我们对于数据所在领域的历史经验,但是这个经验常常难以量化或者模型化,于是贝叶斯学派大胆的假设先验分布的模型,比如正态分布,beta分布等。这个假设一般没有特定的依据,因此一直被频率学派认为很荒谬。虽然难以从严密的数学逻辑里推出贝叶斯学派的逻辑,但是在很多实际应用中,贝叶斯理论很好用,比如垃圾邮件分类,文本分类。

几个基本常用的贝叶斯公式(更具体可参见Bayes' theorem——Wiki

  • 条件独立公式

\large P(X, Y)=P(X) P(Y)

  • 条件概率公式

\large P(Y | X)=P(X, Y) / P(X)

\large P(X | Y)=P(X, Y) / P(Y)

  • 全概率公式

\large P(X)=\sum_{k} P(X | Y=Y_{k}) P\left(Y_{k}\right)

其中\small \sum_{k} P\left(Y_{k}\right)=1

  • 贝叶斯公式

P\left(Y_{k} | X\right)=\frac{P(X | Y_{k}) P\left(Y_{k}\right)}{\sum_{k} P(X | Y=Y_{k}) P\left(Y_{k}\right)}

2. 朴素贝叶斯模型

假设我们有训练数据集如下:

\small \bg_white \left(x_{1}^{(1)}, x_{2}^{(1)}, \ldots x_{n}^{(1)}, y_{1}\right),\left(x_{1}^{(2)}, x_{2}^{(2)}, \ldots x_{n}^{(2)}, y_{2}\right), \ldots\left(x_{1}^{(m)}, x_{2}^{(m)}, \ldots x_{n}^{(m)}, y_{n}\right)

即有m个样本,每个样本有n个特征,特征输出有K个类型,定义为C1、C2、... CK。

于是,从样本中可以得出朴素贝叶斯的先验分布:\small P\left(Y=C_{k}\right)(k=1,2, \ldots K)

接着学习到条件概率分布:\small P(X=x | Y=C_{k})=P\left(X_{1}=x_{1}, X_{2}=x_{2}, \ldots X_{n}=x_{n} | Y=C_{k}\right)

然后根据贝叶斯公式就可以得到XY的联合分布:

\small \begin{aligned} P\left(X, Y=C_{k}\right) &=P\left(Y=C_{k}\right) P(X=x | Y=C_{k}) \\ &=P\left(Y=C_{k}\right) P\left(X_{1}=x_{1}, X_{2}=x_{2}, \ldots X_{n}=x_{n} | Y=C_{k}\right) \end{aligned}

 

朴素贝叶斯模型假设X的n个维度之间相互独立,则有:

\small \begin{array}{c}{P\left(X_{1}=x_{1}, X_{2}=x_{2}, \ldots X_{n}=x_{n} | Y=C_{k}\right)=P\left(X_{1}=x_{1} | Y=C_{k}\right) P\left(X_{2}=x_{2} | Y=C_{k}\right) .} \\ { . P\left(X_{n}=x_{n} | Y=C_{k}\right)}\end{array}

 

回到我们需要解决的问题:判断给定测试集的一个新样本属于哪个类型?

当然作为朴素贝叶斯法进行分类,它是经过学习给定x的模型特征计算后延概率分布,将后验概率最大的类作为X的输出类。

3.朴素贝叶斯的参数估计

在朴素贝叶斯中,学习意味着估计\small P\left(Y=C_{k}\right) 和\small P\left(X_{j}=X_{j}^{(t e s t)} | Y=C_{k}\right)(j=1,2, \ldots n)

对于先验概率,可以简单地用极大似然估计得出,即样本类别Ck出现的次数Mk除以样本总数M。

对于条件概率分布,取决于先验条件:

(1)如果是离散分布:

  • 若采用极大似然估计,则:

\small P\left(X_{j}=X_{j}^{(t e s t)} | Y=C_{k}\right)=\frac{m_{k j^{t e s t}}}{m_{k}}

其中mk为样本类别Ck出现的次数,而分子为样本Ck中,第j维特征出现的次数。

  • 但是在某些时候,用极大似然估计会出现所要估计的概率值为0的情况,这时可考虑在随机变量各个取值的频数上赋予一个大于0的整数lambda,称为贝叶斯估计。常取lambda = 1,这时称为拉普拉斯平滑(Laplace smoothing)

\small P\left(X_{j}=X_{j}^{(t e s t)} | Y=C_{k}\right)=\frac{m_{k j^{t e s t}}+\lambda}{m_{k}+O_{j} \lambda}

(2)如果数据是非常稀疏的离散值,即各个特征出现概率很低,这时我们可以假设Xj符合伯努利分布,即特征Xj出现记为1,不出现记为0。即只要Xj出现即可,我们不关注Xj的次数。这样得到P(Xj=X(test)j|Y=Ck) 是在样本类别Ck中,X(test)j出现的频率。此时有:

\small P\left(X_{j}=X_{j}^{(t e s t)} | Y=C_{k}\right)=P\left(X_{j} | Y=C_{k}\right) X_{j}^{(t e s t)}+\left(1-P\left(X_{j} | Y=C_{k}\right)\right)\left(1-X_{j}^{(t e s t)}\right)

(3)如果数据是连续值,我们通常取Xj的先验概率为正态分布,即在样本类别Ck中,Xj的值符合正态分布。这样P(Xj=X(test)j|Y=Ck)的概率分布是:

\small P\left(X_{j}=X_{j}^{(t e s t)} | Y=C_{k}\right)=\frac{1}{\sqrt{2 \pi \sigma_{k}^{2}}} \exp \left(-\frac{\left(X_{j}^{(t e s t)}-\mu_{k}\right)^{2}}{2 \sigma_{k}^{2}}\right)

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

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐