朴素贝叶斯(naive Bayes)法是基于贝叶斯定理与特征条件独立假设的分类方法。
设试验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
其朴素的含义是:对条件概率分布作了条件独立的假设,用于分类的特征,在类确定的情况下都会条件独立的。
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的类输出。
所谓后验概率,即根据结果推原因,以课堂上是否打网球例子来说,在知道某人没有去打网球的情况,推算今天的风是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)。
先验概率的极大似然估计:
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
朴素贝叶斯法高效易于实现,但存在着条件独立这个很强的假设,在实际的样本中往往不成立,实际数据样本特别是样本数量多且样本属性之间关联较强时,朴素贝叶斯法的分类效果不好。
程序代码:环境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])