朴素贝叶斯法概述
朴素贝叶斯(naive Bayes)法是基于贝叶斯定理与特征条件独立假设的分类方法。
1. 定理及公式推导
1.1 定理:
设试验E的样本空间为
Ω
\Omega
Ω,A为事件
B
1
,
B
2
,
.
.
.
,
B
i
B_{1},B_{2},...,B_{i}
B1,B2,...,Bi.为
Ω
\Omega
Ω的一个划分,且
P
(
A
)
,
P
(
B
i
)
>
0
P(A),P(B_{i})>0
P(A),P(Bi)>0,则
P
(
B
i
∣
A
)
=
P
(
A
∣
B
i
)
P
(
B
i
)
∑
j
=
1
n
P
(
A
∣
B
j
)
P
(
B
j
)
⋯
i
=
1
,
2
,
…
,
n
P\left(B_{\mathrm{i}} \mid A\right)=\frac{P\left(A \mid B_{i}\right) P\left(B_{i}\right)}{\sum_{j=1}^{n} P\left(A \mid B_{j}\right) P\left(B_{j}\right)} \cdots i=1,2, \ldots, n
P(Bi∣A)=∑j=1nP(A∣Bj)P(Bj)P(A∣Bi)P(Bi)⋯i=1,2,…,n
1.2 朴素贝叶斯
其朴素的含义是:对条件概率分布作了条件独立的假设,用于分类的特征,在类确定的情况下都会条件独立的。
1.3 条件独立的假设是:
P
(
X
=
x
∣
Y
=
c
k
)
=
P
(
X
(
1
)
=
x
(
1
)
,
…
,
X
(
n
)
=
x
(
n
)
∣
Y
=
c
k
)
=
∏
j
=
1
n
P
(
X
(
j
)
=
x
(
j
)
∣
Y
=
c
k
)
P\left(X=x \mid Y=c_{k}\right)=P\left(X^{(1)}=x^{(1)}, \ldots, X^{(n)}=x^{(n)} \mid Y=c_{k}\right)=\prod_{j=1}^{n} P\left(X^{(j)}=x^{(j)} \mid Y=c_{k}\right)
P(X=x∣Y=ck)=P(X(1)=x(1),…,X(n)=x(n)∣Y=ck)=j=1∏nP(X(j)=x(j)∣Y=ck)
朴素贝叶斯法分类时,对给定的输入
x
x
x,通过学习到的模型计算后验概率分布
P
(
Y
=
c
k
∣
X
=
x
)
P\left(Y=c_{k} \mid X=x\right)
P(Y=ck∣X=x),将后验概率最大的类作为
x
x
x的类输出。
1.4 先验概率后验概率
所谓后验概率,即根据结果推原因,以课堂上是否打网球例子来说,在知道某人没有去打网球的情况,推算今天的风是weak的概率。
先验概率,即根据原因推结果,还是以打网球为例,在知道今天的风是strong,推算某人去打网球的概率。
贝叶斯算法,学习意味着估计
P
(
Y
=
c
k
)
P(Y=c_{k} )
P(Y=ck)和
P
(
X
(
j
)
=
x
(
j
)
∣
Y
=
c
k
)
P\left(X^{(j)}=x^{(j)} \mid Y=c_{k}\right)
P(X(j)=x(j)∣Y=ck)。
1.5 极大似然估计
先验概率的极大似然估计:
P
(
Y
=
c
k
)
=
∑
i
=
1
N
I
(
y
i
=
c
k
)
N
⋯
k
=
1
,
2
,
…
,
K
P\left(Y=c_{k}\right)=\frac{\sum_{i=1}^{N} I\left(y_{i}=c_{k}\right)}{N} \cdots k=1,2, \ldots, K
P(Y=ck)=N∑i=1NI(yi=ck)⋯k=1,2,…,K
条件概率的极大似然估计:
P
(
X
(
j
)
=
a
j
l
∣
Y
=
c
k
)
=
∑
i
=
1
N
I
(
x
(
j
)
=
a
j
l
,
y
i
=
c
k
)
∑
i
=
1
N
I
(
y
i
=
c
k
)
P\left(X^{(j)}=a_{j l} \mid Y=c_{k}\right)=\frac{\sum_{i=1}^{N} I\left(x^{(j)}=a_{j l}, y_{i}=c_{k}\right)}{\sum_{i=1}^{N} I\left(y_{i}=c_{k}\right)}
P(X(j)=ajl∣Y=ck)=∑i=1NI(yi=ck)∑i=1NI(x(j)=ajl,yi=ck)
j
=
1
,
2
,
…
,
n
;
⋅
l
=
1
,
2
,
…
,
S
j
⋯
;
k
=
1
,
2
,
…
,
K
j=1,2, \ldots, n ; \cdot l=1,2, \ldots, S_{j} \cdots ; k=1,2, \ldots, K
j=1,2,…,n;⋅l=1,2,…,Sj⋯;k=1,2,…,K
其中
x
(
j
)
x^{(j)}
x(j)是第
j
j
j个样本的第个特征;
a
j
l
a_{jl}
ajl是第
j
j
j个特征可能取的第
l
l
l个值;
I
I
I为指示函数。
在实际训练中,会出现训练集实例少,分类类别较多,可能会出现类别中没有训练集实例的情况,这时候,用极大似然估计可能会出现所要估计的概率值为0的情况,这时,会影响到后验概率的计算,使分类产生偏差。通常采用贝叶斯估计:
P
λ
(
X
(
j
)
=
a
j
l
∣
Y
=
c
k
)
=
∑
i
=
1
N
I
(
x
(
j
)
=
a
j
l
,
y
i
=
c
k
)
+
λ
∑
i
=
1
N
I
(
y
i
=
c
k
)
+
S
j
λ
⋅
, 其中
λ
≥
0
P_{\lambda}\left(X^{(j)}=a_{j l} \mid Y=c_{k}\right)=\frac{\sum_{i=1}^{N} I\left(x^{(j)}=a_{j l}, y_{i}=c_{k}\right)+\lambda}{\sum_{i=1}^{N} I\left(y_{i}=c_{k}\right)+S_{j} \lambda} \cdot \text {, 其中 } \lambda \geq 0
Pλ(X(j)=ajl∣Y=ck)=∑i=1NI(yi=ck)+Sjλ∑i=1NI(x(j)=ajl,yi=ck)+λ⋅, 其中 λ≥0
朴素贝叶斯法高效易于实现,但存在着条件独立这个很强的假设,在实际的样本中往往不成立,实际数据样本特别是样本数量多且样本属性之间关联较强时,朴素贝叶斯法的分类效果不好。
2. python实现
程序代码:环境python3.7
import numpy as np
from collections import Counter
data=[[1,'S',-1],[1,'M',-1],[1,'M',1],[1,'S',1],[1,'S',-1],[2,'S',-1],[2,'M',-1],[2,'M',1],[2,'L',1],[2,'L',1],[3,'L',1],[3,'L',1],[3,'M',1],[3,'M',1],[3,'L',-1]]
data_new=np.array(data)
x=[]
count_x=[]
x_num=[]
x_elem=[]
lam=1
for i in range(len(data_new[0,:])-1):
x.append(data_new[:,i])
count_x.append(Counter(x[i]))
x_num.append(len(count_x[i]))#对应特征可能取值数[3,3]
x_elem.append(list(count_x[i]))#特征中的元素[['1', '2', '3'], ['S', 'M', 'L']]
y=data_new[:,-1]
count_y=Counter(y) #标签元素及对应的个数 Counter({'1': 9, '-1': 6})
y_num=len(count_y) #y的类别数 2
y_elem=list(count_y)#标签中的元素[-1,1]
p_y=[]
p_x_y=[]
for i in range(y_num):
p_y.append((count_y[y_elem[i]]+lam)/(len(y)+y_num*lam))
print('此时先验概率P(Y={})={}'.format(y_elem[i],p_y[i]))
for i in range(len(x)):
p_xi_j=[]
for j in range(x_num[i]):
p_xj_y=[]
for k in range(y_num):
x_val = np.where(x[i] == x_elem[i][j])[0] #np.where(condiction )输出满足条件的元素坐标
y_val = np.where(y == y_elem[k])[0]
intersect_x_y = list(set(y_val).intersection(set(x_val))) #set创建一个无序不重复的元素集 y-val与x_val的交集
p_temp = (len(intersect_x_y)+lam) /( count_y[y_elem[k]]+x_num[i]*lam) #条件概率
print('条件概率P(X{}={}|Y={})={}'.format(i+1,x_elem[i][j],y_elem[k],p_temp))
p_xj_y.append(p_temp)
p_xi_j.append(p_xj_y)
p_x_y.append(p_xi_j)
data_pred=[2,'S']
def predict(data_pred,p_x_y,p_y,x_elem,y_elem):
x_num=len(p_x_y)
x=[]
x_index=[]
x_elem=np.array(x_elem)
for i in range(x_num):
x.append(str(data_pred[i]))
x_index.append(np.where(x_elem[i]==x[i])[0])
p_y_pred=[]
p_y_max=0
index=1000
for i in range(len(p_y)):
p=p_y[i]
for j in range(x_num):
p*=p_x_y[j][x_index[j][0]][i]
p_y_pred.append(p)
print('y={}的概率为:{}'.format(y_elem[i],p))
if p>p_y_max:
p_y_max=p
index=i
return index
index=predict(data_pred,p_x_y,p_y,x_elem,y_elem)
print('此时测试集数据所属类别为:',y_elem[index])
运行结果