《机器学习》第7章 贝叶斯分类
关键字
概率,是机器学习中的重要角色,那么何谓概率?抛硬币时正面朝上的概率为0.5,这句话又代表着何含义呢?对于概率的理解往往有两种不同的方式:
其一是所谓的频率论解释(Frequentist Interpretation)。这种观点中,概率代表着某个事件在较长范围内的出现频次。譬如这里的抛硬币问题可以阐述为,如果我们抛足够的次数,我们会观测到正面朝上的次数与反面朝上的次数基本相同。
另一种即时所谓的贝叶斯解释(Bayesian Interpretation),我们认为概率是用来衡量某件事的不确定性(uncertainty),其更多地与信息相关而不再是重复尝试的次数。用贝叶斯理论阐述抛硬币问题则为下一次抛硬币时正面朝上的可能性与反面朝上的可能性相差无几。贝叶斯解释的最大优势在于我们可以去为事件的不确定性建立具体的模型而不再依赖于多次试验得出的频次结果。譬如我们要去预测2020年世界杯的冠军,我们肯定不能让球队比赛很多次来观测频次计算概率,这件事只会发生零或一次,反正是无法重复发生的。基于贝叶斯理论我们便可以利用可观测到的数据推测该事件的结果概率,典型的应用是垃圾邮件过滤系统中,我们可以根据带标签的训练数据来对新的邮件进行判断。
朴素贝叶斯算法
1、简介
贝叶斯学派的思想可以概括为先验概率+数据=后验概率。也就是说我们在实际问题中需要得到的后验概率,可以通过先验概率和数据一起综合得到。一般来说先验概率就是我们对于数据所在领域的历史经验,但是这个经验常常难以量化或者模型化。虽然难以从严密的数学逻辑里推出贝叶斯学派的逻辑,但是在很多实际应用中,贝叶斯理论很好用,比如垃圾邮件分类,文本分类。
2、贝叶斯决策论
贝叶斯决策论(Bayesian decision theory)是概率框架下实施决策的基本方法。对分类任务来说,在所有相关概率都已知的理想情形下,贝叶斯决策论考虑如何基于这些概率和误判损失来选择最优的类别标记。
具体来说,若我们决策的目标是最小化分类错误率,贝叶斯最优分类器要对每个样本 x,选择能使后验概率 P( c | x )最大的类别 c 标记。在现实任务中后验概率通常难以直接获得。从这个角度来说,机器学习所要实现的是基于有限的训练样本集尽可能准确地估计出后验概率 P( c | x )。大体来说,主要有两种策略:给定x,可通过直接建模P( c | x )来预测c,这样得到的是“判别式模型”,例如,决策树、BP神经网络、支持向量机等等;也可先对联合概率分布P( x,c )建模,然后在由此获得P( c | x ),这样得到的是“生成式模型”。对于生成式模型来说,必然考虑
基于贝叶斯定理, P( c | x )可写为
P(c)是类先验概率, 表达了样本空间中各类样本所占的比例,根据大数定律,当训练集包含充足的独立同分布样本时,P(c) 可通过各类样本出现的频率来进行估计。P(x|c)是样本x相对于类标记c的类条件概率或称为似然,P(x)是用于归一化的证据因子。
这就将估计P(c|x)的问题转化为如何基于训练数据D估计先验P(c)和似然P(x|c)
因为对于类条件概率 P( x | c ) 来说,由于它涉及关于 x 所有属性的联合概率,直接根据样本出现的频率来估计将会遇到严重的困难。假如样本的d个属性都是二值的,则样本空间将有2的d次方种可能取值,在现实中,这个种类数往往大于训练样本,也就是说,很多样本取值在训练集中根本没有出现,直接使用频率来估计 P( x | c )显然不可行,因为“未被观测到”与“出现概率为零”通常是不同的。这可以通过极大似然估计来解决。
3、朴素贝叶斯分类器
基于贝叶斯公式来估计后验概率P( c | x )的主要困难在于:类条件概率P( x | c )是所有属性上的联合概率,难以从有限的训练样本直接估计而得。因此朴素贝叶斯分类器采用了“属性条件独立性假设”:对已知类别,假设所有属性相互独立。也就是说,假设每个属性独立的对分类结果发生影响。
基于属性独立性假设,后验概率P( c | x )可写为
显然朴素贝叶斯分类器的训练过程就是基于训练集D来估计类先验概率P( c ),并为每个属性估计条件概率P( x|c )。
由于对所有类别来说P( x )相同,因此贝叶斯判定准则有
下面是一个用西瓜数据集3.0训练朴素贝叶斯分类器,对测试例“测1”进行分类:
注意:实践中常通过取对数的方式来将“连乘”转化为“连加”以避免数值下溢。
4、拉普拉斯修正
若某个属性值在训练集中没有与某个类同时出现过,则基于式(7.17)进行概率估计,再根据式(7.15)进行判别将出现问题。例如在使用西瓜数据集3.0训练朴素贝叶斯分类器时,对一个“敲声=清脆”的测试例,有
由于式(7.15)的连乘式计算出的概率值为零,因此,无论该样本的属性如何,分类的结果都是“好瓜=否”,这明显不合理。
这时候就要进行“平滑”,常用“拉普拉斯修正”。式(7.16)和(7.17)分别修正为
N表示训练集D可能的类别数,Ni表示第i个属性可能的取值数
显然,拉普拉斯修正避免了因训练集不充分而导致概率估值为零的问题,并且在训练集变大时,修正过程所引入的先验的影响也会逐渐变得可忽略,使得估值渐趋向于实际概率值。
5、朴素贝叶斯的实现代码
引入了拉普拉斯修正,数据集用的是西瓜数据集3.0
import numpy as np
import pandas as pd
dataset = pd.read_csv('watermelon_3.csv', delimiter=",")
del dataset['编号']
print(dataset)
X = dataset.values[:, :-1]
m, n = np.shape(X)
for i in range(m):
X[i, n - 1] = round(X[i, n - 1], 3)
X[i, n - 2] = round(X[i, n - 2], 3)
y = dataset.values[:, -1]
columnName = dataset.columns
colIndex = {}
for i in range(len(columnName)):
colIndex[columnName[i]] = i
Pmap = {} # 函数P很耗时间,而且经常会求一样的东西,因此我加了个记忆化搜索,用map存一下,避免重复计算
kindsOfAttribute = {} # kindsOfAttribute[0] = 3,因为有3种不同的类型的"色泽"
for i in range(n):
kindsOfAttribute[i] = len(set(X[:, i]))
continuousPara = {} # 记忆一些参数的连续数据,以避免重复计算
goodList = []
badList = []
for i in range(len(y)):
if y[i] == '是':
goodList.append(i)
else:
badList.append(i)
import math
def P(colID, attribute, C): # P(colName=attribute|C) P(色泽=青绿|是)
if (colID, attribute, C) in Pmap:
return Pmap[(colID, attribute, C)]
curJudgeList = []
if C == '是':
curJudgeList = goodList
else:
curJudgeList = badList
ans = 0
if colID >= 6:
mean = 1
std = 1
if (colID, C) in continuousPara:
curPara = continuousPara[(colID, C)]
mean = curPara[0]
std = curPara[1]
else:
curData = X[curJudgeList, colID]
mean = curData.mean()
std = curData.std()
# print(mean,std)
continuousPara[(colID, C)] = (mean, std)
ans = 1 / (math.sqrt(math.pi * 2) * std) * math.exp((-(attribute - mean) ** 2) / (2 * std * std))
else:
for i in curJudgeList:
if X[i, colID] == attribute:
ans += 1
ans = (ans + 1) / (len(curJudgeList) + kindsOfAttribute[colID])
Pmap[(colID, attribute, C)] = ans
# print(ans)
return ans
def predictOne(single):
ansYes = math.log2((len(goodList) + 1) / (len(y) + 2))
ansNo = math.log2((len(badList) + 1) / (len(y) + 2))
for i in range(len(single)): # 书上是连乘,但在实践中要把“连乘”通过取对数的方式转化为“连加”以避免数值下溢
ansYes += math.log2(P(i, single[i], '是'))
ansNo += math.log2(P(i, single[i], '否'))
# print(ansYes,ansNo,math.pow(2,ansYes),math.pow(2,ansNo))
if ansYes > ansNo:
return '是'
else:
return '否'
def predictAll(iX):
predictY = []
for i in range(m):
predictY.append(predictOne(iX[i]))
return predictY
predictY = predictAll(X)
print(y)
print(np.array(predictAll(X)))
confusionMatrix = np.zeros((2, 2))
for i in range(len(y)):
if predictY[i] == y[i]:
if y[i] == '否':
confusionMatrix[0, 0] += 1
else:
confusionMatrix[1, 1] += 1
else:
if y[i] == '否':
confusionMatrix[0, 1] += 1
else:
confusionMatrix[1, 0] += 1
print(confusionMatrix)
输出结果:
输出结果说明:
[7,2]表示预测的结果有7个坏瓜预测成功,两个预测成好瓜
[1,7]表示预测的结果有一个好瓜预测成坏瓜,7个好瓜预测成好瓜
【问题】:逻辑回归与朴素贝叶斯的区别和联系?
这个问题分为三个问题进行回答。
什么是朴素贝叶斯分类?
通俗的介绍下如何通过条件概率来进行分类,假设我们看到了一个人的背影,想通过他背影的一些特征(数据)来判断这个人的性别(类别),假设其中涉及到的特征有: 是否是长发, 身高是否在170以上,腿细,是否穿裙子。当我们看到一个背影便会得到一个特征向量用来描述上述特征(1表示是,0表示否): ω=[0,1,1,0]
贝叶斯分类便是比较如下两个条件概率:
p(男生|ω),ωω 等于 [0,1,1,0] 的条件下此人是男生的概率
p(女生|ω),ωω 等于 [0,1,1,0] 的条件下此人是女生的概率
若p(男生|ω)>p(女生|ω), 则判定此人为男生, 否则为女生
那么p(男生|ω) 怎么求呢? 这就要上贝叶斯准则了
根据贝叶斯准则
image写成好理解些的便是:
如果特征之间都是相互独立的(条件独立性假设),那么便可以将上述条件概率改写成:
image这样我们就能计算当前这个背影属于男生和属于女生的条件概率了。
image什么是逻辑回归分类?
逻辑斯特回归实际上是用线性回归模型的预测结果去逼近后验概率的逻辑发生比,直接写出来就是:
image此处 w 为特征权重和,x 为特征值,可以是连续变量,也可以是离散变量。
逻辑回归与朴素贝叶斯的区别和联系?
我们看到朴素贝叶斯里有求和项,逻辑回归中也有求和项。我们如果采用二元离散特征 x\in{0,1} 带入到逻辑回归中:
image逻辑回归和朴素贝叶斯的表达式惊人地相似!
image与 w_i 对应,
image与 b 对应。
但二者还是有区别的,用两种方法求出来的权重是不一样。产生差别的原因在于朴素贝叶斯方法的条件独立假设。因为条件独立假设,朴素贝叶斯可以不使用梯度下降,而直接通过统计每个特征的逻辑发生比来当做权重。
而逻辑回归,条件独立假设并不成立,通过梯度下降法,可以得到特征之间的耦合信息,从而得到相应的权重。
完整代码参考码云
参考文献:
https://zhuanlan.zhihu.com/p/27906640
https://zhuanlan.zhihu.com/p/24602462 (基本概率的解释)
https://zhuanlan.zhihu.com/p/21571692
https://zhuanlan.zhihu.com/p/27906640(python的实现案例1)
https://zhuanlan.zhihu.com/p/28059124(python的实现案例2)