机器学习最易懂之贝叶斯模型详解与python实现

0、预备知识

0.1 先验概率、条件概率、后验概率

  条件概率: 就是事件A在事件B发生的条件下发生的概率,表示为 P ( A B ) P(A|B) ,读作“在B发生的条件下A发生的概率。

  先验概率: 在贝叶斯统计中,某一不确定量 p p 的先验概率分布是指:在考虑"观测数据"前,也就是没有样本集的情况下,能表达 p p 不确定性的概率分布。先验概率是指根据以往的经验和分析得到的概率,往往作为“由因求果”问题中的“因”出现。

  后验概率: 在贝叶斯统计中,一个随机事件或者一个不确定事件的后验概率是在考虑和给出相关证据或数据后所得到的条件概率。同样,后验概率分布是一个未知量(视为随机变量)基于试验和调查后得到的概率分布。“后验”在本文中代表考虑了被测试事件的相关证据。

  现有两个随机变量 A , B A,B ,其中 A A 表示西瓜的颜色, B B 表示西瓜的好坏:

条件概率:

  • 在瓜颜色是青绿的情况下,瓜是好瓜的概率,记为 P ( B = A = 绿 ) P(B=好瓜|A=青绿)
  • 在瓜是好瓜的情况下,瓜的颜色是青绿色的概率,记为 P ( A = 绿 B = ) P(A=青绿|B=好瓜)

先验概率:

  • 瓜的颜色是青绿的概率,即 P ( A = 绿 ) P(A=青绿) ,称作是 A A 的先验概率,因为它不用考虑任何B方面的因素;
  • 瓜是好瓜的概率,即 P ( B = ) P(B=好瓜) ,称作是 B B 的先验概率,因为它不用考虑任何 A A 方面的因素。

后验概率:

  • P ( A = 绿 B = ) P(A=青绿|B=好瓜) 是在瓜是好瓜的情况下,瓜的颜色是青绿色的概率,也是由于得知 B B 的取值后知道 A A 的概率,所以是 A A 的先验概率;
  • P ( B = A = 绿 ) P(B=好瓜|A=青绿) 是 在瓜颜色是青绿的情况下,瓜是好瓜的概率,也是由于得知 A A 的取值后知道 B B 的概率,所以是 B B 的先验概率

0.2 贝叶斯公式

  根据条件概率公式:

P ( X Y ) = P ( X Y ) P ( Y ) = P ( Y X ) P ( X ) P(XY)=P(X|Y)P(Y)=P(Y|X)P(X)

可得:

P ( Y X ) = P ( X Y ) P ( Y ) P ( X ) P(Y|X)=\frac{P(X|Y)P(Y)}{P(X)}

其中 P ( Y ) P(Y) Y Y “先验概率”; P ( X Y ) P(X|Y) 是样本 X X 对于类标记为 Y Y 的类条件概率,或称为“似然”; P ( X ) P(X) 是用于归一化的“证据”因子,上式即为贝叶斯公式。

可以将其看做 P ( ) = P ( , ) P ( ) = P ( ) P ( ) P ( ) P(类别|特征) = \frac{P(特征,类别)}{P(特征)} = \frac{P(类别) P(特征|类别)}{P(特征)}

  对类条件概率 P ( X Y ) P(X|Y) 来说,直接根据样本出现的频率来估计将会遇到严重的困难,所以引入了极大似然估计

0.3 极大似然估计

  估计类条件概率有一种常用的策略就是先假定其具有某种确定的概率分布形式,再基于训练样本对概率分布的参数进行估计。假设 P ( x c ) P(x|c) 具有某种确定的形式并且被参数 θ c θ_c 唯一确定,则我们的任务就是利用训练结D估计参数 θ c θ_c 。为了明确期间,我们将 P ( x c ) P(x|c) 记为 p ( x θ c ) p(x|θc) .
  举个通俗的例子:假设一个袋子装有白球与红球,比例未知,现在抽取10次(每次抽完都放回,保证事件独立性),假设抽到了7次白球和3次红球,在此数据样本条件下,可以采用最大似然估计法求解袋子中白球的比例(最大似然估计是一种“模型已定,参数未知”的方法)。当然,这种数据情况下很明显,白球的比例是70%,但如何通过理论的方法得到这个答案呢?一些复杂的条件下,是很难通过直观的方式获得答案的,这时候理论分析就尤为重要了,这也是学者们为何要提出最大似然估计的原因。我们可以定义从袋子中抽取白球和红球的概率如下:

f ( x 1 , x 2 θ ) = f ( x 1 θ ) × f ( x 2 θ ) f(x_1,x_2|\theta)=f(x_1|\theta)\times f(x_2|\theta)

x1为第一次采样,x2为第二次采样,f为模型, theta为模型参数
其中 θ \theta 是未知的,因此,我们定义似然 L L 为:

L ( θ x 1 , x 2 ) = f ( x 1 , x 2 θ ) = i = 1 2 f ( x i θ ) L(\theta|x_1,x_2)=f(x_1,x_2|\theta)=\prod_{i=1}^2f(x_i|\theta)

L为似然的符号。两边取ln,取ln是为了将右边的乘号变为加号,方便求导。

l n L ( θ x 1 , x 2 ) = l n i = 1 2 f ( x i θ ) = i = 1 2 l n f ( x i θ ) lnL(\theta|x_1,x_2)=ln\prod_{i=1}^2f(x_i|\theta)=\sum_{i=1}^2lnf(x_i|\theta)

两边取ln的结果,左边的通常称之为对数似然。

^ = 1 2 l n L ( θ x 1 , x 2 ) \hat\ell=\frac{1}{2} lnL(\theta|x_1,x_2)

最大似然估计的过程,就是找一个合适的theta,使得平均对数似然的值为最大。因此,可以得到以下公式:

θ ^ m l e = arg max θ Θ ^ ( θ x 1 , x 2 ) \hat\theta_{mle}=\arg \max_{\theta\in\Theta}\hat\ell(\theta|x_1,x_2)

