本文从贝叶斯与频率概率的对比入手理解贝叶斯决策的思维方式。通过两个实例理解贝叶斯的思想与流程,然后梳理了朴素贝叶斯分类器的算法流程,最后从零开始实现了朴素分类器的算法。
1.起源、提出与贝叶斯公式
贝叶斯派别主要是与古典统计学相比较区分的。
古典统计学基于大数定理,将一件事件经过大量重复实验得到的频率作为事件发生的概率,如常说的掷一枚硬币,正面朝上的概率为0.5。但,如果事先知道硬币的密度分布并不均匀,那此时的概率是不是就不为0.5呢?这种不同于“非黑即白”的思考方式,就是贝叶斯式的思考方式。
贝叶斯除了提出上述思考方式之外,还特别提出了举世闻名的贝叶斯定理。贝叶斯公式:
$$ P(B_i|A) = \frac{P(B_i)P(A|B_i)}{\sum_{j=1}^nP(B_j)P(A|B_j)}$$
这里通过全概率公式,我们可以将上式等同于
$$ P(B|A) = \frac{P(B)P(A|B)}{P(A)} = P(B)\frac{P(A|B)}{P(A)}$$
右边的分式中,分子的P(A)称为先验概率,是B事件未发生前,对A事件概率的判断;P(A|B)即是在B事件发生之后,对A事件发生的后验概率。这整个分式我们也称之为‘’可能性函数(Likelyhood)‘’,这是一个调整因子,对A事件未发生之前B的概率进行调整,以得到A事件发生的前提下B事件发生的后验概率P(B|A)。
以一句话与一张图概括:贝叶斯定理是一种在已知其他概率的情况下求概率的方法。
2.以实例感受贝叶斯决策:癌症病人计算 问题
有一家医院为了研究癌症的诊断,对一大批人作了一次普查,给每人打了试验针,然后进行统计,得到如下统计数字:
- 这批人中,每1000人有5个癌症病人;
- 这批人中,每100个正常人有1人对试验的反应为阳性
- 这批人中,每100个癌症病人有95入对试验的反应为阳性。
通过普查统计,该医院可开展癌症诊断。现在某人试验结果为阳性,诊断结果是什么?
(全是公式实在不好打,就用自己笔记代替啦)
上述例子是基于最小错误率贝叶斯决策,即哪类的概率大判断为哪类,也是我们常见的分类决策方法。但是将正常人错判为癌症病人,与将癌症病人错判为正常人的损失是不一样的。将正常人错判为癌症病人,会给他带来短期的精神负担,造成一定的损失,这个损失比较小。如果把癌症病人错判为正常人,致使患者失去挽救的机会,这个损失就大了。这两种不同的错判所造成损失的程度是有显著差别的。
所以,在决策时还要考虑到各种错判所造成的不同损失,由此提出了最小风险贝叶斯决策。
我们将$I_{ij}$记为将j类误判为i类所造成的损失。此处类别为2,如将样本x判为癌症病人$c_1$造成损失的数学期望为:
$R_1=I_{11}P(C_1|X)+I_{12}P(C_2|X)$
同理,将样本x判为癌症病人$c_2$造成损失的数学期望为
$R_2=I_{21}P(C_1|X)+I_{22}P(C_2|X)$
选择最小风险作为决策准则,若$R_1<R_2$,则样本X$\epsilon R_1$,否则X$\epsilon R_2$
3.以实例感受贝叶斯修正先验概率:狼来了
给出一些合理解释:
事件A表示:“小孩说谎”;事件B表示:“小孩可信”。
村民起初对这个小孩的信任度为0.8,即P(B)=0.8。
我们认为可信的孩子说谎的可能性为0.1。即P(A|B)=0.1。
不可信的孩子说谎的可能性为0.5,即P(A|^B)=0.5(用 ^B表示B的对立事件)。
求小孩第一次说谎、第二次说谎后,村民对这个小孩的信任度从P(B)=0.8会发生什么变化?
由此我们可以得到贝叶斯决策另一个道理,贝叶斯决策会不断用后验概率,逐渐修正先验概率。投射到现实生活,我们也可以理解为当对某件事进行判断决策时,关于此事得到的信息越多,对此事的决策越准,而绝非yes/no的五五开决策。
还是狼来的例子,如果这个孩子要改邪归正,他需要多少次才能把信任度提高到80%?
如果要把信任度提高,那接下来就需要通过几次 不说谎 的经历来修正村民的观念,那可信度的计算,要记得将P(A|B)换成P((fei)A|B),(A上方的横线打不出来…),就是可信的孩子不说谎的可能性为1-P(A|B)=1-0.1,同样,不可信的孩子不说谎的概率为1-0.5
此时,我们就要用代码来实现而不是手算啦。代码如下:
1 | def calculateTrustDegree(pb): |
4.朴素贝叶斯分类器
贝叶斯分类算法是一大类分类算法的总称。
贝叶斯分类算法以样本可能属于某类的概率来作为分类依据。
朴素贝叶斯分类算法是贝叶斯分类算法中最简单的一种,采用了“属性条件独立性假设”:对已知类别,假设所有属性互相独立,也就是在概率的计算时,可以将一个类别的每个属性直接相乘。这在概率论中应该学过,两个事件独立时,两个事件同时发生的概率等于两个事件分别发生的乘积。
给定一个属性值,其属于某个类的概率叫做条件概率。对于一个给定的类值,将每个属性的条件概率相乘,便得到一个数据样本属于某个类的概率。
我们可以通过计算样本归属于每个类的概率,然后选择具有最高概率的类来做预测。
我们以鸢尾花分类实例来过算法流程,并不适用sklearn库自实现朴素贝叶斯分类器。
实例数据集介绍:鸢尾花数据集包含4维的特征,共三类150个样本,每类均有50个样本。
算法流程概括如下:
- 计算样本属于某类的先验概率,属于A类的概率为$\frac{属于A类的样本数}{所有样本数}$,以此类推
- 计算类条件概率,离散值通过类别数量比值,此数据集的属性特征为连续值所以通过 概率密度函数 来计算。首先计算在一个属性的前提下,该样本属于某类的概率;相乘合并所有属性的概率,即为某个数据样本属于某类的类条件概率
- 计算每个特征属于每类的条件概率
- 概率密度函数实现
- 计算每个属性的均值和方差
- 按类别提取属性特征,这里会得到 类别数目*属性数目 组 (均值,方差)
- 按类别将每个属性的条件概率相乘,如下所示
- 判断为A类的概率:p(A|特征1)p(A|特征2)p(A|特征3)*p(A|特征4)…..
- 判断为B类的概率:p(B|特征1)p(B|特征2)p(B|特征3)*p(B|特征4)…..
- 判断为C类的概率:p(C|特征1)p(C|特征2)p(C|特征3)*p(C|特征4)…..
- 计算每个特征属于每类的条件概率
- 先验概率*类条件概率,回顾一下贝叶斯公式,$$ P(B_i|A) = \frac{P(B_i)P(A|B_i)}{\sum_{j=1}^nP(B_j)P(A|B_j)}$$。由于样本确定时,贝叶斯公式的分母都是相同的。所以判断样本属于哪类只需要比较分子部分:先验概率类条件概率,最终属于哪类的概率最大,则判别为哪类,此处为*最小错误率贝叶斯分类**,若采用最小风险需要加上判断为每个类别的风险损失值。
5.代码实现
1.数据集载入,划分训练集与测试集
1 | data_df = pd.read_csv('IrisData.csv') |
2.计算先验概率
此时需要先知道数据集中属于各类别的样本分别有多少。我们通过一个函数实现按类别划分数据。
两个返回值分别为划分好的数据字典,以及划分好的数据集中每个类别的样本数
1 | def seprateByClass(dataset): |
计算属于每个类别的先验概率
1 | def calulateClassPriorProb(dataset,dataset_info): |
3.计算类条件概率
3.1 首先计算每个特征属于每类的条件概率,前面说过这里我们使用概率密度函数来计算
概率密度函数实现:
方差公式:$ var = \frac{\sum(x-avg)^{2}}{n-1}$,概率密度函数:$ p(xi|c) = \frac{1}{\sqrt{2\pi}\sigma_{c,i}}exp(-\frac{(xi-mean_{c,i})^{2}}{2\sigma_{c,i}^{2}})$ , $\sigma$是标准差(方差开方)
1 | # 均值 |
每个属性特征属于每类的条件概率是个组合。举例来说,这里有3个类和4个数值属性,然后我们需要每一个属性(4)和类(3)的组合的类条件概率。
为了得到这12个概率密度函数,那我们需要提前知道这12个属性分别的均值和方差,才可以带入到上述概率密度函数中计算。
计算每个属性的均值和方差:
1 | def summarizeAttribute(dataset): |
按类别提取属性特征,这里会得到 类别数目*属性数目 组 (均值,方差)
1 | def summarizeByClass(dataset): |
按类别将每个属性的条件概率相乘。
我们前面已经将训练数据集按类别分好,这里就可以实现,输入的测试数据依据每类的每个属性(就那个类别数*属性数的字典)计算属于某类的类条件概率。
1 | def calculateClassProb(input_data,train_Summary_by_class): |
4.先验概率*类条件概率
朴素贝叶斯分类器
1 | def bayesianPredictOneSample(input_data): |
终于把分类器写完啦,接下来就让我们看看测试数据的结果!
单个样本测试:
1 | input_vector = testset[1] |
看看分类准确率
1 | def calculateAccByBeyesian(dataset): |
全部代码及数据集已上传至github,第一次写博客不足之处欢迎大家提出交流学习。