朴素贝叶斯分类器,英文叫’naive Bayes classifier’.顾名思义,就是很naive的一个算法。naive主要体现在一个方面 —— “属性条件独立性假设”。就是用贝叶斯算法进行分类的时候,假设所有的属性相互独立。
公式符号说明:
- A A A表示输入属性,等价x和 x ⃗ \vec{x} x(x粗写表示这是一个向量)。
- B i B_i Bi表示分类的类别,等价 c c c。
- x i x_i xi表示x的一个维度(属性)
1 . 预备知识
贝叶斯公式(不熟悉请戳《贝叶斯公式》 )
贝叶斯分类原理:
首先贝叶斯分类器具有所有分类器一样的功能:根据输入x给出一个分类结果c。
假设用朴素贝叶斯分类选秀球员,输入属性x, x是一个多维向量,包含: {百米速度,卧推,摸高,臂展,命中率,球商} 等6个维度。
输出的分类结构为
c
c
c,
c
c
c的取值范围是:
{好,一般,差}。
在这里我们对每个属性进行0-1编码量化(每个属性取值都在0和1之间,越接近1说明程度越高)。
第一步,用贝叶斯建模:
上图是贝叶斯公式的图解:
那么,把实际问题映射到这张图上就是说:
A
A
A表示输入属性,
B
B
B表示分类结果。当输入是
A
A
A的时候,
A
A
A的可能实际类别是:
B
1
B_1
B1,
B
2
B_2
B2,…,
B
n
B_n
Bn。分类器只能选出一个类别作为输出结果,那么怎么选呢?当然要选可能性最大的那个分类咯。
在图上可以清晰看到,
A
A
A与
B
n
B_n
Bn的相交面积最大,所以贝叶斯分类器会把
A
A
A分类到
B
n
B_n
Bn。即:
输出类别= argmax(P(判断类别|输入属性))
事实上,要进行更智能的分类,可以加一个风险加权值,通过最小化风险来求得分类结果(这里只讨论思维,详细可以下一篇博文再讨论)。
实际分类过程中,我们从以往经验中总结得到先验概率 P P P( B i B_i Bi)和似然概率 P P P( A A A| B i B_i Bi),然后通过贝叶斯公式获得结果。怎么操作呢?
- 首先用数据对分类器进行训练,这里的训练无非就是对训练数据进行一些统计(都有哪些类别,每种类别的概率等),根据大数定律,当训练集包含充足的独立同分布样本时,先验概率 P ( B i ) P(B_i) P(Bi)可通过各类样本出现的频率来进行估计。
- 然后获取似然概率 P ( A ∣ B i ) P(A|B_i) P(A∣Bi),由于它涉及关于 A A A所有属性的联合概率,难以从有限的训练样本直接估计而得。那么就可以引出这篇博文的主角——“朴素贝叶斯分类器”了。
2 . 朴素贝叶斯分类器
如上面最后一句话所说,朴素贝叶斯分类器就是解决似然概率难以统计获得的问题。假设每个属性独立地对分类结果产生影响。
怎么理解上面这句话呢,属性之间不相互独立的例子如下:一个球员摸高和臂展其实是高度相关的。
现在就是要naive地认为每个属性都是独立产生影响的。则贝叶斯公式可以重写为:
P
P
P(
c
c
c|x) =
P
(
c
)
P
(
x
⃗
∣
c
)
P
(
x
⃗
)
\frac{P(c)P(\vec{x}|c)} {P(\vec{x})}
P(x)P(c)P(x∣c) =
P
(
c
)
P
(
x
⃗
)
∏
i
=
1
d
P
(
x
i
∣
c
)
\frac{P(c)} {P(\vec{x})}\prod_{i=1}^dP(x_i|c)
P(x)P(c)∏i=1dP(xi∣c)
(x =
x
⃗
\vec{x}
x)
公式 1通过统计求单独的属性对结果的似然概率是很容易的,所有单独属性似然概率的乘积就是
P
(
A
∣
B
i
)
P(A|B_i)
P(A∣Bi)了。那么,上面公式里的
P
(
x
i
∣
c
)
P(x_i|c)
P(xi∣c)怎么求呢?
对于离散情况
离散情况的意思是:各属性的取值是离散的,比如说颜值的取值直接就是{高,中,低}这样的离散值,而不是0.889这样的连续取值,对于离散情况直接统计出来就行了:
P
(
x
i
∣
c
)
=
D
c
,
x
i
/
D
c
P(x_i|c) = D_{c,xi} / D_c
P(xi∣c)=Dc,xi/Dc
D
c
,
x
i
D_{c,xi}
Dc,xi表示
D
c
D_c
Dc中在第i个属性取值为
x
i
x_i
xi的样本组成的集合,
D
c
D_c
Dc表示训练集
D
D
D中第
c
c
c类样本组成的集合。
最后的
P
P
P(x|
c
c
c)就把各
P
P
P(
x
i
x_i
xi|
c
c
c)累乘起来就可以了,代入公式1可以求得
P
P
P(
c
c
c|x)。
对于连续情况
当x各维度连续取值时,你不可能在训练的时候遍历所有的取值。怎么理解呢?当训练数据某个属性取值有{0.1, 0.2, 0.3, 0.4, … , 1},当你用训练后的分类器去对新对象进行分类,而这个新对象在这个属性的取值是0.15,并不存在你的训练集中,这就是问题所在。那怎么解决呢?
我们有中心极限定理:
随机变量如果是有大量独立的而且均匀的随机变量相加而成,那么它的分布将近似于正态分布。
上面是引用百度百科,这是对中心极限定理的总结。我用白话再翻译一遍:
如果变量的取值满足独立(可以不同分布),那么这些变量叠加之后的分布是满足正态分布的。这也是自然界随处可见各种‘钟形’分布的原因。
在这里,我们也可以假设
P
P
P(
x
i
x_i
xi|
c
c
c)服从正态分布,求得训练样本中
P
P
P(
x
i
x_i
xi|
c
c
c)的期望和方差,对
P
P
P(
x
i
x_i
xi|
c
c
c)的取值做一个正态分布建模,如下:
假定
P
P
P(
x
i
x_i
xi|
c
c
c) ~
N
N
N(
μ
\mu
μ,
σ
2
\sigma^2
σ2),其中
μ
\mu
μ和
σ
2
\sigma^2
σ2分别是第c类样本在第i个属性上取值的均值和方差:
那这样就解决了连续取值问题,当输入属性取值xi并未在训练样本中出现,直接把这个取值输入
N
N
N(
μ
\mu
μ,
σ
2
\sigma^2
σ2)中,获得的取值就是
P
(
x
i
∣
c
)
P(x_i|c)
P(xi∣c)了。
同上,最后的p(x|c)就把各
P
P
P(
x
i
x_i
xi|
c
c
c)累乘起来就可以了,代入公式1可以求得
P
P
P(
c
c
c|x)。
一个基于scikit-learn的高斯朴素贝叶斯实现代码:
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
iris = datasets.load_iris()
gnb = GaussianNB()
y = gnb.fit(iris.data, iris.target).predict(iris.data)
all_num = iris.data.shape[0]
hit_num = (iris.target == y).sum()
print("accuracy=%d%%, hit/predict=%d/%d" % (100 * hit_num/all_num, hit_num, all_num))
3. 总结
对于朴素贝叶斯分类器的操作可以理解如下:
- 输入大量训练样本,每个样本包括属性和类别,属性又有连续属性和离散属性之分。
- 对样本进行统计: 都有哪些类别,每种类别占比多少( P P P( c c c)),每个属性对样本分类单独造成的影响( P P P( x i x_i xi| c c c))
- 对离散取值的属性可通过直接统计求得 P P P( x i x_i xi| c c c);而对于连续取值的属性需要进行一个正态分布建模,求出训练样本中 P P P( x i x_i xi| c c c)的期望和方差,代入到 N N N( μ \mu μ, σ 2 \sigma^2 σ2)中完成建模。
- 根据上述3个步骤,我们可以获得 P P P( c c c)和各属性的 P P P( x i x_i xi| c c c),那么直接代入公式1中,就可以求得 P P P( c c c|x)了。
- 那最终进行分类,就比较各类别的 P P P( c c c|x)(即取不同的c值),最大的那个就是我们的分类,即公式0所表示的。