这里讨论的是2次采样的情况,当然也可以拓展到多次采样的情况:

θ ^ m l e = arg max θ Θ ^ ( θ x 1 , x 2 , . . . , x n ) \hat\theta_{mle}=\arg \max_{\theta\in\Theta}\hat\ell(\theta|x_1,x_2,...,x_n)

我们定义M为模型(也就是之前公式中的f),表示抽到白球的概率为theta,而抽到红球的概率为(1-theta),因此10次抽取抽到白球7次的概率可以表示为:

P ( x 1 , x 2 , . . . , x 10 M ) = P ( x 1 M ) × P ( x 2 M ) × . . . × P ( x 10 M ) = θ 7 ( 1 θ ) 3 P(x_1,x_2,...,x_{10}|M)=P(x_1|M)\times P(x_2|M)\times ... \times P(x_{10}|M)=\theta^7(1-\theta)^3

将其描述为平均似然可得:

^ = 1 10 l n P ( x 1 , x 2 , . . . , x 10 M ) = 1 10 l n [ θ 7 ( 1 θ ) 3 ] \hat\ell=\frac{1}{10}lnP(x_1,x_2,...,x_{10}|M)=\frac{1}{10}ln[\theta^7(1-\theta)^3]

10次抽取抽到白球7次的平均对数似然,抽球的情况比较简单,可以直接用平均似然来求解
那么最大似然就是找到一个合适的 θ \theta ,获得最大的平均似然。因此我们可以对平均似然的公式对 θ \theta 求导,并另导数为0。

^ ( θ ) = 7 θ 6 ( 1 θ ) 3 3 θ 7 ( 1 θ ) 2 = 0 θ = 0.7 \hat\ell'(\theta)=7\theta^6(1-\theta)^3-3\theta^7(1-\theta)^2=0\Rightarrow \theta=0.7

由此可得,当抽取白球的概率为0.7时,最可能产生10次抽取抽到白球7次的事件。

以上就用到了最大似然估计的思想

令Dc表示训练集D中第c类样本组成的集合,假设这些集合是独立同分布的,则对参数θcθc对于数据集Dc的似然是:

P ( D c θ c ) = P ( x θ c ) P(D_c|\theta_c) = \prod P(\mathbf{x}|\theta_c)

θ c θ_c 进行激发似然估计买就是去寻找能最大化似然函数的参数值 θ c θ_c .直观上,极大似然估计是在试图在 θ c θ_c 的所有可能的去职中,找到一个能使数据出现最大“可能性”的最大值。
上面的式子中的连乘操作容易造成下溢,通常使用对数似然:

L ( θ c ) = log P ( D c θ c ) = x D c log P ( x θ c ) L(\theta_c) = \log P(D_c| \theta_c) = \sum_{x\in D_c} \log P(x|\theta_c)

此时,参数 θ c θ_c 的极大似然估计 θ c ^ \hat{\theta_c} 为:

θ c ^ = a r g m a x θ c L L ( θ c ) \hat{\theta_c} = argmax_{\theta_c} LL(\theta_c)

例如,在连续属性的情形下,假设概率密度函数 p ( x c ) N ( μ c , σ 2 ) p(x|c) \sim \mathcal{N}(\mu_c , \sigma^2) ,则参数 μ c μ_c σ 2 σ_2 的极大似然估计为:

μ c ^ = 1 D c x D c x \hat{\mu_c} = \frac{1}{|D_c|} \sum_{x\in D_c} x

σ c ^ 2 = 1 D c x D c ( x μ c ^ ) ( x μ c ^ T ) \hat{\sigma_c}^2 = \frac{1}{|D_c|} \sum_{x\in D_c} (x-\hat{\mu_c} )(x-\hat{\mu_c} ^T)

也就是说通过极大似然发得到的额正态分布均值就是样本均值,方差就是 ( x μ c ^ ) ( x μ c ^ T ) (x-\hat{\mu_c} )(x-\hat{\mu_c} ^T) 的均值。这显然是一个符合直觉的结果,在离散属性情形下,也可以通过类似的方法来估计类条件概率。
需要注意的是这种方法虽然能够使类条件概率估计变得简单,但是估计结果准确性严重依赖于所假设的概率分布形式是否符合潜在的真实数据分布。在显示生活中往往需要应用任务本身的经验知识,“猜测”则会导致误导性的结果。

贝叶斯分类器的训练过程就是参数估计。总结最大似然法估计参数的过程,一般分为以下四个步骤:

  • 1.写出似然函数;
  • 2.对似然函数取对数,并整理;
  • 3.求导数,令偏导数为0,得到似然方程组;
  • 4.解似然方程组,得到所有参数即为所求。

