1. 朴素贝叶斯介绍
朴素贝叶斯法是基于贝叶斯定理()与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入x, 利用贝叶斯定理求出后验概率最大的输出y。
2. 朴素贝叶斯特点
优点:在数据较少的情况下仍然有效,可以处理多类别问题
缺点:对于输入数据的准备方式较为敏感。
使用数据类型:标称型数据
3. 朴素贝叶斯法的学习与分类
3.1.1基本方法
设输入空间为n维向量的集合,输出空间为类标记集合
。输入特征为特征向量
,输出为类标记
。
是定义在输入空间
上面的随机变量,
是定义在输出空间
上面的随机变量。
是x和y的联合概率分布,训练集
由独立同分布产生。
朴素贝叶斯法通过训练数据集学习联合概率分布。具体地,学习以下先验概率分布和条件概率分布。先验概率分布:
条件概率分布
于是就学到了联合概率分布
条件概率有指数级数量的参数,其估计实际是不可行的。事实上,假设,假设可取值有
个,
,Y可取值有K个,那么参数个数为
.
由
可取值有
个,可知
个取值;
个取值
......
个取值
又由于
参数个数为
关于朴素贝叶斯的条件独立性假设的理解:
朴素贝叶斯分类时,对于给定的输入的,通过学习到的模型计算后验概率 分布
,将后验概率最大的类作为
的类输出。后验概率计算根据贝叶斯定理可知:
推导过程如下:
由贝叶斯定理得
根据全概率公式可知
所以可知
将式(3.3)带入式(3.4)得
这是朴素贝叶斯分类的基本公式,于是有朴素贝叶斯分类器可表示为
又因为,在式中(3.7)分母对所有的都是相同的,所以
4.1.2后验概率最大化的含义
假设选择0-1损失函数:
式中是分类决策函数。这时,期望风险函数为
期望是对联合分布取的,由此条件期望为
具体这一步是怎么来的呢,如下所示:
要是期望风险最小,也就是这个图中的积分最小,那么对于任意的一个X=x在P(X=x)为常数条件下内层积分最小,即期望风险最小等价于条件期望最小。
而为了使得期望风险最小化,只需对X=x逐个极小化,则有:
由期望风险最小化就可以得到后验概率最大化准则:
也就是朴素贝叶斯所采用的原理。
4. 朴素贝叶斯法的参数估计
4.1 极大似然估计
在朴素贝叶斯学习中,学习意味着估计和
。可以应用极大似然估计法估计相应的概率。先验概率
的极大似然估计是
设第j个特征可能取值的集合为
,条件概率
的极大似然估计是
式中,是第i个样本的第j个特征;
是第j个特征可能取的第
个值;
为指示函数。
4.2 学习与分类算法
输入:训练数据
其中,
是第i个样本的第j个特征,
,
是第j个特征可能取的第
个值,
;实例
;
输出:实例的分类。
(1)计算先验概率及条件概率
先验概率:
条件概率:
(2)对于给定的实例,计算
(3)确定实例的类
例1.试由表1的训练数据学习朴素贝叶斯分类器并确定的类标记
,表中
为特征,取值的集合分别为
为类标记,
表1 训练数据
解答如下:
代码如下:
#!/usr/bin/env python3
#coding=utf-8
import numpy as np
class NaiveBeyes(object):
#获取训练数据
def getTrainSet(self):
dataSet=np.array([[1,'S'],[1,'M'],[1,'M'],[1,'S'],[1,'S'],[2,'S'],[2,'M'],[2,'M'],[2,'L'],[2,'L'],[3,'L'], [3,'M'],[3,'M'],[3,'L'],[3,'L']])
labels=[-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]
return dataSet,labels
def classify(self,trainData,labels,features):
#先计算先验概率
#用于存放不同类别的先验概率
labelProb={}
for label in labels:
labelProb[label]=labels.count(label)/float(len(labels))
#计算特征和标签同时发生的概率
# 用来存放特征和标签同时发生时的概率
p_xy = {}
for tagvalue in labelProb.keys():
#获取Labels中出现tagvalue值的所有数值的下标索引
tagvalueIndex=[index for index,label in enumerate(labels) if label==tagvalue]
for i in range(len(features)):
#获取features中的值在训练集中出现的所有下标索引
x_index=[index for index,feature in enumerate(trainData[:,i]) if feature==features[i]]
xy_count=len(set(tagvalueIndex) & set(x_index)) #如果它们索引相同,说明它们特征和标签同时发生
key=str(features[i])+'*'+str(tagvalue)
p_xy[key]=xy_count/float(len(labels))
#计算条件概率
#创建空字典,并将条件概率存入其中
prob={}
for tagvalue in labelProb.keys():
for feature in features:
pkey=str(feature)+'|'+str(tagvalue)
prob[pkey]=p_xy[str(feature)+'*'+str(tagvalue)]/float(labelProb[tagvalue])
#计算[2,S]所属类别
#创建空字典用于存放[2,S]所属不同类别的概率
resultProb={}
for tagvalue in labelProb.keys():
resultProb[tagvalue]=labelProb[tagvalue]
for x in features:
resultProb[tagvalue]=resultProb[tagvalue]*prob[str(x)+'|'+str(tagvalue)]
#max(dict,key=dict.get)表示获取字典中值最大所对应的键
result_feature=max(resultProb,key=resultProb.get)
return result_feature
if __name__=='__main__':
NB=NaiveBeyes()
#训练数据
trainData,labels=NB.getTrainSet()
features=np.array([2,'S'])
result=NB.classify(trainData,labels,features)
print("[2,'S']的类别标记为:{}".format(result))
4.3贝叶斯估计
用极大似然估计可能会出现所要估计的概率值为0的情况,这时会影响到后验概率的计算结果,使分类产生偏差。解决这一问题的方法是采用朴素贝叶斯估计。具体的是如下所示:
式中。等价于在随机变量各个取值的频数上赋值一个正数
。当
时就是极大似然估计。常取
,这时称为拉普拉斯平滑。显然,对于任何
,有
表明式(4.3)确实是一个概率分布,同时,先验概率的贝叶斯估计为
这里的K应该是指类别数
例2. 同例1,按照拉普拉斯平滑估计概率,即取。
解答过程如下:
代码如下:
#!/usr/bin/env python3
#coding=utf-8
import numpy as np
class NaiveBeyes(object):
#初始化K,j,λ值
def __init__(self):
self.D=1 #表示λ=1
self.K=2
self.S=3
#获取训练数据
def getTrainSet(self):
dataSet=np.array([[1,'S'],[1,'M'],[1,'M'],[1,'S'],[1,'S'],[2,'S'],[2,'M'],[2,'M'],[2,'L'],[2,'L'],[3,'L'],[3,'M'],[3,'M'],[3,'L'],[3,'L']])
labels=[-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]
return dataSet,labels
def classify(self,trainData,labels,features):
#先计算先验概率
#用于存放不同类别的先验概率
labelProb={}
for label in labels:
labelProb[label]=(labels.count(label)+self.D)/float(len(labels)+self.K*self.D)
#计算条件概率
# 用来存放特征和标签同时发生时的概率
prob = {}
for tagvalue in labelProb.keys():
#获取labels中出现tagvalue值的所有数值的下标索引
tagvalueIndex=[index for index,label in enumerate(labels) if label==tagvalue]
#获取labels中每个标签出现的个数
tagvalueCount=labels.count(tagvalue)
for i in range(len(features)):
#获取features中的值在训练集中出现的所有下标索引
x_index=[index for index,feature in enumerate(trainData[:,i]) if feature==features[i]]
xy_count=len(set(tagvalueIndex) & set(x_index)) #如果它们索引相同,说明它们特征和标签同时发生
key=str(features[i])+'|'+str(tagvalue)
prob[key]=(xy_count+self.D)/float(tagvalueCount+self.S*self.D)
#计算[2,S]所属类别
#创建空字典用于存放[2,S]所属不同类别的概率
resultProb={}
for tagvalue in labelProb.keys():
resultProb[tagvalue]=labelProb[tagvalue]
for x in features:
resultProb[tagvalue]=resultProb[tagvalue]*prob[str(x)+'|'+str(tagvalue)]
#max(dict,key=dict.get)表示获取字典中值最大所对应的键
result_feature=max(resultProb,key=resultProb.get)
return result_feature
if __name__=='__main__':
NB=NaiveBeyes()
#训练数据
trainData,labels=NB.getTrainSet()
features=np.array([2,'S'])
result=NB.classify(trainData,labels,features)
print("[2,'S']的类别标记为:{}".format(result))