贝叶斯决策论是在概率框架下实施决策的一种基本方法。对分类问题而言,朴素贝叶斯理论在大数定律和属性条件独立性假设的基础上,根据先验概率和类条件概率计算后验概率,从而得到新样本属于某一类的概率。
基本原理
基于贝叶斯定理,后验概率\(P(c|\vec{x})\)可以通过先验概率和条件概率计算得到: \[
P(c|\vec{x}) = \frac{P(c)P(\vec{x})|c}{p(\vec{x})}
\] 其中\(P(c)\)是类先验概率(prior probability),\(P(\vec{x})|c)\)是样本\(\vec{x}\)相对于类标记\(c\)的类条件概率(class-conditional probability),或者“似然”(likelihood),\(P(\vec{x})\)是用于归一化的证据(evidence)因子。证据因子和类标记无关,因此估计后验概率P(c|)的问题转化为如何基于训练数据\(D\)来估计先验\(P(c)\)和似然\(P(\vec{x})|c)\)。
1. 类先验概率\(P(c)\)表达了样本空间中各类样本所占的比例。根据大数定律,当训练集包含充足的独立同分布样本时,\(P(c)\)可通过各类样本出现的频率来进行估计: \[
P(c) = \frac{|D_c|}{|D|}
\] 其中\(D_c\)表示训练集\(D\)中第\(c\)类样本组成的集合,运算\(|D|\)表示集合\(D\)的样本个数。 2. 类条件概率\(P(\vec{x})|c)\)指的是属性\(\vec{x}\)的联合概率,直接根据样本出现的频率来估计将会遇到严重的困难。比如,样本共有\(d\)个属性,每个属性都是二值的,那么样本空间将有\(2^d\)种可能的取值,在现实应用中,这个值往往远大于训练样本个数\(m\)。如果各个属性是相互独立的,那么需要的样本数就可以减少到\(2*d\)。 \[
P(x_i|c) = \frac{|D_{c,x_i}|}{|D_c|}
\] \[
P(\vec{x}|c) = \prod_{i=1}^{d} P(x_i|c)
\] 3. “未被观测到”不等于“出现概率为0”,为此,需要进行平滑处理,常用“拉普拉斯修正”, \[
P(c) = \frac{|D_c|+1}{|D|+N}
\] 其中\(N\)表示训练集\(D\)中的类别数; \[
P(x_i|c) = \frac{|D_{c,x_i}|+1}{|D_c|+N_i}
\] 其中\(N_i\)表示第\(i\)个属性的取值数。 4. 多次连乘小的数容易导致下溢,为了避免这个问题,取连乘结果的对数: \[
P(\vec{x}|c) = \sum_{i=1}^{d} log(P(x_i|c))
\]
最终的朴素贝叶斯(Naive Bayes)分类器的表达式为: \[ h_{nb}(\vec{x}) = argmax_{c \in K} \left[log(P(c)) + \sum_{i=1}^{d} log(P(x_i|c)) \right] \]
算法实现
数据准备
1 | def loadDataSet(): |
1 | listOPosts, listClasses = loadDataSet() |
['is', 'cute', 'food', 'him', 'so', 'posting', 'has', 'love', 'mr', 'dog', 'not', 'licks', 'take', 'I', 'stupid', 'to', 'my', 'help', 'flea', 'park', 'garbage', 'problem', 'maybe', 'how', 'please', 'steak', 'worthless', 'dalmation', 'quit', 'ate', 'stop', 'buying']
[0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0]
训练算法
1 | from numpy import * |
1 | listOPosts, listClasses = loadDataSet() |
[ 0.04166667 0.04166667 0. 0.08333333 0.04166667 0.
0.04166667 0.04166667 0.04166667 0.04166667 0. 0.04166667
0. 0.04166667 0. 0.04166667 0.125 0.04166667
0.04166667 0. 0. 0.04166667 0. 0.04166667
0.04166667 0.04166667 0. 0.04166667 0. 0.04166667
0.04166667 0. ]
[ 0. 0. 0.05263158 0.05263158 0. 0.05263158
0. 0. 0. 0.10526316 0.05263158 0.
0.05263158 0. 0.15789474 0.05263158 0. 0. 0.
0.05263158 0.05263158 0. 0.05263158 0. 0. 0.
0.10526316 0. 0.05263158 0. 0.05263158 0.05263158]
0.5
测试算法
1 | def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): |
实例:过滤垃圾邮件
1 | def textParse(bigString): |
1 | spamTest() |
the error rate is: 0.1
/home/seisinv/anaconda3/envs/tensorflow/lib/python3.5/re.py:203: FutureWarning: split() requires a non-empty pattern match.
return _compile(pattern, flags).split(string, maxsplit)
结论与讨论
结论
优点:在数据较少的情况下仍然有效,可以处理多分类问题。
缺点:对输入数据的准备方式较为敏感
讨论
- 对连续属性可考虑概率密度函数。比如第\(i\)个属性\(c_i\)连续变化,假定\(x_i\)满足正态分布,即\(p(x_i|c) \sim N(\mu_{c,i}, \sigma^2_{c,i})\),则可以通过最大似然法估计均值和方差,最终得到该属性的概率密度函数: \[ p(x_i|c) = \frac{1}{\sqrt{2\pi}\sigma} exp \left( -\frac{(x_i-\mu_{c,i})^2}{2\sigma^2_{c,i}} \right) \]
- 为了提高预测效率,对给定训练数据集,可将朴素贝叶斯分类器所涉及到的所有概率估值事先存储起来,在预测的时候只需要“查表”即可进行判断;若任务数据更替频繁,则可采用“懒惰学习”(lazy learning)方式,先不进行任何训练,待收到预测请求的时候,再根据当前数据集进行概率估计;若数据不断增加,则可在现有估值的基础上,仅对新增样本属性所涉及的概率估值进行计数修正即可,实现增量学习。
- 朴素贝叶斯假定属性各个属性是独立的,实际情况往往并不是这样,为此,学者们提出半朴素贝叶斯分类器,基本思想是考虑一部分属性间的相互依赖关系。有“独依赖估计”(One-Dependent Estimator, ODE), SPODE(Super-Parent ODE), TAN(Tree Augmented naive Bayes), AODE(Averaged One-Dependent Esimator),贝叶斯网(Bayesian Network)或信念网(Belief network)。
- 朴素贝叶斯分类器假设所有属性变量值都可以被观测到,即训练数据是完整的,但是现实应用中往往会遇到“不完整”的训练样本,此时需要采用EM(Expectation Maximization)算法分两步估计隐变量(latent variable)和模型参数。
参考资料
- Peter Harrington, Machine learning in action, Manning Publications, 2012
- 周志华,机器学习,清华大学出版社, 2016