0.4 生成模型与判别模型

  监督学习的任务就是从数据中学习一个模型(也叫分类器),应用这一模型,对给定的输入X预测相应的输出Y。这个模型的一般形式为决策函数 Y = f ( X ) Y=f(X) 或者条件概率分布 P ( Y X ) P(Y|X) 。监督学习方法可以分为生成方法和判别方法,所学到的模型分别称为生成模型和判别模型。

  生成模型:在概率统计理论中, 生成模型是指能够随机生成观测数据的模型,尤其是在给定某些隐含参数的条件下。在机器学习中,生成模型根据样本学习联合概率分布 P ( X , Y ) P(X,Y) ,然后求出条件概率 P ( Y X ) P(Y|X) 的分布。生成模型认为样本数据集是由联合分布 P ( X , Y ) P(X,Y) 独立同分布产生的。

  我们已知某一个样本具有某种特征 X X ,现在要确定它输入哪个类 Y Y ,而自然的因果关系是,样本之所以具有这种特征 X X ,是因为它属于某一类。例如,我们要根据体重,脚的尺寸这两个特征 X X 来判断一个人是男性还是女性,我们都知道,男性的体重总体来说比女性大,脚的尺寸也更大,因此从逻辑上来说,是因为一个人是男性,因此才有这种大的体重和脚尺寸。而在分类任务中要做的却相反,是给了你这样个特征的样本,让你反推这人是男性还是女性。这就需要我们完成因果转换,贝叶斯公式恰巧就提供了因果转化的方法。我们要完成的是由果(样本特征)推断因(种类),而在训练时我们建立的是因到果的模型及 P ( X Y ) P(X|Y) ,即男性和女性的体重、脚尺寸分别服从的概率分布。

  生成模型的典型代表是朴素贝叶斯和隐马尔科夫模型,其他还有高斯混合模型和其他混合模型、随机上下文无关文法、AODE分类器、潜在狄利克雷分配模型、受限玻尔兹曼机。。

  总结起来,生成模型对联合概率 P ( X , Y ) ) P(X,Y)) 建模,根据它,我们可以得到 Y Y 的后验概率 P ( Y X ) P(Y|X) 。事实上,这种做法不仅仅局限于分类问题,如果将 X X 看做可以观测的变量, Y Y 看做不可观测到的变量,只要具有这种特征的问题(例如隐马尔科夫模型),我们都可以建立生成模型。

  举例:利用生成模型来判断一个西瓜是好瓜还是坏瓜。根据好瓜的特征首先学习出一个好瓜的模型(其实并不是学习一个模型而是在学习的时候对不同类的样本单独考虑),然后根据坏瓜的特征学习得到一个坏瓜的模型,然后从需要预测的瓜中提取特征,放到生成好的好瓜的模型中看概率是多少,在放到生产的坏瓜模型中看概率是多少,哪个概率大就预测其为哪个。

  判别模型: 在机器学习领域判别模型是一种对未知数据 Y Y 与已知数据 X X 之间关系进行建模的方法。已知输入变量 X X ,判别模型通过构建条件概率分布 P ( Y X ) P(Y|X) 预测 Y Y 。常见的基于判别模型算法有逻辑回归、线性回归、支持向量机、提升方法、条件随机场、人工神经网络、随机森林、感知器。

  举例:要确定一个瓜是好瓜还是坏瓜,用判别模型的方法是从历史数据中学习到模型,然后通过提取这个瓜的特征来预测出这只瓜是好瓜的概率,是坏瓜的概率。

  生成模型是所有变量的全概率模型,而判别模型是在给定观测变量值前提下目标变量条件概率模型。因此生成模型能够用于模拟(即生成)模型中任意变量的分布情况,而判别模型只能根据观测变量得到目标变量的采样。生成模型直接学习联合概率分布 P ( X , Y ) P(X,Y) 从统计的角度表示数据的分布情况,能够反映同类数据本身的相似度,但它不关心到底划分各个类列的那个分类边界在哪。判别模型直接学习条件概率 P ( Y X ) P(Y|X) 不能反映训练数据本身的特性,但它能寻找不同类别之间的最优分类面,反映各类数据之间的差异。直接面对预测,往往学习的准确率更高。

生成算法尝试去找到底这个数据是怎么生成的(产生的),然后再对一个数据进行分类。基于你的生成假设,那么那个类别最有可能产生这个数据,这个数据就属于那个类别。判别模型不关心数据是怎么生成的,它只关心数据类别之间的差别,然后用差别来简单对给定的一个数据进行分类

1、朴素贝叶斯模型

  基于贝叶斯公式来估计后验概率 P ( Y X ) P(Y|X) 主要困难在于类条件概率 P ( X Y ) P(X|Y) 是所有属性上的联合概率,难以从有限的训练样本直接估计而得。基于有限训练样本直接计算联合概率 P ( X , Y ) P(X,Y) ,在计算上将会遭遇组合爆炸问题;在数据上将会遭遇样本稀疏问题;属性越多,问题越严重。为了避开这个障碍,朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法。

1.1 朴素贝叶斯的符号说明

  啥也不说,先来定义一系列符号。

  • 输入空间 X R n \mathcal{X}\in R^n n n 维向量的集合
  • 输出空间 Y = { c 1 , c 2 , . . . , c K } \mathcal{Y} =\{c_1,c_2,...,c_K\} c k c_k 表示类别,总数 K K
  • 输入为 d d 维特征向量 x X \boldsymbol{x} \in \mathcal{X}
  • x ( i ) x^{(i)} 表示样本的第 i i 维特征
  • x i x_i 表示样本数据集中的第 i i 个样本
  • 输出为类别的标记 y Y y\in \mathcal{Y}
  • X X 是定义在输入空间上的随机变量
  • 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)} ,共 N N 个样本。

1.2 朴素贝叶斯的特征条件独立假设

  朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法,特征条件独立性假设是指:对类别已知(这就是条件独立中的条件) Y = c k Y=c_k ,假设所有特征相互独立 x 1 , x 2 , . . . x d x_1,x_2,...x_d 相互独立),也就是假设每个特征对分类结果产生的影响相互独立。在西瓜数据集上就可以认为{色泽 根蒂 敲声 纹理 脐部 触感}这些属性对西瓜是好还是坏的结果所产生的影响相互独立,彼此互相不影响。
条件独立性假设,可以表示为:

P ( X = x Y = c k ) = P ( X ( 1 ) = x ( 1 ) , X ( 1 ) = x ( 1 ) , . . . , X ( d ) = x ( d ) Y = c k ) = P ( X ( 1 ) = x ( 1 ) Y = c k ) P ( X ( 2 ) = x ( 2 ) Y = c k ) . . . P ( X ( d ) = x ( d ) Y = c k ) = i = 1 d P ( X ( i ) = x ( i ) Y = c k ) \begin{aligned} P(X=\boldsymbol{x}|Y=c_k)&= P(X^{(1)}=x^{(1)},X^{(1)}=x^{(1)},...,X^{(d)}=x^{(d)}|Y=c_k)\\ &=P(X^{(1)}=x^{(1)}|Y=c_k)P(X^{(2)}=x^{(2)}|Y=c_k)...P(X^{(d)}=x^{(d)}|Y=c_k)\\ &= \prod_{i=1}^d P(X^{(i)}=x^{(i)}|Y=c_k) \end{aligned}

