机器学习8-贝叶斯分类器
师兄博客原文地址 https://blog.csdn.net/LogHouse/article/details/97376419
@
智能控制与优化决策课题组制作。
对应周志华《机器学习》第七章内容。
一些问题
- 1、解释先验概率、后验概率、全概率公式、条件概率公式,结合实例说明贝叶斯公式,如何理解贝叶斯定理?
- ①先验概率:
在贝叶斯分类中,先验概率指训练数据中某种条件(原因)\(c\)的初始概率,通常依据先验知识获取,记为\(P(c)\)。
②后验概率:
后验概率指在已知某种现象(结果)\(x\)的情况下,推测其原因为\(c\)的概率,记为\(P(c|x)\)。
③全概率:
\(x\)为一个现象(结果);\(c_1,c_2,\cdots,c_i,\cdots,c_n\)为一个事件组,满足\(\bigcup\limits^n_{i=1}c_i=\Omega\),且其中事件两两互斥,即任取\(c_i\cap c_j=\varnothing\),其中\(\Omega\)为整个样本空间。
则有:
④条件概率:
即在出现某种条件\(c\)的情况下,发生事件(结果)\(x\)的概率,记为\(P(x|c)\)。
⑤贝叶斯公式:
用于已知发生某事件(结果)\(x\)的情况下,推测其产生的原因为\(c_i\in\bm C\)的概率,\(\bm C\)为所有原因的集合。则有:
- 2、结合实例说明朴素贝叶斯分类器是如何对测试样本进行分类的?并归纳总结算法步骤。
- ①统计先验概率
一种方法为,通过统计给定训练集中的样本中各个条件(原因)出现的概率作为先验概率。在分类问题中,可以认为各种不同的类别为原因,记作\(c_i\in\bm{C}\),其产生的不同表现——样本的属性值\(\bm{x_i}=\{x_{i,1},x_{i,2},\cdots,x_{i,m}\}\)为现象(结果)。
②统计每个特征的条件概率
对于一个样本,它有很多不同的属性值,也就是有多种表现,记为\(\bm{x_i}=\{x_{i,1},x_{i,2},\cdots,x_{i,m}\}\)。
我们需要统计不同表现在不同原因下出现的概率\(P(x_{i,j}|c_k)\)。
③计算后验概率
我们的目标是分类,即在已知结果的情况下,推测其最可能的原因。故,我们需要找到的是\(\max P(c_k|\bm x_i)\)。
由于朴素贝叶斯假设所有属性都是相互独立的,可以根据贝叶斯公式可以计算出结果为\(\bm x_i\)的情况下其原因为\(c_k\)的概率为:
其中\(l\)为总的类别数目,而:
④找到该结果下最可能的原因
\(\max P(c_k|\bm x_i)\)。
- 3、分别说明如何用极大似然估计和贝叶斯估计进行朴素贝叶斯的参数估计。
- ①极大似然估计:
极大似然估计是根据数据采样来估计概率分布参数的经典方法。
给定数据集\(X\),假定其概率密度函数为\(f(\cdot)\),以及一个分布的参数\(\theta\),从数据集中抽出样本\(x_1,x_2,\cdots,x_n\),那么通过参数\(\theta\)的模型\(f(\cdot)\)产生上面样本的概率为:
最大似然估计会寻找关于\(\theta\)的最可能的值,即在所有可能的\(\theta\)取值中,寻找一个值使这个采样的“可能性”最大化!
因为是“模型已定,参数未知”,此时我们是根据样本采样\(x_1,x_2,\cdots,x_n\)取估计参数\(\theta\),定义似然函数为:
实际使用中,因为\(f(x_i|θ)\)一般比较小,而且\(n\)往往会比较大,连乘容易造成浮点运算下溢。所以一般我们用对数似然函数:
则最终的\(\theta\)的估计值为:
②贝叶斯估计:
统计学里有两个大的流派,一个是频率派,一个是贝叶斯派。时至今日,这两派还未就各自的观点达成统一。前面提到的最大似然估计就是频率派的典型思路,接下来再看看贝叶斯派的思路。
两个随机变量x,y的联合概率p(x,y)的乘法公式:
如果x,y是独立随机变量,上面的式子可以表示为:
那么条件概率就可以表示为:
对于一个完备事件组y1,y2,⋯,yn,可以使用全概率公式:
其中\(\sum^n_{i=1}p(y_i)=1\)。
由以上这些,可以得出贝叶斯公式:
其中,\(p(y_i|x)\)是后验概率。\(p(x|y_i)\)是条件概率,或者说似然概率,这个概率一般都可以通过历史数据统计得出。而\(p(y_i)\)是先验概率,一般也是根据历史数据统计得出或者认为给定的,贝叶斯里的先验概率,就是指\(p(y_i)\)。对于\(p(x)\),我们前面提到可以用全概率公式计算得出,但是在贝叶斯公式里面我们一般不在意这个概率,因为我们往往只需要求出最大后验概率而不需要求出最大后验的具体值
Bayes公式比MLE公式里就多了一项\(p(yi)p(yi)\),而条件概率或者说似然概率的表达式是一致的。从数学表达式的角度来说,两者最大的区别就在这里:贝叶斯估计引入了先验概率,通过先验概率与似然概率来求解后验概率。而最大似然估计是直接通过最大化似然概率来求解得出的。换句话说,最大似然估计没有考虑模型本身的概率,或者说认为模型出现的概率都相等。而贝叶斯估计将模型出现的概率用先验概率的方式在计算过程中有所体现。
编程实现朴素贝叶斯
载入西瓜数据集
训练集
# 不同的特征及其对应可能的特征值
Dkeys = {
'色泽': ['青绿', '乌黑', '浅白'],
'根蒂': ['蜷缩', '硬挺', '稍蜷'],
'敲声': ['清脆', '沉闷', '浊响'],
'纹理': ['稍糊', '模糊', '清晰'],
'脐部': ['凹陷', '稍凹', '平坦'],
'触感': ['软粘', '硬滑'],
}
Class, labels = '好瓜', ['是', '否']
# 读取数据集
def loadTest():
array = ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.697, 0.460, '']
wmData = {a: b for a, b in zip(dataSet.columns, array)}
return wmData
# 统计数据
def calculateD(dataSet):
D = []
for label in labels:
temp = dataSet.loc[dataSet[Class] == label]
D.append(temp)
return D
这里按照西瓜书的例子,测试样例如下
def testData():
array = ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.697, 0.460, '']
testData= {a: b for a, b in zip(dataSet.columns, array)}
return testData
贝叶斯分类
参考上面第二个问题,主要需要实现4个功能
统计不同类的先验概率
def calculatePc(Dc, D):
D_size = D.shape[0]
Dc_size = Dc.shape[0]
N = len(labels)
return (Dc_size+1) / (D_size+N)
统计每个特征的条件概率
def calculatePx_c(key, value, Dc):
Dc_size = Dc.shape[0]
Dcx_size = Dc[key].value_counts()[value]
Ni = len(Dkeys[key])
return (Dcx_size + 1) / (Dc_size + Ni)
计算后验概率
def calculatePc_x(key, value, Dc):
mean, var = Dc[key].mean(), Dc[key].var()
exponent = math.exp(-(math.pow(value - mean, 2) / (2 * var)))
return (1 / (math.sqrt(2 * math.pi * var)) * exponent)
def calculate_probability(label, Dc, dataSet, data_test):
prob = calculatePc(Dc, dataSet)
for key in Dc.columns[:-1]:
value = data_test[key]
if key in Dkeys:
prob *= calculatePx_c(key, value, Dc)
else:
prob *= calculatePc_x(key, value, Dc)
return prob
计算测试样本(结果)最可能的类别(原因)
def predict(dataSet, data_test):
# mu, sigma = dataSet.mean(), dataSet.var()
Dcs = calculateD(dataSet)
max_prob = -1
for label, Dc in zip(labels, Dcs):
prob = calculate_probability(label, Dc, dataSet, data_test)
if prob > max_prob:
best_label = label
max_prob = prob
print(label, prob)
return best_label
主函数
import math
import numpy as np
import pandas as pd
if __name__ == '__main__':
# 读取数据
filename = 'data_3.txt'
dataSet = loadData(filename)
data_test = load_data_test()
label = predict(dataSet, data_test)
print('预测结果:', label)