朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法。
要明白什么是贝叶斯定理,则先复习一下几个术语:条件概率、特征条件独立假设.
什么是条件概率?
P ( A ∣ B ) P(A|B) P(A∣B)表示事件B已经发生的前提下,事件A发生的概率,也叫做事件B发生下事件A的条件概率。上述用数学语言描述为:
P ( A ∣ B ) = P ( A B ) P ( B ) {P(A|B)=\frac{P(AB)}{P(B)}} P(A∣B)=P(B)P(AB)
贝叶斯定理是基于条件概率,通过 P ( A ∣ B ) P(A|B) P(A∣B)来求解 P ( B ∣ A ) P(B|A) P(B∣A): P ( B ∣ A ) = P ( A ∣ B ) P ( B ) P ( A ) P(B|A)=\frac{P(A|B)P(B)}{P(A)} P(B∣A)=P(A)P(A∣B)P(B)
根据全概率公式,上式又可以写为:
P ( B i ∣ A ) = P ( B i ) P ( A ∣ B i ) ∑ j = 1 n P ( B j ) P ( A ∣ B j ) {P(B_i|A)=\frac{P(B_i)P(A|B_i)}{\sum_{j=1}^{n} P(B_j)P(A|B_j)}} P(Bi∣A)=∑j=1nP(Bj)P(A∣Bj)P(Bi)P(A∣Bi)
上面介绍了条件概率,那什么是特征条件独立假设?
给定训练集 ( X , Y ) (X,Y) (X,Y), x x x是集合 X X X中的样本( x ∈ X x \in X x∈X), x = ( x 1 , x 2 , . . . , x n ) x=(x_1,x_2,...,x_n) x=(x1,x2,...,xn),类标记集合含有 K K K中类别,及 Y = { c 1 , c 2 , . . . , c K } \mathcal{Y}=\{c_1,c_2,...,c_K\} Y={c1,c2,...,cK}.
如何预测新样本 x x x的类别呢?从概率的角度分析,该问题的本质就是给定 x x x,它属于哪个类别的概率最大.
即问题转化为求解 P ( Y = c 1 ∣ X = x ) , P ( Y = c 2 ∣ X = x ) , . . . , P ( Y = c k ∣ X = x ) P(Y=c_1|X=x),P(Y=c_2|X=x),...,P(Y=c_k|X=x) P(Y=c1∣X=x),P(Y=c2∣X=x),...,P(Y=ck∣X=x)中最大的概率,即求后验概率最大输出: arg max c k P ( Y = c k ∣ X = x ) {\arg \max_{c_k} P(Y=c_k|X=x)} argmaxckP(Y=ck∣X=x).后验概率最大的类作为 x x x的类别输出.
要求后验概率最大输出: arg max c k P ( Y = c k ∣ X = x ) {\arg \max_{c_k} P(Y=c_k|X=x)} argmaxckP(Y=ck∣X=x),也就是要求出: P ( Y = c k ∣ X = x ) {P(Y=c_k|X=x)} P(Y=ck∣X=x).想要求出 P ( Y = c k ∣ X = x ) {P(Y=c_k|X=x)} P(Y=ck∣X=x),就要用到贝叶斯定理,根据贝叶斯定理,可得:
(1) P ( Y = c k ∣ X = x ) = P ( X = x ∣ Y = c k ) P ( Y = c k ) ∑ k P ( X = x ∣ Y = c k ) P ( Y = c k ) {P(Y=c_k|X=x)=\frac{P(X=x|Y=c_k)P(Y=c_k)}{\sum_{k} P(X=x|Y=c_k)P(Y=c_k)}} \tag{1} P(Y=ck∣X=x)=∑kP(X=x∣Y=ck)P(Y=ck)P(X=x∣Y=ck)P(Y=ck)(1)
针对条件概率 P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , . . . , X ( n ) = x ( n ) ) P(X=x|Y=c_k)=P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)}) P(X=x∣Y=ck)=P(X(1)=x(1),...,X(n)=x(n)),假设第 i i i维特征 x i x_i xi可取值有 S j S_j Sj个,类别取值个数为 K K K个,那么参数个数为: K ∏ j = 1 n S j K \prod_{j=1}^{n}S_j K∏j=1nSj,其规模为指数数量级别的。这在实际应用中肯定不行的。
为了解决这个问题,朴素贝叶斯法对条件概率分布作了条件独立性的假设,即假设各个维度的特征 x 1 , x 2 , . . . , x n x_1,x_2,...,x_n x1,x2,...,xn互独立.
有了上述假设,条件概率可以转化为:
(2) P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , . . . , X ( n ) = x ( n ) ) = ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) {P(X=x|Y=c_k)=P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)})}=\prod_{j=1}^{n}P(X^{(j)}=x^{(j)}|Y=c_k) \tag{2} P(X=x∣Y=ck)=P(X(1)=x(1),...,X(n)=x(n))=j=1∏nP(X(j)=x(j)∣Y=ck)(2)
将式子(2)带入式子(1)可得:
(3) P ( Y = c k ∣ X = x ) = P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) ∑ k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) , k = 1 , 2 , . . . , K {P(Y=c_k|X=x)=\frac {P(Y=c_k) \prod_{j} P(X^{(j)}=x^{(j)}|Y=c_k)}{\sum_k P(Y=c_k) \prod_j P(X^{(j)}=x^{(j)}|Y=c_k)}},k=1,2,...,K \tag{3} P(Y=ck∣X=x)=∑kP(Y=ck)∏jP(X(j)=x(j)∣Y=ck)P(Y=ck)∏jP(X(j)=x(j)∣Y=ck),k=1,2,...,K(3)
式子(3)位朴素贝叶斯分类的基本公式。即 朴素贝叶斯分类器可由下式子表示:
(4) y = f ( x ) = arg max c k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) ∑ k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) {y=f(x)=\arg \max_{c_k} \frac {P(Y=c_k) \prod_{j} P(X^{(j)}=x^{(j)}|Y=c_k)}{\sum_k P(Y=c_k) \prod_j P(X^{(j)}=x^{(j)}|Y=c_k)}} \tag{4} y=f(x)=argckmax∑kP(Y=ck)∏jP(X(j)=x(j)∣Y=ck)P(Y=ck)∏jP(X(j)=x(j)∣Y=ck)(4)
由于对于所有的 c k c_k ck,上式子分母的值是一样的,所以可以忽略掉分母部分。最终朴素贝叶斯分类器的表达式为:
y = arg max c k P ( Y = c k ) ∏ j P ( X ( j ) = x ( j ) ∣ Y = c k ) {y=\arg \max_{c_k} P(Y=c_k) \prod_{j} P(X^{(j)}=x^{(j)}|Y=c_k)} y=argckmaxP(Y=ck)j∏P(X(j)=x(j)∣Y=ck)
上述的表述是从头到尾推导出朴素贝叶斯分类器的过程.
若对推导过程不感兴趣,可跳过上述推导,直接看下面朴素贝叶斯分类算法:
基本方法:
设输入空间 X ⊆ R n \mathcal{X}\subseteq \mathcal{R}^n X⊆Rn是 n n n维向量的集合,输出空间为类标记集合 Y = { c 1 , c 2 , . . . , c K } \mathcal{Y}=\{c_1,c_2,...,c_K\} Y={c1,c2,...,cK}.其中特征向量 x ∈ X {x}\in \mathcal{X} x∈X作为输入,类标记 y ∈ Y y\in \mathcal{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),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)}由 P ( X , Y ) P(X,Y) P(X,Y)独立同分部产生。其中 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的联合概率分布。
输入:
训练数据 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)},其中 x i = ( x i ( 1 ) , x i ( 2 ) , . . . , x i ( n ) ) T x_i=(x_{i}^{(1)},x_{i}^{(2)},...,x_{i}^{(n)})^{\mathrm{T}} xi=(xi(1),xi(2),...,xi(n))T, x i ( j ) x_{i}^{(j)} xi(j)是第 i i i个样本的第 j j j个特征, x i ( j ) ∈ { a j 1 , a j 2 , . . . , a j S j } x_i^{(j)} \in \{a_{j1},a_{j2},...,a_{jS_j}\} xi(j)∈{aj1,aj2,...,ajSj}, a j l a_{jl} ajl是第 j j j个特征可能取的第 l l l个值, j = 1 , 2 , . . . , n j=1,2,...,n j=1,2,...,n, l = 1 , 2 , . . . , S j l=1,2,...,S_j l=1,2,...,Sj, y i ∈ { c 1 , c 2 , . . . , c K } y_i \in \{c_1,c_2,...,c_K\} yi∈{c1,c2,...,cK}, x x x是实例。
输出:
实例 x x x的分类
第一步:先计算先验概率及条件概率
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}},k=1,2,...,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)
S j = 1 , 2 , . . . , n ; l = 1 , 2 , . . . , S j ; k = 1 , 2 , . . . , K Sj=1,2,...,n;l=1,2,...,S_j;k=1,2,...,K Sj=1,2,...,n;l=1,2,...,Sj;k=1,2,...,K
第二步:对于给定的实例 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) x=(x^{(1)},x^{(2)},...,x^{(n)}) x=(x(1),x(2),...,x(n))计算
P ( Y = c k ) ∏ j = 1 n P ( X ( j ) ∣ Y = c k ) , k = 1 , 2 , . . . , K {P(Y=c_k)}\prod_{j=1}^{n}P(X^{(j)}|Y=c_k),k=1,2,...,K P(Y=ck)j=1∏nP(X(j)∣Y=ck),k=1,2,...,K
第三步:确定实例 x x x的类
y = arg max c k P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) {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)
针对最终的朴素贝叶斯分类算法,如何求解 P ( Y = c k ) , P ( X ( j ) = x ( j ) ∣ Y = c k ) P(Y=c_k),P(X^{(j)}=x^{(j)}|Y=c_k) P(Y=ck),P(X(j)=x(j)∣Y=ck),常见有三种模型:
多项式模型、高斯模型、伯努利模型。
其中 N N N是总的样本个数, k k k是总的类别个数, N c k N_{c_k} Nck是类别 c k c_k ck的样本个数, α \alpha α是平滑值.
P ( X ( j ) = x ( j ) ∣ Y = c k ) = N c k , x i + α N c k + n α {P(X^{(j)}=x^{(j)}|Y=c_k)=\frac{N_{c_k,x_i}+\alpha}{N_{c_k}+n\alpha}} P(X(j)=x(j)∣Y=ck)=Nck+nαNck,xi+α
其中 N c k N_{c_k} Nck是类别 c k c_k ck的样本个数, n n n是特征维数, N c k , x i N_{c_k,x_i} Nck,xi是类别 c k c_k ck的样本中,第 i i i维特征值是 x i x_i xi的样本个数, α \alpha α是平滑值。
当** α = 1 \alpha=1 α=1时,称作 L a p l a c e 平 滑 Laplace平滑 Laplace平滑;
当 0 < α < 1 0<\alpha<1 0<α<1时,称作 L i d s t o n e 平 滑 Lidstone平滑 Lidstone平滑**;
当 α = 0 \alpha=0 α=0时,不做平滑处理。
高斯模型 GaussianNB
特征的可能性被假设为高斯
其概率密度函数:
P ( x i ∣ y k ) = 1 2 π σ y k 2 e x p ( − ( x i − μ y k ) 2 2 σ y k 2 ) P(x_i | y_k)=\frac{1}{\sqrt{2\pi\sigma^2_{yk}}}exp(-\frac{(x_i-\mu_{yk})^2}{2\sigma^2_{yk}}) P(xi∣yk)=2πσyk21exp(−2σyk2(xi−μyk)2)
数学期望(mean): μ \mu μ
方差: σ 2 = ∑ ( X − μ ) 2 N \sigma^2=\frac{\sum(X-\mu)^2}{N} σ2=N∑(X−μ)2
与多项式模型一样,伯努利模型适用于离散特征的情况,所不同的是,伯努利模型中每个特征的取值只能是1和0.(举例说明:在文本分类中,某个单词在文档中出现过,则其特征值为1,否则为0)
在伯努利模型中,条件概率 P ( X ( j ) = x ( j ) ∣ Y = c k ) P(X^{(j)}=x^{(j)}|Y=c_k) P(X(j)=x(j)∣Y=ck)的计算方式如下:
当特征值 x ( j ) = 1 x^{(j)}=1 x(j)=1时, P ( X ( j ) = x ( j ) ∣ Y = c k ) = P ( X ( j ) = 1 ∣ Y = c k ) P(X^{(j)}=x^{(j)}|Y=c_k)=P(X^{(j)}=1|Y=c_k) P(X(j)=x(j)∣Y=ck)=P(X(j)=1∣Y=ck)
当特征值 x ( j ) = 0 x^{(j)}=0 x(j)=0时, P ( X ( j ) = x ( j ) ∣ Y = c k ) = 1 − P ( X ( j ) = 1 ∣ Y = c k ) P(X^{(j)}=x^{(j)}|Y=c_k)=1-P(X^{(j)}=1|Y=c_k) P(X(j)=x(j)∣Y=ck)=1−P(X(j)=1∣Y=ck)
下面是是scikit-learn库中多项式模型的朴素贝叶斯分类器实现代码
案例代码已上传:Github地址
"""
API Reference: http://scikit-learn.org/stable/modules/naive_bayes.html#naive-bayes
定义一个MultinomialNB类
"""
import numpy as np
class MultinomialNB(object):
def __init__(self,alpha=1.0,fit_prior=True,class_prior=None):
"""
多项式模型的朴素贝叶斯分类器。多项式朴素贝叶斯分类器适用于具有离散特征的分类。
参数
----------
alpha : 平滑参数(float类型),默认为1.0;
如果alpha=0则不平滑。
如果 0 < alpha < 1 则为Lidstone平滑
如果 alpha = 1 则为Laplace 平滑
fit_prior : 布尔型
是否学习类别先验概率。
如果设置为False,将使用统一的优先权。
class_prior : array-like, size (n_classes,)
类别的先验概率。如果指定,则不会根据数据调整优先级。
"""
self.alpha = alpha
self.fit_prior = fit_prior
self.class_prior = class_prior
self.classes = None
self.conditional_prob = None
def _calculate_feature_prob(self,feature):
values = np.unique(feature)
total_num = float(len(feature))
value_prob = {}
for v in values:
value_prob[v] = (( np.sum(np.equal(feature,v)) + self.alpha ) /( total_num + len(values)*self.alpha))
return value_prob
def fit(self,X,y):
#TODO: check X,y
self.classes = np.unique(y)
#计算类别先验概率: P(y=ck)
if self.class_prior == None:
class_num = len(self.classes)
if not self.fit_prior:
self.class_prior = [1.0/class_num for _ in range(class_num)] #uniform prior
else:
self.class_prior = []
sample_num = float(len(y))
for c in self.classes:
c_num = np.sum(np.equal(y,c))
self.class_prior.append((c_num+self.alpha)/(sample_num+class_num*self.alpha))
#计算条件概率 P( xj | y=ck )
self.conditional_prob = {} # like { c0:{ x0:{ value0:0.2, value1:0.8 }, x1:{} }, c1:{...} }
for c in self.classes:
self.conditional_prob[c] = {}
for i in range(len(X[0])): #for each feature
feature = X[np.equal(y,c)][:,i]
self.conditional_prob[c][i] = self._calculate_feature_prob(feature)
return self
#给定values_prob {value0:0.2,value1:0.1,value3:0.3,.. } and target_value
#返回target_value的概率
def _get_xj_prob(self,values_prob,target_value):
return values_prob[target_value]
#基于(class_prior,conditional_prob)预测单个样本
def _predict_single_sample(self,x):
label = -1
max_posterior_prob = 0
#对于每个类别,计算其后验概率: class_prior * conditional_prob
for c_index in range(len(self.classes)):
current_class_prior = self.class_prior[c_index]
current_conditional_prob = 1.0
feature_prob = self.conditional_prob[self.classes[c_index]]
j = 0
for feature_i in feature_prob.keys():
current_conditional_prob *= self._get_xj_prob(feature_prob[feature_i],x[j])
j += 1
#比较后验概率并更新最大后验概率,标签
if current_class_prior * current_conditional_prob > max_posterior_prob:
max_posterior_prob = current_class_prior * current_conditional_prob
label = self.classes[c_index]
return label
#样本预测(也可以是单样本预测)
def predict(self,X):
#TODO1:check and raise NoFitError
#ToDO2:check X
if X.ndim == 1:
return self._predict_single_sample(X)
else:
#为每个样本进行分类
labels = []
for i in range(X.shape[0]):
label = self._predict_single_sample(X[i])
labels.append(label)
return labels
多项式模型下的朴素贝叶斯分类算法测试:
import numpy as np
X = np.array([
[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3],
[4,5,5,4,4,4,5,5,6,6,6,5,5,6,6]
])
X = X.T
y = np.array([-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1])
nb = MultinomialNB(alpha=1.0,fit_prior=True)
nb.fit(X,y)
print(nb.predict(np.array([2,4])))#输出-1
高斯模型与多项式模型唯一不同的地方就在于计算 P(xi|yk),高斯模型假设各维特征服从正态分布,需要计算的是各维特征的均值与方差。所以我们定义GaussianNB类,继承自MultinomialNB并且重载相应的方法即可。
#GaussianNB differ from MultinomialNB in these two method:
# _calculate_feature_prob, _get_xj_prob
class GaussianNB(MultinomialNB):
#计算给定特征的平均值(mu)和标准偏差(sigma)
def _calculate_feature_prob(self,feature):
mu = np.mean(feature)
sigma = np.std(feature)
return (mu,sigma)
#高斯分布的概率密度
def _prob_gaussian(self,mu,sigma,x):
return ( 1.0/(sigma * np.sqrt(2 * np.pi)) *
np.exp( - (x - mu)**2 / (2 * sigma**2)) )
#给定mu和sigma,目标值返回高斯分布概率
def _get_xj_prob(self,mu_sigma,target_value):
return self._prob_gaussian(mu_sigma[0],mu_sigma[1],target_value)
案例代码已上传:Github地址
参考资料:
[1] 《统计学习方法》
[2]: 朴素贝叶斯算法实现
Github地址https://github.com/Vambooo/lihang-dl
更多技术干货在公众号:深度学习学研社