其中, d d 为特征的数目, x ( i ) x^{(i)} X X 在第 i i 个属性上取值。

这个假设太过强硬,太naive,这也是朴素贝叶斯名字的来源。

1.3 朴素贝叶斯模型推导

  朴素贝叶斯是一个生成模型,所以是对联合概率分布 P ( X , Y ) P(X,Y) 进行建模,根据条件概率公式可知:

P ( X , Y ) = P ( Y ) P ( X Y ) = P ( X = x Y = c k ) P ( Y = c k ) P(X,Y)=P(Y)P(X|Y)=P(X=\boldsymbol{x}|Y=c_k)P(Y=c_k)

可以看出,朴素贝叶斯需要学习 P ( X = x Y = c k ) P(X=\boldsymbol{x}|Y=c_k) P ( Y = c k ) P(Y=c_k)
对于 P ( Y = c k ) P(Y=c_k) 的学习,使用极大似然,假设 P ( Y = c k ) = θ P(Y=c_k)=\theta ,则似然函数:

L ( θ ) = P ( T θ ) = i N P ( Y i θ ) \begin{aligned} L(\theta)&=P(T|\theta)=\prod_i^NP(Y_i|\theta) \end{aligned}

假设属于 c k c_k 的样本数量为 N k N_k :

L ( θ ) = i N P ( Y i θ ) = i N k P ( Y i = c k θ ) j N N k P ( Y i c k θ ) = θ N k ( 1 θ ) N N k \begin{aligned} L(\theta)&=\prod_i^NP(Y_i|\theta)\\ &=\prod_i^{N_k}P(Y_i=c_k|\theta)\prod_j^{N-N_k}P(Y_i \neq c_k|\theta)\\ &=\theta^{N_k}(1-\theta)^{N-N_k} \end{aligned}

取对数:

log L ( θ ) = log ( θ N k ( 1 θ ) N N k ) = N k log θ + ( N N k ) log ( 1 θ ) \begin{aligned} \log L(\theta)&=\log (\theta^{N_k}(1-\theta)^{N-N_k})\\ &=N_k\log\theta+(N-N_k)\log(1-\theta) \end{aligned}

求导:

d log L ( θ ) d θ = N k 1 θ ( N N k ) 1 1 θ = N k N θ θ ( 1 θ ) \begin{aligned} \frac{d\log L(\theta)}{d\theta}&=N_k\frac{1}{\theta}-(N-N_k)\frac{1}{1-\theta}\\ &=\frac{N_k-N\theta}{\theta(1-\theta)} \end{aligned}

令导数为0:,可得 θ = N k N \theta=\frac{N_k}{N}
所以:

P ( Y = c k ) = N k N P(Y=c_k)=\frac{N_k}{N}

P ( Y = c k ) P(Y=c_k) 的学习是很简单的,对 P ( X = x Y = c k ) P(X=\boldsymbol{x}|Y=c_k) 的学习就比较困难了:

