统计学习方法笔记(三)-朴素贝叶斯原理及python实现

朴素贝叶斯

    • 条件概率
    • 特征条件独立假设
    • 朴素贝叶分类器
    • 朴素贝叶斯分类算法原理
      • 学习与分类算法
        • 朴素贝叶斯算法原理
    • 模型
      • 多项式模型
      • 高斯模型
      • 伯努利模型
    • 多项式模型的朴素贝叶斯分类器实现代码
    • 高斯模型的朴素贝叶斯分类器实现代码
    • 代码案例地址

条件概率

朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法。

要明白什么是贝叶斯定理,则先复习一下几个术语:条件概率、特征条件独立假设.

什么是条件概率?

P ( A ∣ B ) P(A|B) P(AB)表示事件B已经发生的前提下,事件A发生的概率,也叫做事件B发生下事件A的条件概率。上述用数学语言描述为:
P ( A ∣ B ) = P ( A B ) P ( B ) {P(A|B)=\frac{P(AB)}{P(B)}} P(AB)=P(B)P(AB)

贝叶斯定理是基于条件概率,通过 P ( A ∣ B ) P(A|B) P(AB)来求解 P ( B ∣ A ) P(B|A) P(BA) P ( B ∣ A ) = P ( A ∣ B ) P ( B ) P ( A ) P(B|A)=\frac{P(A|B)P(B)}{P(A)} P(BA)=P(A)P(AB)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(BiA)=j=1nP(Bj)P(ABj)P(Bi)P(ABi)

特征条件独立假设

上面介绍了条件概率,那什么是特征条件独立假设?

给定训练集 ( X , Y ) (X,Y) (X,Y), x x x是集合 X X X中的样本( x ∈ X x \in X xX), 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=c1X=x),P(Y=c2X=x),...,P(Y=ckX=x)中最大的概率,即求后验概率最大输出: arg ⁡ max ⁡ c k P ( Y = c k ∣ X = x ) {\arg \max_{c_k} P(Y=c_k|X=x)} argmaxckP(Y=ckX=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=ckX=x),也就是要求出: P ( Y = c k ∣ X = x ) {P(Y=c_k|X=x)} P(Y=ckX=x).想要求出 P ( Y = c k ∣ X = x ) {P(Y=c_k|X=x)} P(Y=ckX=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=ckX=x)=kP(X=xY=ck)P(Y=ck)P(X=xY=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=xY=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 Kj=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=xY=ck)=P(X(1)=x(1),...,X(n)=x(n))=j=1nP(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=ckX=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)=argckmaxkP(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)jP(X(j)=x(j)Y=ck)

上述的表述是从头到尾推导出朴素贝叶斯分类器的过程.

朴素贝叶斯分类算法原理

若对推导过程不感兴趣,可跳过上述推导,直接看下面朴素贝叶斯分类算法:

基本方法:

设输入空间 X ⊆ R n \mathcal{X}\subseteq \mathcal{R}^n XRn 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} xX作为输入,类标记 y ∈ Y y\in \mathcal{Y} yY作为输出。

训练集 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)=Ni=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)=ajlY=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=1nP(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=1nP(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),常见有三种模型:
多项式模型、高斯模型、伯努利模型。

模型

多项式模型

  • 多项式模型
    当特征是离散时,使用多项式模型,多项式模型在计算先验概率 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 ) = N c k + α N + k α {P(Y=c_k)=\frac{N_{c_k}+\alpha}{N+k\alpha}} P(Y=ck)=N+kαNck+α

其中 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(xiyk)=2πσyk2 1exp(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)=1Y=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)=1P(X(j)=1Y=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
更多技术干货在公众号:深度学习学研社
统计学习方法笔记(三)-朴素贝叶斯原理及python实现_第1张图片

你可能感兴趣的:(机器学习算法系列实现)