0%

概率图模型——朴素贝叶斯

​ 逻辑回归通过拟合曲线实现分类,决策树通过寻找最佳划分特征进而学习样本路径实现分类,支持向量机通过寻找分类超平面进而最大化类间间隔实现分类,而朴素贝叶斯通过

朴素贝叶斯思想


​ 朴素贝叶斯是一种最简单的概率图模型,通过根据训练样本统计出样本的概率分布,基于贝叶斯定理条件独立假设来进行建模预测的模型。

朴素贝叶斯概率图

贝叶斯定理

1
2
3
4
5
6
7
8
p(AB)=P(A/B)P(B)
=P(B/A)P(A)

在贝叶斯模型中用到的是下面的形式:
P(Ci/W) = P(W|Ci)*P(Ci)/P(W)
其中,W为向量,有的多个值组成,Ci为标签,也就是上式可以写成下面的形式
P(Ci/w0,w1,..,w) = P(w0,w1,...,wn/Ci)*P(Ci)/P(W)
里面的P(Ci/w0,w1,..,w)就是机器学习建模最终的目标,在一定条件下是某一类的概率

条件独立假设

1
2
3
4
5
	条件独立假设认为:每个事件的发生都相互独立,互相之间没有影响。由于这个假设,上面的式子可以改为:

P(Ci/w0,w1,..,w) = P(w0,w1,...,wn/Ci)/P(Ci) = P(w0/Ci)P(w1/Ci)...P(wn/Ci)*P(Ci)/p(W)

到这里,我们可以知道,要求的最终的结果,只需要在训练集中求得P(Ci)以及在P(w0/Ci)...P(wn/Ci)即可

模型训练

因此在NB算法训练时,只需要在训练集样本中到下面三个概率分布:

​ 1.P(Ci),在训练集中标签1出现的概率(二分类只需要统计一个,n分类就需要n-1个)

​ 2.P(wj/Ci),在训练集中属于各个标签的条件下第n个特征是i的概率

注意:这里不需要统计P(W)的概率,因为最终属于各个类型的概率都需要除以相同的P(W),因此约掉

训练代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def trainNB(dataSetList,labels):
dataSetVec = np.array(dataSetList)

#计算Pc
sampleNums = len(dataSetVec)
pc = np.sum(datasetVec)/sampleNums

#计算p(wj/Ci),这里是二分类
p0Nums = 0
p1Nums = 0

#这里涉及到初始化问题
p0Vecs = np.ones(len(dataSetVec[0]))
p1Vecs = np.ones(len(dataSetVec[0]))

for i in range(len(labels)):
if labels[i]==0:
p0Vecs += dataSetVec[0]
p0Nums += 1
else:
p1Vecs += dataSetVec[0]
p1Nums += 1

p0Vecs = p0Vecs/p0Nums
p1Vecs = p1Vecs/p1Nums

return pc,p0Vecs,p1Vecs

初始化问题

​ 再利用贝叶斯分类器进行分类时,要计算多个概率等乘积以计算文档属于某个分类的概率,即计算:

​ P(w0|c=1)P(w1|c=1)….P(wn|c=1)

​ 如果其中任意一项为0,那么最终的成绩也将等于0。为了降低这种情况造成的影响,可以将所有词初始化为1.

预测过程

​ NB模型的预测过程就是使用上面统计得到的概率分布与输入数据进行关联后,计算出新的样本属于各个类型的概率,然后选择其中概率最大的类型作为模型预测类型的过程。预测过程中需要关注的一个关键问题需要重点关注,那就是python的下溢出问题

下溢出问题:在python中当多个很小的数相乘时会产生下溢出问题(最后四舍五入得到0)

解决办法:取自然对数。因为自然对数和原来的数怎增减性相同,极值点也相同

​ 使用自然对数后,上面的式可以转换成:

​ P(Ci/w0,w1,..,w) = P(w0/Ci)P(w1/Ci)…P(wn/Ci)/P(Ci) —>P(Ci/w0,w1,..,w) = log(P(w0/Ci))+…+log(P(wn/Ci))+P(Ci)

预测代码

​ 预测过程中将已知的概率分布与输入数据进行关联的方式:

​ log(P(w0/Ci))+…+log(P(wn/Ci))+P(Ci) ——>log(P(w0/Ci))x0+…+log(P(wn/Ci))xn+log(P(Ci)

​ 这里的input_data*np.log(p0Vecs)代表将每个出现的词和其出现在该类中出现该词的概率关联起来.

1
2
3
4
5
6
7
8
9
def classfyNB(input_data,pc,p0Vecs,p1Vecs):
#这里的input_data*np.log(p0Vecs)代表将每个出现的词和其出现在该类中出现该词的概率关联起来
#这里之所以没有除以pw,是因为对每个类型的pw是一致的,就没有必要所有都除了
p0 = sum(input_data*np.log(p0Vecs))+math.log(pc)
p1 = sum(input_data*np.log(p1Vecs))+math.log(1-pc)
if p0>p1:
return 0
else:
return 1