跳转至

朴素贝叶斯概述

基础

朴素贝叶斯的数学理论基础源于概率论。所以,在学习朴素贝叶斯算法之前,首先对其中涉及到的概率论知识做简要讲解。

条件概率

条件概率就是指事件 A 在另外一个事件 B 已经发生条件下的概率。如图所示 :

untitled.png

其中:

  • P(A) 表示 A 事件发生的概率。
  • P(B) 表示 B 事件发生的概率。
  • P(AB) 表示 A,B 事件同时发生的概率。

而最终计算得到的 P(A∣B) 便是条件概率,表示在 B 事件发生的情况下 A 事件发生的概率。

贝叶斯定理

上面提到了条件概率的基本概念,那么当知道事件 B 发生的情况下事件 A 发生的概率 P(A∣B),如何求 P(B∣A) 呢?贝叶斯定理应运而生。根据条件概率公式可以得到:

ps1.png

而同样通过条件概率公式可以得到:

ps2.png

将 (2) 式带入 (1) 式便可得到完整的贝叶斯定理:

ps3.png

以下,通过一张图来完整且形象的展示条件概率和贝叶斯定理的原理。

ps4.png

先验概率

指的是根据以往经验和分析得到的概率。例如以上公式中的P(A),P(B),又例如:X 表示投一枚质地均匀的硬币,正面朝上的概率,显然在我们根据以往的经验下,我们会认为X 的概率P(X)=0.5 。其中P(X)=0.5 就是先验概率。

后验概率

后验概率(Posterior Probability)是事件发生后求的反向条件概率;即基于先验概率通过贝叶斯公式求得的反向条件概率。例如公式中的 P(B∣A) 就是通过先验概率 P(A)和P(B) 得到的后验概率,其通俗的讲就是「执果寻因」中的「因」。

朴素贝叶斯

介绍

朴素贝叶斯(Naive Bayes)就是将贝叶斯原理以及条件独立结合而成的算法,其思想非常的简单,根据贝叶斯公式:

ps5.png

变形表达式为:

ps6.png

公式(5)利用先验概率,即特征和类别的概率;再利用不同类别中各个特征的概率分布,最后计算得到后验概率,即各个特征分布下的预测不同的类别。

利用贝叶斯原理求解固然是一个很好的方法,但实际生活中数据的特征之间是有相互联系的,在计算P(特征∣类别) 时,考虑特征之间的联系会比较麻烦,而朴素贝叶斯则人为的将各个特征割裂开,认定特征之间相互独立。

朴素贝叶斯中的「朴素」,即条件独立,表示其假设预测的各个属性都是相互独立的,每个属性独立地对分类结果产生影响,条件独立在数学上的表示为:P(AB)=P(A)*P(B)。这样,使得朴素贝叶斯算法变得简单,但有时会牺牲一定的分类准确率。对于预测数据,求解在该预测数据的属性出现时各个类别的出现概率,将概率值大的类别作为预测数据的类别。

理解条件独立或特征独立的小例子:如果一种水果其具有红,圆,直径大概3英寸等特征,该水果可以被判定为是苹果。尽管这些特征相互依赖或者有些特征由其他特征决定,然而朴素贝叶斯分类器认为这些属性在判定该水果是否为苹果的概率分布上独立的。

步骤

1)准备数值型或者布尔型数据;

2)计算不同的独立特征的条件概率计算P(y1∣x),P(y2∣x),P(y3∣x),…,P(ym∣x);

3)寻找P(y1∣x),P(y2∣x),P(y3∣x),…,P(ym∣x) 中最大的概率P(yk∣x),则x属于类别yk。

liuc.png

优缺点

优点

  1. 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。

  2. 对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。

  3. 对缺失数据不太敏感,算法也比较简单,常用于文本分类。

缺点

  1. 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。

  2. 需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。

  3. 由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。

  4. 对输入数据的表达形式很敏感。

推导

lcc1.png
liucc.png

代码实现

 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#数据集
x = [0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1]
y = [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1]
labels = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]

#先验概率P(种类)
print("=========计算先验概率========")
labels0_count = 0
labels1_count = 0
for c in range(len(labels)):
    if labels[c] == 0:
        labels0_count += 1
    else:
        labels1_count +=1
print("labels = 0的概率为:",labels0_count/len(labels))
print("labels = 1的概率为:",labels1_count/len(labels))
Plabels0 = labels0_count/len(labels)
Plabels1 = labels1_count/len(labels)

print("=========计算条件概率========")
#对labels = 0时的概率计算
x0_count = 0
x1_count = 0
y0_count = 0
y1_count = 0
for cc in range(len(x[:10])):
    if x[cc] == 0:
        x0_count += 1
    elif x[cc] == 1:
        x1_count += 1
for cc in range(len(x[:10])):
    if y[cc] == 0:
        y0_count += 1
    elif y[cc] == 1:
        y1_count += 1
print("P(x=0|labels=0):",x0_count/len(x[:10]))
print("P(x=1|labels=0):",x1_count/len(x[:10]))
print("P(y=0|labels=0):",y0_count/len(x[:10]))
print("P(y=1|labels=0):",y1_count/len(x[:10]))
Px00 = x0_count/len(x[:10])
Px10 = x1_count/len(x[:10])
Py00 = y0_count/len(x[:10])
Py10 = y1_count/len(x[:10])

#对labels = 1时的概率计算
ex0_count = 0
ex1_count = 0
ey0_count = 0
ey1_count = 0
for kk in range(10,20):
    if x[kk] == 0:
        ex0_count += 1
    elif x[kk] == 1:
        ex1_count += 1
for kk in range(10,20):
    if y[kk] == 0:
        ey0_count += 1
    elif y[kk] == 1:
        ey1_count += 1
print("P(x=0|labels=1):",ex0_count/len(x[10:20]))
print("P(x=1|labels=1):",ex1_count/len(x[10:20]))
print("P(y=0|labels=1):",ey0_count/len(x[10:20]))
print("P(y=1|labels=1):",ey1_count/len(x[10:20]))
Px01 = ex0_count/len(x[10:20])
Px11 = ex1_count/len(x[10:20])
Py01 = ey0_count/len(x[10:20])
Py11 = ey1_count/len(x[10:20])


print("==========分类结果=========")
#引入测试样本ex={x=1,y=2},实现对ex的分类,即属于labels=0还是labels=1
#贝叶斯定理,由于分母相同,所以只求分子
a = (Px10*Py10)*Plabels0
b = (Px11*Py11)*Plabels1
print("a=",a,"\n","b=",b)
if a > b:
    print("测试样本ex属于labels=0类")
else:
    print("测试样本ex属于labels=1类")
朴素贝叶斯运行结果查看

bspysjg.png

ip2.png