P ( X = x Y = c k ) = P ( X = P ( X ( 1 ) = x ( 1 ) , X ( 1 ) = x ( 1 ) , . . . , X ( d ) = x ( d ) Y = c k ) P(X=\boldsymbol{x}|Y=c_k)=P(X= P(X^{(1)}=x^{(1)},X^{(1)}=x^{(1)},...,X^{(d)}=x^{(d)}|Y=c_k)

若是直接对上式进行学习,假设第 j j 个特征有 S j S_j 个值,则总参数为 K j d S j K\prod\limits_j^dS_j ,很多时候这个值已经超过了样本数据集的数量,模型学习是不可能的。为了解决这个问题,就用了特征条件独立这个假设

P ( X = x Y = c k ) = P ( X = P ( X ( 1 ) = x ( 1 ) , X ( 1 ) = x ( 1 ) , . . . , X ( d ) = x ( d ) Y = c k ) = i = 1 d P ( X ( i ) = x ( i ) Y = c k ) \begin{aligned} P(X=\boldsymbol{x}|Y=c_k)&=P(X= P(X^{(1)}=x^{(1)},X^{(1)}=x^{(1)},...,X^{(d)}=x^{(d)}|Y=c_k)\\ &=\prod_{i=1}^d P(X^{(i)}=x^{(i)}|Y=c_k) \end{aligned}

和上文对 P ( Y = c k ) P(Y=c_k) 的学习一样,使用极大似然来学习:

P ( X ( j ) = a j l Y = c k ) = N j l N k P(X^{(j)}=a_{jl}|Y=c_k)=\frac{N_{jl}}{N_k}

其中, x ( j ) x^{(j)} 的取值有 { a j 1 , a j 2 , . . . , a j S j } \{a_{j1},a_{j2},...,a_{jS_j}\} N k N_k 是分类为 c k c_k 的样本数, N j l N_{jl} 是分类为 c k c_k 且第 j j 个特征取值为 a j l a_{jl} 的样本数。

朴素贝叶斯学习完成就可以得到朴素贝叶斯模型,那么来了一个新的样本,怎么判断它的类别呢?

  首先,对于给定的一个新样本 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( d ) ) T \boldsymbol{x}=(x^{(1)},x^{(2)},...,x^{(d)})^T ,计算 Y Y 的后验概率:

P ( Y = c k X = x ) = P ( Y = c k ) P ( X = x Y = c k ) P ( X = x ) = P ( Y = c k ) P ( X = x Y = c k ) k P ( Y = c k ) P ( X = x Y = c k ) = P ( Y = c k ) j = 1 d P ( X ( j ) = x ( j ) Y = c k ) k P ( Y = c k ) j = 1 d P ( X ( j ) = x ( j ) Y = c k ) \begin{aligned}P(Y=c_k|X=\boldsymbol{x})&=\frac{P(Y=c_k)P(X=\boldsymbol{x}|Y=c_k)}{P(X=\boldsymbol{x})}\\ &=\frac{P(Y=c_k)P(X=\boldsymbol{x}|Y=c_k)}{\sum\limits_kP(Y=c_k)P(X=\boldsymbol{x}|Y=c_k)}\\ &=\frac{P(Y=c_k)\prod_{j=1}^dP(X^{(j)}=x^{(j)}|Y=c_k)}{\sum\limits_kP(Y=c_k)\prod_{j=1}^dP(X^{(j)}=x^{(j)}|Y=c_k)} \end{aligned}

y ^ = arg max c k P ( Y = c k X = x ) = arg max c k P ( Y = c k ) j = 1 d P ( X ( j ) = x ( j ) Y = c k ) k P ( Y = c k ) j = 1 d P ( X ( j ) = x ( j ) Y = c k ) = arg max c k P ( Y = c k ) j = 1 d P ( X ( j ) = x ( j ) Y = c k ) \begin{aligned} \hat y& = \arg\max_{c_k}P(Y=c_k|X=\boldsymbol{x})\\ &=\arg\max_{c_k} \frac{P(Y=c_k)\prod_{j=1}^dP(X^{(j)}=x^{(j)}|Y=c_k)}{\sum\limits_kP(Y=c_k)\prod_{j=1}^dP(X^{(j)}=x^{(j)}|Y=c_k)}\\ &=\arg\max_{c_k} P(Y=c_k)\prod_{j=1}^dP(X^{(j)}=x^{(j)}|Y=c_k) \end{aligned}

计算了所有分类的后验概率 P ( Y = c k X = x ) P(Y=c_k|X=\boldsymbol{x}) ,找到最大的一个后验概率就是样本的分类,即:

y = arg max c k P ( Y = c k X = x ) y^*=\arg\max_{c_k}P(Y=c_k|X=\boldsymbol{x})

为什么要是用最大后验概率作为朴素贝叶斯的预测呢?答案就是贝叶斯决策理论。

1.4 贝叶斯决策理论——为什么是最大后验概率?

  贝叶斯决策论是概率框架下实施决策的基本方法,对分类任务来说,在所有相关概率都已知的理想情形下,贝叶斯决策论考虑如何基于这些概率和误判损失来选择最优的类别标记。

   假设有N种可能标记, λ i j λ_{ij} 是将类 c j c_j 误分类为 c i c_i 所产生的损失,基于后验概率 P ( c i x ) P(c_i | x) 可以获得样本 x x 分类为 c i c_i 所产生的期望损失 ,即在样本x上的条件风险:

R ( c i x ) = j = 1 N λ i j P ( c j x ) R(c_i|\mathbf{x}) = \sum_{j=1}^N \lambda_{ij} P(c_j|\mathbf{x})

我们的任务是寻找一个判定准则 h : X Y h:X→Y 以最小化总体风险

R ( h ) = E x [ R ( c i ( x ) ) ] = E x [ R ( h ( x ) ( x ) ) ] R(h)=\mathbb{E}_x [R(c_i|\mathbf(x))]= \mathbb{E}_x [R(h\mathbf(x) | \mathbf(x))]

显然,对每个样本 x x ,若h能最小化条件风险 R ( h ( ( x ) ) ( x ) ) R(h((x))|(x)) ,则总体风险 R ( h ) R(h) 也将被最小化。这就产生了贝叶斯判定准则:为最小化总体风险,只需要在每个样本上选择那个能使条件风险R(c|x)最小的类别标记,即:

h ( x ) = arg min c Y R ( c x ) h^* (x) = \arg\min_{c\in \mathcal{Y}} R(c|\mathbf{x})

此时, h h 称作贝叶斯最优分类器,与之对应的总体风险 R ( h ) R(h) 称为贝叶斯风险, 1 R ( h ) 1-R(h*) 反映了分类器能达到的最好性能,即机器学习所产生的模型精度的上限。

朴素贝叶斯分类器的目标是最小化分类错误率(对应0/1损失),则 λ i j λ_{ij} 可以用0/1损失改写,记 L ( c i , h ( x ) ) L(c_i,h(x))

L ( c i , h ( x ) ) = { 1 , h ( x ) c i 0 , h ( x ) = c i L(c_i,h(x)) =\begin{cases}1, h(x)\neq c_i\\0,h(x) = c_i\end{cases}

所有分类的损失:

R ( h ) = i = 1 K L ( c i , h ( x ) ) R(h)=\sum_{i=1}^KL(c_i,h(x))

最小化损失:

arg min c i Y i = 1 K L ( c i , h ( x ) ) = arg min c i Y i = 1 K P ( Y c i X = x ) = arg min c i Y i = 1 K [ 1 P ( Y = c i X = x ) ] \begin{aligned} \arg\min_{c_i\in \mathcal{Y}}\sum_{i=1}^KL(c_i,h(x))&=\arg\min_{c_i\in \mathcal{Y}}\sum_{i=1}^KP(Y\neq c_i|X=x)\\ &=\arg\min_{c_i\in \mathcal{Y}}\sum_{i=1}^K[1-P(Y=c_i|X=x)]\\ \end{aligned}

最小化 1 P ( Y = c i X = x ) 1-P(Y=c_i|X=x) ,就是最大化 P ( Y = c i X = x ) P(Y=c_i|X=x) ,则:

arg min c i Y i = 1 K L ( c i , h ( x ) ) = arg max c i Y i = 1 K P ( Y = c i X = x ) \begin{aligned} \arg\min_{c_i\in \mathcal{Y}}\sum_{i=1}^KL(c_i,h(x))&=\arg\max_{c_i\in \mathcal{Y}}\sum_{i=1}^KP(Y=c_i|X=x) \end{aligned}

这就是后验概率最大。

h ( x ) = arg max c i Y P ( c i x ) h^*(x) = \arg\max_{c_i\in \mathcal{Y}} P(c_i|\mathbf{x})

即对每个样本 x x ,选择能使后验概率 P ( c x ) P(c|x) 最大的类别标识。

获得后验概率的两种方法:

  1. 判别式模型:给定 x x ,可以通过直接建模 P ( c x ) P(c|x) 来预测 c c
  2. 生成模型:先对联合分布 p ( x , c ) p(x, c) 建模,然后再有此获得 P ( c x ) P(c|x)

朴素贝叶斯采用的是生成模型。

3、零概率问题如何解决?

零概率问题,就是在计算实例的概率时,如果某个量x,在观察样本库(训练集)中没有出现过,会导致整个实例的概率结果是0.

在实际的模型训练过程中,可能会出现零概率问题(因为先验概率和反条件概率是根据训练样本算的,但训练样本数量不是无限的,所以可能出现有的情况在实际中存在,但在训练样本中没有,导致为0的概率值,影响后面后验概率的计算),即便可以继续增加训练数据量,但对于有些问题来说,数据怎么增多也是不够的。这时我们说模型是不平滑的,我们要使之平滑,一种方法就是将训练(学习)的方法换成贝叶斯估计。

现在看一个示例,及 P ( = = ) = 8 0 = 0 P(敲声=清脆|好瓜=是)=\frac{8}{0}=0
不论样本的其他属性如何,分类结果都会为“好瓜=否”,这样显然不太合理。

朴素贝叶斯算法的先天缺陷:其他属性携带的信息被训练集中某个分类下未出现的属性值“抹去”,造成预测出来的概率绝对为0。为了拟补这一缺陷,前辈们引入了拉普拉斯平滑的方法:对先验概率的分子(划分的计数)加1,分母加上类别数;对条件概率分子加1,分母加上对应特征的可能取值数量。这样在解决零概率问题的同时,也保证了概率和依然为1:
P ( c ) = D c D P ( c ) = D c + 1 D + N P(c) = \frac{{|{D_c}|}}{{|D|}} \to P(c) = \frac{{|{D_c}| + 1}}{{|D| + N}}
P ( x i c ) = D x i c D c P ( x i c ) = D x i c + 1 D c + N i P({x_i}|c) = \frac{{|{D_{{x_i}|c}}|}}{{|{D_c}|}} \to P({x_i}|c) = \frac{{|{D_{{x_i}|c}}| + 1}}{{|{D_c}| + {N_i}}}

其中,N表示数据集中分类标签, N i N_i 表示第 i i 个属性的取值类别数,|D|样本容量, D c |D_c| 表示类别c的记录数量, D x i c {|{D_{{x_i}|c}}|} 表示类别c中第i个属性取值为 x i x_i 的记录数量。

将这两个式子应用到上面的计算过程中,就可以弥补朴素贝叶斯算法的这一缺陷问题。

用西瓜的数据来看,当我们计算

P(好瓜=是)时,样本有17个,所以|D| = 17,N,好瓜标签可以分为{是,否}两类,所以N=2,(好瓜=是)的样本个数有8个,所以这里 D c |D_c| =8。

综上,根据拉普拉斯平滑后有 P ( = ) = D c + 1 D + N = 8 + 1 17 + 2 P(好瓜=是) = \frac{{|{D_c}| + 1}}{{|D| + N}} = \frac{{|{8}| + 1}}{{|17| + 2}}
P(色泽=青绿|好瓜=是)时,色泽青绿的样本有8个,所以|D_c| = 8,N,色泽标签可以分为{青绿,浅白,乌黑}三类,所以N=3,(好瓜=是)的样本个数有3个,所以这里 D c , x i |D_{c,x_i}| =3。
综上,根据拉普拉斯平滑后有 P = 绿 = = D x i c + 1 D c + N i = 3 + 1 8 + 3 P(色泽=青绿|好瓜=是)= \frac{{|{D_{{x_i}|c}}| + 1}}{{|{D_c}| + {N_i}}}=\frac{{|{3}}| + 1}{{|{8}| + {3}}}
同理,分析可知,之前不合理的 P ( = = ) = 8 0 = 0 P(敲声=清脆|好瓜=是)=\frac{8}{0}=0 在进行拉普拉斯平滑后为 P ( = = ) = D x i c + 1 D c + N i = 0 + 1 8 + 3 P(敲声=清脆|好瓜=是)= \frac{{|{D_{{x_i}|c}}| + 1}}{{|{D_c}| + {N_i}}}=\frac{{|{0}}| + 1}{{|{8}| + {3}}} 显然结果不是0,使结果变得合理。

4、sklearn实现朴素贝叶斯

4.1 加载鸢尾花数据集并分类

from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_iris
import pandas as pd
from sklearn.model_selection import train_test_split
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2)
clf = GaussianNB().fit(X_train, y_train)
print ("Classifier Score:", clf.score(X_test, y_test))
Classifier Score: 0.9666666666666667

4.2 sklearn参数详解

  高斯朴素贝叶斯算法是假设特征的可能性(即概率)为高斯分布。
class sklearn.naive_bayes.GaussianNB(priors=None)
参数:

  • priors:先验概率大小,如果没有给定,模型则根据样本数据自己计算(利用极大似然法)。
  • var_smoothing:可选参数,所有特征的最大方差

属性:

  • class_prior_:每个样本的概率
  • class_count:每个类别的样本数量
  • classes_:分类器已知的标签类型
  • theta_:每个类别中每个特征的均值
  • sigma_:每个类别中每个特征的方差
  • epsilon_:方差的绝对加值方法

朴素贝叶斯和其他模型一样的方法:

  • fit(X,Y):在数据集(X,Y)上拟合模型。
  • get_params():获取模型参数。
  • predict(X):对数据集X进行预测。
  • predict_log_proba(X):对数据集X预测,得到每个类别的概率对数值。
  • predict_proba(X):对数据集X预测,得到每个类别的概率。
  • score(X,Y):得到模型在数据集(X,Y)的得分情况。
    这里采用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_{y_{k}}^{2}}}exp( -\frac{(x_{i}-\mu_{y_{k}})^2} {2\sigma_{y_{k}}^{2}} )
    数学期望: μ \mu
    方差: σ 2 = 1 n i n ( x i x ) 2 \sigma ^2=\frac{1}{n}\sum_i^n(x_i-\overline x)^2

4.3 自己实现朴素贝叶斯

import math
class NaiveBayes:
    def __init__(self):
        self.model = None

    # 数学期望
    @staticmethod
    def mean(X):
        """计算均值
        Param: X : list or np.ndarray
        
        Return:
            avg : float
        
        """
        avg = 0.0
        # ========= show me your code ==================
        avg = sum(X) / float(len(X))
        # ========= show me your code ==================
        return avg

    # 标准差(方差)
    def stdev(self, X):
        """计算标准差
        Param: X : list or np.ndarray
        
        Return:
            res : float
        
        """
        res = 0.0
        # ========= show me your code ==================
        avg = self.mean(X)
        res = math.sqrt(sum([pow(x - avg, 2) for x in X]) / float(len(X)))
        # ========= show me your code ==================
        return res
        
    # 概率密度函数
    def gaussian_probability(self, x, mean, stdev):
        """根据均值和标注差计算x符号该高斯分布的概率
        Parameters:
        ----------
        x : 输入
        mean : 均值
        stdev : 标准差
        
        Return:
        
        res : float, x符合的概率值
            
        """
        res = 0.0
        # ========= show me your code ==================
        exponent = math.exp(-(math.pow(x - mean, 2) /
                              (2 * math.pow(stdev, 2))))
        res = (1 / (math.sqrt(2 * math.pi) * stdev)) * exponent
        # ========= show me your code ==================
        
        return res
        
    # 处理X_train
    def summarize(self, train_data):
        """计算每个类目下对应数据的均值和标准差
        Param: train_data : list
        
        Return : [mean, stdev]
        """
        summaries = [0.0, 0.0]
        # ========= show me your code ==================
        summaries = [(self.mean(i), self.stdev(i)) for i in zip(*train_data)]
        
        # ========= show me your code ==================
        return summaries

    # 分类别求出数学期望和标准差
    def fit(self, X, y):
        labels = list(set(y))
        data = {label: [] for label in labels}
        for f, label in zip(X, y):
            data[label].append(f)
        self.model = {
            label: self.summarize(value) for label, value in data.items()
        }
        return 'gaussianNB train done!'

    # 计算概率
    def calculate_probabilities(self, input_data):
        """计算数据在各个高斯分布下的概率
        Paramter:
        input_data : 输入数据
        
        Return:
        probabilities : {label : p}
        """
        # summaries:{0.0: [(5.0, 0.37),(3.42, 0.40)], 1.0: [(5.8, 0.449),(2.7, 0.27)]}
        # input_data:[1.1, 2.2]
        probabilities = {}
        # ========= show me your code ==================
        for label, value in self.model.items():
            probabilities[label] = 1
            for i in range(len(value)):
                mean, stdev = value[i]
                probabilities[label] *= self.gaussian_probability(
                    input_data[i], mean, stdev)
        # ========= show me your code ==================
        return probabilities

    # 类别
    def predict(self, X_test):
        # {0.0: 2.9680340789325763e-27, 1.0: 3.5749783019849535e-26}
        label = sorted(self.calculate_probabilities(X_test).items(), key=lambda x: x[-1])[-1][0]
        return label
    # 计算得分
    def score(self, X_test, y_test):
        right = 0
        for X, y in zip(X_test, y_test):
            label = self.predict(X)
            if label == y:
                right += 1

        return right / float(len(X_test))
model = NaiveBayes()
model.fit(X_train, y_train)
(array([4.7, 3.2, 1.6, 0.2]),)
(array([4.3, 3. , 1.1, 0.1]),)
(array([5.1, 3.8, 1.6, 0.2]),)
(array([4.8, 3. , 1.4, 0.3]),)
(array([5.1, 3.7, 1.5, 0.4]),)
(array([4.7, 3.2, 1.3, 0.2]),)
(array([4.4, 2.9, 1.4, 0.2]),)
(array([5.2, 3.4, 1.4, 0.2]),)
(array([5.1, 3.4, 1.5, 0.2]),)
(array([4.6, 3.4, 1.4, 0.3]),)
(array([4.6, 3.6, 1. , 0.2]),)
(array([5. , 3.5, 1.6, 0.6]),)
(array([4.9, 3.1, 1.5, 0.1]),)
(array([5.7, 3.8, 1.7, 0.3]),)
(array([4.6, 3.1, 1.5, 0.2]),)
(array([4.9, 3.6, 1.4, 0.1]),)
(array([4.8, 3.4, 1.9, 0.2]),)
(array([5.1, 3.5, 1.4, 0.3]),)
(array([5.1, 3.8, 1.5, 0.3]),)
(array([5.3, 3.7, 1.5, 0.2]),)
(array([5.4, 3.9, 1.7, 0.4]),)
(array([5. , 3.4, 1.6, 0.4]),)
(array([5.4, 3.7, 1.5, 0.2]),)
(array([5.1, 3.5, 1.4, 0.2]),)
(array([4.9, 3. , 1.4, 0.2]),)
(array([5.7, 4.4, 1.5, 0.4]),)
(array([4.8, 3.4, 1.6, 0.2]),)
(array([4.4, 3.2, 1.3, 0.2]),)
(array([5. , 3.3, 1.4, 0.2]),)
(array([4.6, 3.2, 1.4, 0.2]),)
(array([5.4, 3.4, 1.5, 0.4]),)
(array([5.1, 3.8, 1.9, 0.4]),)
(array([4.5, 2.3, 1.3, 0.3]),)
(array([5. , 3.5, 1.3, 0.3]),)
(array([4.4, 3. , 1.3, 0.2]),)
(array([5.2, 3.5, 1.5, 0.2]),)
(array([6. , 2.7, 5.1, 1.6]),)
(array([6.1, 2.8, 4.7, 1.2]),)
(array([6.6, 2.9, 4.6, 1.3]),)
(array([6.4, 2.9, 4.3, 1.3]),)
(array([5.8, 2.6, 4. , 1.2]),)
(array([5.5, 2.5, 4. , 1.3]),)
(array([5.5, 2.4, 3.8, 1.1]),)
(array([5.6, 2.5, 3.9, 1.1]),)
(array([5.4, 3. , 4.5, 1.5]),)
(array([6.4, 3.2, 4.5, 1.5]),)
(array([5.7, 2.8, 4.1, 1.3]),)
(array([6. , 3.4, 4.5, 1.6]),)
(array([5.9, 3.2, 4.8, 1.8]),)
(array([6.6, 3. , 4.4, 1.4]),)
(array([5.6, 3. , 4.5, 1.5]),)
(array([5.8, 2.7, 3.9, 1.2]),)
(array([4.9, 2.4, 3.3, 1. ]),)
(array([5.9, 3. , 4.2, 1.5]),)
(array([6. , 2.9, 4.5, 1.5]),)
(array([5.7, 3. , 4.2, 1.2]),)
(array([7. , 3.2, 4.7, 1.4]),)
(array([6.3, 2.5, 4.9, 1.5]),)
(array([5.5, 2.6, 4.4, 1.2]),)
(array([6.1, 2.8, 4. , 1.3]),)
(array([5. , 2. , 3.5, 1. ]),)
(array([6.3, 2.3, 4.4, 1.3]),)
(array([5.5, 2.3, 4. , 1.3]),)
(array([5.6, 2.7, 4.2, 1.3]),)
(array([5.6, 2.9, 3.6, 1.3]),)
(array([5.7, 2.8, 4.5, 1.3]),)
(array([6.2, 2.9, 4.3, 1.3]),)
(array([6.1, 3. , 4.6, 1.4]),)
(array([5.5, 2.4, 3.7, 1. ]),)
(array([6.7, 3. , 5. , 1.7]),)
(array([5.8, 2.7, 4.1, 1. ]),)
(array([6.5, 2.8, 4.6, 1.5]),)
(array([6. , 2.2, 4. , 1. ]),)
(array([6.9, 3.1, 4.9, 1.5]),)
(array([5.6, 3. , 4.1, 1.3]),)
(array([6.8, 2.8, 4.8, 1.4]),)
(array([5. , 2.3, 3.3, 1. ]),)
(array([6.3, 3.3, 4.7, 1.6]),)
(array([6.2, 2.2, 4.5, 1.5]),)
(array([5.7, 2.6, 3.5, 1. ]),)
(array([5.1, 2.5, 3. , 1.1]),)
(array([6.3, 2.7, 4.9, 1.8]),)
(array([6.7, 2.5, 5.8, 1.8]),)
(array([6.2, 3.4, 5.4, 2.3]),)
(array([5.8, 2.8, 5.1, 2.4]),)
(array([4.9, 2.5, 4.5, 1.7]),)
(array([6.7, 3.3, 5.7, 2.1]),)
(array([6.3, 2.9, 5.6, 1.8]),)
(array([6.9, 3.1, 5.1, 2.3]),)
(array([6.4, 3.1, 5.5, 1.8]),)
(array([6.1, 3. , 4.9, 1.8]),)
(array([6.5, 3. , 5.2, 2. ]),)
(array([6.3, 3.4, 5.6, 2.4]),)
(array([7.2, 3.2, 6. , 1.8]),)
(array([7.7, 3. , 6.1, 2.3]),)
(array([6.4, 2.7, 5.3, 1.9]),)
(array([7.2, 3.6, 6.1, 2.5]),)
(array([6.4, 3.2, 5.3, 2.3]),)
(array([6. , 3. , 4.8, 1.8]),)
(array([5.8, 2.7, 5.1, 1.9]),)
(array([6.7, 3.3, 5.7, 2.5]),)
(array([6.5, 3. , 5.5, 1.8]),)
(array([5.7, 2.5, 5. , 2. ]),)
(array([5.9, 3. , 5.1, 1.8]),)
(array([6.4, 2.8, 5.6, 2.2]),)
(array([7.7, 2.6, 6.9, 2.3]),)
(array([6.3, 2.5, 5. , 1.9]),)
(array([6.8, 3.2, 5.9, 2.3]),)
(array([6.5, 3.2, 5.1, 2. ]),)
(array([6. , 2.2, 5. , 1.5]),)
(array([7.7, 2.8, 6.7, 2. ]),)
(array([6.1, 2.6, 5.6, 1.4]),)
(array([6.9, 3.1, 5.4, 2.1]),)
(array([6.7, 3. , 5.2, 2.3]),)
(array([6.2, 2.8, 4.8, 1.8]),)
(array([7.2, 3. , 5.8, 1.6]),)
(array([6.9, 3.2, 5.7, 2.3]),)
(array([7.6, 3. , 6.6, 2.1]),)
(array([5.6, 2.8, 4.9, 2. ]),)
(array([6.3, 3.3, 6. , 2.5]),)





'gaussianNB train done!'
print(model.predict([4.4,  3.2,  1.3,  0.2]))
0
model.score(X_test, y_test)
0.9666666666666667

5、优缺点

优点

  1. 朴素贝叶斯模型有稳定的分类效率。
  2. 对小规模的数据表现很好,能处理多分类任务,适合增量式训练,尤其是数据量超出内存时,可以一批批的去增量训练。
  3. 对缺失数据不太敏感,算法也比较简单,常用于文本分类。

缺点:

  1. 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
  2. 需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。
  3. 由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。
  4. 对输入数据的表达形式很敏感。

参考文献

西瓜书
https://samanthachen.github.io/2016/08/05/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0_%E5%91%A8%E5%BF%97%E5%8D%8E_%E7%AC%94%E8%AE%B07/

https://www.jianshu.com/p/f1d3906e4a3e

https://zhuanlan.zhihu.com/p/66117273

https://zhuanlan.zhihu.com/p/39780650

https://blog.csdn.net/zrh_CSDN/article/details/81007851

原创文章 58 获赞 7 访问量 6196

猜你喜欢

转载自blog.csdn.net/Elenstone/article/details/105677886
今日推荐