这次需要总结的是朴素贝叶斯算法,参考文章:
朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法。
贝叶斯定理是基于条件概率来计算的,条件概率是在已知事件B发生的前提下,求解事件A发生的概率,即 P(A|B)=P(AB)P(B) ,而贝叶斯定理则可以通过 P(A|B) 来求解 P(B|A) :
而特征条件独立假设是指假设各个维度的特征 x1,x2,...,xn 互相独立,则条件概率可以转化为:
朴素贝叶斯的学习意味着估计 P(yk) 和 P(xi|yk) ,可以通过极大似然估计来估计相应的概率。
如上图所示,分别是 P(yk) 和 P(xi|yk) 的极大似然估计。
当求解完上述两个概率,就可以对测试样本使用朴素贝叶斯分类算法来预测其所属于的类别,简单总结的算法流程如下所示:
用极大似然估计可能会出现所要估计的概率值为0的情况,这会影响到后验概率的计算,使分类产生偏差。解决这个问题的办法是使用贝叶斯估计,也被称为多项式模型。
当特征是离散的时候,使用多项式模型。多项式模型在计算先验概率 P(yk) 和条件概率 P(xi|yk) 时,会做一些平滑处理,具体公式为:
N 是总的样本个数,k是总的类别个数, Nyk 是类别为 yk 的样本个数, α 是平滑值。
Nyk 是类别为 yk 的样本个数, n 是特征的维数,Nyk,xi是类别为 yk 的样本中,第 i 维特征的值是xi的样本个数, α 是平滑值。
当α=1时,称作Laplace平滑,当 0<α<1 时,称作Lidstone平滑,α=0时不做平滑。
如果不做平滑,当某一维特征的值 xi 没在训练样本中出现过时,会导致 P(xi|yk)=0 ,从而导致后验概率为0。加上平滑就可以克服这个问题。
当特征是连续变量的时候,运用多项式模型会导致很多 P(xi|yk)=0 (不做平滑的情况下),即使做平滑,所得到的条件概率也难以描述真实情况,所以处理连续变量,应该采用高斯模型。
高斯模型是假设每一维特征都服从高斯分布(正态分布):
与多项式模型一样,伯努利模型适用于离散特征的情况,所不同的是,伯努利模型中每个特征的取值只能是1和0(以文本分类为例,某个单词在文档中出现过,则其特征值为1,否则为0).
伯努利模型中,条件概率P(xi|yk)的计算方式是:
当特征值 xi 为1时, P(xi|yk)=P(xi=1|yk) ;
当特征值 xi 为0时, P(xi|yk)=1−P(xi=1|yk) ;
下面是使用sklearn
的代码例子,分别实现上述三种模型,例子来自朴素贝叶斯的三个常用模型:高斯、多项式、伯努利。
下面是高斯模型的实现
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> iris.feature_names # 四个特征的名字
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
>>> iris.data
array([[ 5.1, 3.5, 1.4, 0.2],
[ 4.9, 3. , 1.4, 0.2],
[ 4.7, 3.2, 1.3, 0.2],
[ 4.6, 3.1, 1.5, 0.2],
[ 5. , 3.6, 1.4, 0.2],
[ 5.4, 3.9, 1.7, 0.4],
[ 4.6, 3.4, 1.4, 0.3],
[ 5. , 3.4, 1.5, 0.2],
......
[ 6.5, 3. , 5.2, 2. ],
[ 6.2, 3.4, 5.4, 2.3],
[ 5.9, 3. , 5.1, 1.8]]) #类型是numpy.array
>>> iris.data.size
600 #共600/4=150个样本
>>> iris.target_names
array(['setosa', 'versicolor', 'virginica'],
dtype='|S10')
>>> iris.target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,....., 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ......, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
>>> iris.target.size
150
>>> from sklearn.naive_bayes import GaussianNB
>>> clf = GaussianNB()
>>> clf.fit(iris.data, iris.target)
>>> clf.predict(iris.data[0])
array([0]) # 预测正确
>>> clf.predict(iris.data[149])
array([2]) # 预测正确
>>> data = numpy.array([6,4,6,2])
>>> clf.predict(data)
array([2]) # 预测结果很合理
多项式模型如下:
>>> import numpy as np
>>> X = np.random.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(alpha=1.0, class_prior=None, fit_prior=True)
>>> print(clf.predict(X[2]))
[3]
值得注意的是,多项式模型在训练一个数据集结束后可以继续训练其他数据集而无需将两个数据集放在一起进行训练。在sklearn中,MultinomialNB()类的partial_fit()方法可以进行这种训练。这种方式特别适合于训练集大到内存无法一次性放入的情况。
在第一次调用partial_fit()
时需要给出所有的分类标号。
>>> import numpy
>>> from sklearn.naive_bayes import MultinomialNB
>>> clf = MultinomialNB()
>>> clf.partial_fit(numpy.array([1,1]), numpy.array(['aa']), ['aa','bb'])
GaussianNB()
>>> clf.partial_fit(numpy.array([6,1]), numpy.array(['bb']))
GaussianNB()
>>> clf.predict(numpy.array([9,1]))
array(['bb'],
dtype='|S2')
伯努利模型如下:
>>> import numpy as np
>>> X = np.random.randint(2, size=(6, 100))
>>> Y = np.array([1, 2, 3, 4, 4, 5])
>>> from sklearn.naive_bayes import BernoulliNB
>>> clf = BernoulliNB()
>>> clf.fit(X, Y)
BernoulliNB(alpha=1.0, binarize=0.0, class_prior=None, fit_prior=True)
>>> print(clf.predict(X[2]))
[3]
朴素贝叶斯的总结就到这里为止。