朴素贝叶斯法(naive Bayes)是基于贝叶斯定理与特征条件独立假设的分类方法。朴素贝叶斯法是典型的生成方法,即由数据学习联合概率分布 P ( X , Y ) P(X, Y) P(X,Y) ,进而求出条件概率分布 P ( Y ∣ X ) P(Y|X) P(Y∣X) 作为预测的模型,更加关注 X X X 与 Y Y Y 的关系。而前面学习的回归、k-NN、感知机以及后面要学的SVM、决策树和提升方法等都是判别方法(由数据直接学习 f ( X ) f(X) f(X) 或者 P ( Y ∣ X ) P(Y|X) P(Y∣X) 作为预测的模型,关心对给定的输入 X X X,应预测什么样的输出 Y Y Y)。
数据:训练数据集 T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) T = {(x_1, y_1),(x_2, y_2),\dots,(x_N, y_N)} T=(x1,y1),(x2,y2),…,(xN,yN) 由 P ( X , Y ) P(X, Y) P(X,Y) 独立同分布产生,其中 x ∈ X ⊆ R n x \in \mathcal{X} \subseteq \mathbf{R}^n x∈X⊆Rn 为 n 维特征向量, y ∈ Y = c 1 , c 2 , ⋯   , c K y \in \mathcal{Y} = {c_1, c_2, \cdots, c_K} y∈Y=c1,c2,⋯,cK 为类标记, X X X 是定义在输入空间 X \mathcal{X} X 上的随机向量, Y Y Y 是定义在输出空间 Y \mathcal{Y} Y 上的随机变量, P ( X , Y ) P(X, Y) P(X,Y) 是 X X X 和 Y Y Y 的联合概率分布。
目标: P ( X , Y ) P(X, Y) P(X,Y)
(1) 学习先验概率分布 P ( Y = c k ) P(Y = c_k) P(Y=ck):
(2) 学习条件概率分布 P ( X = x ∣ Y = c k ) P(X = x|Y = c_k) P(X=x∣Y=ck):
P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , X ( 2 ) = x ( 2 ) , ⋯   , X ( n ) = x ( n ) ∣ Y = c k ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) (特征独立) \begin{aligned} P(X = x|Y = c_k) & = P(X^{(1)} = x^{(1)}, X^{(2)} = x^{(2)}, \cdots, X^{(n)} = x^{(n)}|Y = c_k) \\ & = \prod_{j = 1}^{n}P(X^{(j)} = x^{(j)}|Y = c_k) \quad \text{(特征独立)} \end{aligned} P(X=x∣Y=ck)=P(X(1)=x(1),X(2)=x(2),⋯,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 ( X = x , Y = c k ) P ( X = x ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) ∑ k = 1 K P ( X = x ∣ Y = c k ) P ( Y = c k ) (贝叶斯定理) = [ ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) ] P ( Y = c k ) ∑ k = 1 K [ ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) ] P ( Y = c k ) ∝ [ ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) ] P ( Y = c k ) (分母对所有 c k 都是相同的) \begin{aligned} P(Y = c_k|X = x) & = \frac{P(X = x, Y = c_k)}{P(X = x)} \\ & = \frac{P(X = x|Y = c_k)P(Y = c_k)}{\sum_{k = 1}^{K}P(X = x|Y = c_k)P(Y = c_k)} \quad \text{(贝叶斯定理)} \\ & = \frac{\left[\prod_{j = 1}^{n}P(X^{(j)} = x^{(j)}|Y = c_k)\right]P(Y = c_k)}{\sum_{k = 1}^{K}\left[\prod_{j = 1}^{n}P(X^{(j)} = x^{(j)}|Y = c_k)\right]P(Y = c_k)} \\ & \propto \left[\prod_{j = 1}^{n}P(X^{(j)} = x^{(j)}|Y = c_k)\right]P(Y = c_k) \quad \text{(分母对所有}c_k\text{都是相同的)} \end{aligned} P(Y=ck∣X=x)=P(X=x)P(X=x,Y=ck)=∑k=1KP(X=x∣Y=ck)P(Y=ck)P(X=x∣Y=ck)P(Y=ck)(贝叶斯定理)=∑k=1K[∏j=1nP(X(j)=x(j)∣Y=ck)]P(Y=ck)[∏j=1nP(X(j)=x(j)∣Y=ck)]P(Y=ck)∝[j=1∏nP(X(j)=x(j)∣Y=ck)]P(Y=ck)(分母对所有ck都是相同的)
于是:
y = arg max c k P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) \color{Red}{y = \arg \max_{c_k} P(Y = c_k)\prod_{j = 1}^{n}P(X^{(j)} = x^{(j)}|Y = c_k)} y=argckmaxP(Y=ck)j=1∏nP(X(j)=x(j)∣Y=ck)
对于给定的损失函数 L ( Y , f ( X ) ) L(Y, f(X)) L(Y,f(X)) 以及决策函数 f ( X ) f(X) f(X),期望风险函数为
R e x p ( f ) = E [ L ( Y , f ( X ) ) ] = ∫ X , Y L ( y , f ( x ) ) P ( x , y )   d x   d y = ∫ X , Y L ( y , f ( x ) ) P ( y ∣ x ) P ( x )   d x   d y = ∫ X ( ∫ Y L ( y , f ( x ) ) P ( y ∣ x )   d y ) P ( x )   d x ≜ ∫ X H ( x ) P ( x )   d x \begin{aligned} R_{exp}(f) & = E [L(Y, f(X))] \\ & = \int_{\mathcal{X},\mathcal{Y}}L(y, f(x))P(x, y) \,dx\,dy \\ & = \int_{\mathcal{X,\mathcal{Y}}}L(y, f(x))P(y|x)P(x) \,dx\,dy \\ & = \int_{\mathcal{X}}\left(\int_{\mathcal{Y}}L(y, f(x))P(y|x) \,dy\right)P(x) \,dx \\ & \triangleq \int_{\mathcal{X}}H(x)P(x) \,dx \end{aligned} Rexp(f)=E[L(Y,f(X))]=∫X,YL(y,f(x))P(x,y)dxdy=∫X,YL(y,f(x))P(y∣x)P(x)dxdy=∫X(∫YL(y,f(x))P(y∣x)dy)P(x)dx≜∫XH(x)P(x)dx
注意到 L ( y , f ( x ) ) , P ( y ∣ x ) , P ( x ) L(y, f(x)), P(y|x), P(x) L(y,f(x)),P(y∣x),P(x) 都大于等于 0,因此最小化期望风险等价于最小化 H ( x ) P ( x ) H(x)P(x) H(x)P(x),等价于对 X = x X = x X=x 逐个极小化 H ( x ) H(x) H(x)
对于朴素贝叶斯模型我们选择 0-1 损失函数,即:
L ( Y , f ( X ) ) = { 1 , Y ≠ f ( X ) 0 , Y = f ( X ) L(Y, f(X)) = \begin{cases} 1, & Y \neq f(X) \\ 0, & Y = f(X) \end{cases} L(Y,f(X))={1,0,Y̸=f(X)Y=f(X)
于是
f ( x ) = arg min y ∫ Y L ( y , f ( x ) ) P ( y ∣ x )   d y = arg min y ∑ k = 1 K L ( c k , y ) P ( c k ∣ X = x ) = arg min y ∑ k = 1 K P ( y ≠ c k ∣ X = x ) = arg min y ( 1 − P ( y = c k ∣ X = x ) ) = arg max y P ( y = c k ∣ X = x ) = arg max c k P ( c k ∣ X = x ) \begin{aligned} f(x) & = \arg \min_y \int_{\mathcal{Y}}L(y, f(x))P(y|x) \,dy \\ & = \arg \min_y \sum_{k = 1}^{K} L(c_k, y)P(c_k|X = x) \\ & = \arg \min_y \sum_{k = 1}^{K} P(y \neq c_k|X = x) \\ & = \arg \min_y (1 - P(y = c_k|X = x)) \\ & = \arg \max_y P(y = c_k|X = x) \\ & = \arg \max_{c_k} P(c_k|X = x) \end{aligned} f(x)=argymin∫YL(y,f(x))P(y∣x)dy=argymink=1∑KL(ck,y)P(ck∣X=x)=argymink=1∑KP(y̸=ck∣X=x)=argymin(1−P(y=ck∣X=x))=argymaxP(y=ck∣X=x)=argckmaxP(ck∣X=x)
所以将后验概率最大的类作为 x x x 的输出等价于最小化期望风险,因此是有道理的
前面我们知道了朴素贝叶斯分类器的公式,那么只需要求出两个概率 P ( Y = c k ) P(Y = c_k) P(Y=ck) 和 P ( X ( j ) = x ( j ) ∣ Y = c k ) P(X^{(j)} = x^{(j)}|Y = c_k) 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(Y = c_k) = \frac{\sum_{i = 1}^{N} I(y_i = c_k)}{N}, \quad k = 1,2,\cdots,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 i ( j ) = a j l , y i = c k ) ∑ i = 1 N I ( y i = c k ) P(X^{(j)} = a_{jl}|Y = c_k) = \frac{\sum_{i = 1}^{N} I(x_i^{(j)} = a_{jl}, y_i = c_k)}{\sum_{i = 1}^{N} I(y_i = c_k)} P(X(j)=ajl∣Y=ck)=∑i=1NI(yi=ck)∑i=1NI(xi(j)=ajl,yi=ck)
j = 1 , 2 , ⋯   , n , l = 1 , 2 , ⋯   , S j , k = 1 , 2 , ⋯   , K j = 1,2,\cdots,n, \ l = 1,2,\cdots,S_j, \ k = 1,2,\cdots,K j=1,2,⋯,n, l=1,2,⋯,Sj, k=1,2,⋯,K
其中 a j l a_{jl} ajl 是第 j j j 个特征可能取的第 l l l 个值,一共可取 S j S_j Sj 个值。
考虑到使用极大似然估计,新的实例点存在条件概率分布可能为 0 的情况,因此引入贝叶斯估计:
P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) + λ N + K λ , k = 1 , 2 , ⋯   , K P(Y = c_k) = \frac{\sum_{i = 1}^{N} I(y_i = c_k) \color{Red}{+ \lambda}}{N \color{Red}{+ K\lambda}}, \quad k = 1,2,\cdots,K P(Y=ck)=N+Kλ∑i=1NI(yi=ck)+λ,k=1,2,⋯,K
P ( X ( j ) = a j l ∣ Y = c k ) = ∑ i = 1 N I ( x i ( j ) = a j l , y i = c k ) + λ ∑ i = 1 N I ( y i = c k ) + S j λ P(X^{(j)} = a_{jl}|Y = c_k) = \frac{\sum_{i = 1}^{N} I(x_i^{(j)} = a_{jl}, y_i = c_k) \color{Red}{+ \lambda}}{\sum_{i = 1}^{N} I(y_i = c_k) \color{Red}{+ S_j \lambda}} P(X(j)=ajl∣Y=ck)=∑i=1NI(yi=ck)+Sjλ∑i=1NI(xi(j)=ajl,yi=ck)+λ
j = 1 , 2 , ⋯   , n , l = 1 , 2 , ⋯   , S j , k = 1 , 2 , ⋯   , K , λ ≥ 0 j = 1,2,\cdots,n, \ l = 1,2,\cdots,S_j, \ k = 1,2,\cdots,K, \color{Red}{\lambda \ge 0} j=1,2,⋯,n, l=1,2,⋯,Sj, k=1,2,⋯,K,λ≥0
常取 λ = 1 \lambda = 1 λ=1 ,这时称为拉普拉斯平滑(Lapalce smoothing),当 λ = 1 \lambda = 1 λ=1 时,称为Lidstone平滑方法(Lidstone smoothing)
(1) 分类效率稳定
(2) 对小规模数据表现很好,能处理多分类任务
(3) 适合做增量训练,尤其是数据量超出内存时,可以一批批地进行增量训练
(4) 对缺失数据不敏感
(5) 算法简单,常用于文档分类和垃圾邮件过滤
(1) 理论上模型与其他分类模型相比具有最小的误差率。但实际上总是并非如此,这是因为模型给定了输出类别的情况下假设特征之间相互独立,这是一个较强的假设,在实际中往往不能成立,因此当特征较多或者特征之间相关性较大时分类效果不好。所以也有一些考虑特征相关性而进行改进的贝叶斯算法
(2) 尽管我们可以估计先验概率,但是先验概率的假设是可以有很多种的,因此在某些时候会由于假设的先验模型不好导致预测效果不佳
(3) 由于概率是基于数据进行计算的,所以存在一定的误差
(4) 模型对于输入数据的表达形式很敏感,比如有两个特征 X ( 1 ) , X ( 2 ) X^{(1)},X^{(2)} X(1),X(2),第一个取值为 1,2,3,4,第二个取值为 a,a,b,b,这时还很不错;但如果第一个特征是 1,1.1,2,2.1,特征取值非常接近而被归成了 1 和 2,那么两个特征就强相关了
参考:Scikit-learn 0.21.x 中文文档
朴素贝叶斯分类器有许多种,各种各样的的朴素贝叶斯分类器的差异大部分来自于处理 P ( x i ∣ y ) P(x_i \mid y) P(xi∣y) 分布时的所做的假设不同。
我们前面学习的朴素贝叶斯算法是基于一种假设——数据服从多项分布,即用相对频率来估计概率(平滑过的最大似然估计),这种朴素贝叶斯算法称为多项分布朴素贝叶斯(MultinomialNB,MNB)。该方法是用于文本分类的两大经典朴素贝叶斯算法之一。其在sklearn中的实现函数为 sklearn.naive_bayes.MultinomialNB(),可以通过 partial_fit() 方法动态地增加训练集,解决训练数据过大无法一次性放入内存的问题。
补充朴素贝叶斯(ComplementNB,CNB)是标准多项式朴素贝叶斯(MNB)算法的一种改进,特别适用于不平衡数据集。具体来说,CNB使用来自每个类的补数的统计数据来计算模型的权重。CNB的发明者的经验表明,CNB的参数估计比MNB的参数估计更稳定。此外,CNB在文本分类任务上通常比MNB表现得更好(通常有相当大的优势)。原理参考Tackling the poor assumptions of naive bayes text classifiers。其在sklearn中的实现函数为 sklearn.naive_bayes.ComplementNB()
对于特征是连续型变量的情况,我们可以通过数据分箱转化为离散型变量,甚至进一步转化为One-hot变量。然而有一种更直接的处理离散型变量的方法就是高斯朴素贝叶斯。高斯朴素贝叶斯(GaussianNB)假设特征服从高斯分布(正态分布),即
P ( x i ∣ y ) = 1 2 π σ y 2 exp ( − ( x i − μ y ) 2 2 σ y 2 ) P(x_i \mid y) = \frac{1}{\sqrt{2 \pi \sigma_y^2}} \exp \left( - \frac{{(x_i - \mu_y)}^2}{2 \sigma_y^2}\right) P(xi∣y)=2πσy21exp(−2σy2(xi−μy)2)
其中 μ y \mu_y μy, σ y \sigma_y σy 使用极大似然估计法计算。其在sklearn中的实现函数为sklearn.naive_bayes.GaussianNB()
伯努利朴素贝叶斯(BernoulliNB)假设特征服从伯努利分布。因此,这类算法要求样本以二元值特征向量表示;如果样本含有其他类型的数据, 一个 BernoulliNB 实例会将其二值化(取决于 binarize 参数)。在文本分类中,多用于词频向量(word occurrence vectors)分析,而非词数向量(word count vectors)。其在sklearn中的实现函数为sklearn.naive_bayes.BernoulliNB()
P ( x i ∣ y ) = P ( i ∣ y ) x i + ( 1 − P ( i ∣ y ) ) ( 1 − x i ) P(x_i \mid y) = P(i \mid y)x_i + (1 - P(i \mid y))(1 - x_i) P(xi∣y)=P(i∣y)xi+(1−P(i∣y))(1−xi)
不同于多项分布朴素贝叶斯,在MNB中,若平滑参数(贝叶斯参数)取0,对于样本中没有出现的特征,概率会出现 0,。而在伯努利贝叶斯算法中这一情况就不会出现。
data = np.array([[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,'M',1],
[3,'M',1],
[3,'L',1],
[3,'L',-1]])
x = np.array([2, 'S'])
import numpy as np
class Bayes:
def __init__(self, data):
'''
self.X: 输入空间
self.Y: 输出空间
self.N: 样本个数
self.n: 特征个数
self.label: 类标签
self.K: 类标签数量
self.y_mat: 先验概率
feature_i: 存放特征i的特征值
S_i: 特征i的特征值个数
fi_mat: 存放关于特征i的条件概率
'''
self.X = data[:, :-1]
self.Y = data[:, -1]
self.N = self.X.shape[0]
self.n = self.X.shape[1]
self.label = np.unique(self.Y)
self.K = self.label.shape[0]
self.y_mat = np.zeros(shape = (self.K, ))
for i in range(self.n):
setattr(self, 'feature_'+str(i), np.unique(self.X[:,i]))
setattr(self, 'S_'+str(i), np.unique(self.X[:,i]).shape[0])
setattr(self, 'f'+str(i)+'_mat', np.zeros(shape = (np.unique(self.X[:,i]).shape[0], self.K)))
def fit(self, l = 0, prob_print = False):
'''
求先验概率和条件概率的函数
l: 贝叶斯估计参数,当l=0时为极大似然估计
prob_print: 是否打印所求概率结果
'''
for k in range(self.K):
if prob_print == True:
print('P(Y = %s) = %d/%d' %(self.label[k], sum(self.Y.flatten() == self.label[k]) + l, self.N + self.K*l))
self.y_mat[k] = (sum(self.Y.flatten() == self.label[k]) + l)/(self.N +self.K*l)
for i in range(self.n):
temp_mat = getattr(self, 'f'+str(i)+'_mat')
temp_S = getattr(self, 'S_'+str(i))
for j in range(temp_S):
temp_f = getattr(self, 'feature_'+str(i))
temp_mat[j][k] = (sum((self.X[:,i]==temp_f[j])&(self.Y.flatten()==self.label[k])) + l) \
/(sum(self.Y.flatten()==self.label[k]) + temp_S*l)
if prob_print == True:
print('P(X^%d = %s|Y = %s) = %d/%d' %(i+1, temp_f[j], self.label[k],
sum((self.X[:,i]==temp_f[j])&(self.Y.flatten()==self.label[k])) + l,
sum(self.Y.flatten()==self.label[k]) + temp_S*l))
def predict(self, x):
'''
预测函数
'''
prob = np.zeros(shape = (self.K))
index = np.zeros(shape = (self.n))
for i in range(self.n):
temp_f = getattr(self, 'feature_'+str(i))
index[i] = np.where(temp_f == str(x[i]))[0][0]
for k in range(self.K):
prob[k] = self.y_mat[k]
for i in range(self.n):
temp_mat = getattr(self, 'f'+str(i)+'_mat')
prob[k] = prob[k] * temp_mat[int(index[i])][k]
prediction = self.label[np.where(prob==max(prob))][0]
return prediction
b = Bayes(data)
b.fit(l=0, prob_print=True) # 极大似然估计
P(Y = -1) = 6/15
P(X^1 = 1|Y = -1) = 3/6
P(X^1 = 2|Y = -1) = 2/6
P(X^1 = 3|Y = -1) = 1/6
P(X^2 = L|Y = -1) = 1/6
P(X^2 = M|Y = -1) = 2/6
P(X^2 = S|Y = -1) = 3/6
P(Y = 1) = 9/15
P(X^1 = 1|Y = 1) = 2/9
P(X^1 = 2|Y = 1) = 3/9
P(X^1 = 3|Y = 1) = 4/9
P(X^2 = L|Y = 1) = 4/9
P(X^2 = M|Y = 1) = 4/9
P(X^2 = S|Y = 1) = 1/9
b.predict(x)
‘-1’
b.fit(l=1, prob_print=True) # 拉普拉斯平滑估计
P(Y = -1) = 7/17
P(X^1 = 1|Y = -1) = 4/9
P(X^1 = 2|Y = -1) = 3/9
P(X^1 = 3|Y = -1) = 2/9
P(X^2 = L|Y = -1) = 2/9
P(X^2 = M|Y = -1) = 3/9
P(X^2 = S|Y = -1) = 4/9
P(Y = 1) = 10/17
P(X^1 = 1|Y = 1) = 3/12
P(X^1 = 2|Y = 1) = 4/12
P(X^1 = 3|Y = 1) = 5/12
P(X^2 = L|Y = 1) = 5/12
P(X^2 = M|Y = 1) = 5/12
P(X^2 = S|Y = 1) = 2/12
b.predict(x)
‘-1’
前面所讲的算法在sklearn中实现的类为sklearn.naive_bayes.MultinomialNB(),还有许多改进的朴素贝叶斯法我们后面再讲
参数列表
参数名 | 参数类型 | 参数说明 |
---|---|---|
alpha | float(默认为1) | 贝叶斯估计参数,为0时为极大似然估计 |
fit_prior | boolean(默认True) | 是否根据数据学习一个先验概率,若为False则使用均匀分布 |
class_prior | array-like, size (n_classes,)(默认None) | 自定义的先验概率 |
方法列表
方法 | 说明 |
---|---|
fit(self, X, y[, sample_weight]) | 训练 |
get_params(self[, deep]) | 获取模型参数 |
partial_fit(self, X, y[, classes, sample_weight]) | 在原模型上动态增加训练数据 |
predict(self, X) | 返回预测结果 |
predict_log_proba(self, X) | 返回预测的对数概率 |
predict_proba(self, X) | 返回预测的概率,实际上这个概率的意义并不是很大 |
score(self, X, y[, sample_weight]) | 返回在测试集上的准确率 |
set_params(self, **params) | 设置参数 |
from sklearn.naive_bayes import MultinomialNB
X = np.random.randint(5, size=(6, 100))
y = np.array([1, 2, 3, 4, 5, 6])
clf = MultinomialNB()
clf.fit(X, y)
print(clf.predict(X[2:3]))
[3]
from sklearn import datasets
from sklearn.naive_bayes import GaussianNB
iris = datasets.load_iris()
clf = GaussianNB()
clf.fit(iris.data, iris.target)
GaussianNB(priors=None, var_smoothing=1e-09)
clf.predict(iris.data[0].reshape(1, -1))[0] == iris.target[0]
True
clf.predict(iris.data[149].reshape(1, -1))[0] == iris.target[149]
True
clf.predict(np.array([7, 7, 7, 7]).reshape(1, -1))[0]
2
《统计学习方法》李航
Scikit-learn 0.21.x 中文文档