【机器学习】朴素贝叶斯-贝叶斯公式

       曾以为数理是这世上最绝对、最客观、最远离哲学的,慢慢地我发现其实他们是最不绝对、最不客观、最含有哲学意味儿的。这个看法改变的过程,其实是对世界深度认知的过程,在感性与理性中探索有限与无限。感触有点深,主要是最近对概率统计以及微积分的学习与研究,让我知道那些公式背后都有一些难以跨过的坎。今天不感慨,整理一下几个月前看贝叶斯公式的思路。

       之前介绍条件概率的时候,写的贝叶斯公式中只有AB,是因为我们假设在全集U中,只有AB两个事件,基于这样一个图(这里的AB和上篇博客的AB互换了):


       在这张图中,假设黄色区域为C,面积为cABU的面积分别为a,b,u,那么,贝叶斯公式可以表示为:已知A的面积占U的百分比为P(A)B的面积占U的百分比为P(B),C的面积占B的百分比为P(A|B),求C的面积占A的百分位P(B|A)是多少?我们可以利用面积自己证明一下上篇博客中的贝叶斯公式。

       实际上,U全集中的事件远不止AB,我们假设U全部由多个B组成,从B1Bn,每个B都是相互独立的(朴素),这些B的全集会覆盖A。图和公式如下,再来明确一下贝叶斯公式中的概念。



       P(Bi)是先验概率,是Bi发生的概率,先验概率是在得到实验观测值之前对一个参数概率的主观判断,然后我们得到一个先验概率,通过不断实验对这个数据进行修正,从而得到更接近真实客观的概率值。先验概率不需要通过贝叶斯公式计算。

       P(Bi|A)是后验概率(也叫条件概率),是在A发生的情况下Bi发生的概率,把Bi看做原因,A看做结果,可以认为是在结果已经发生的情况下,求由Bi这一因素引起的概率多大。我看到一种更好的说法。

————————————————————————————————————————————————————

       "如果我们把事件A看做'结果',把诸事件B1,B2...看做导致这个结果的可能的'原因',则可以形象地把全概率公式看做成为'由原因推结果';而贝叶斯公式则恰好相反,其作用于'由结果推原因':现在有一个'结果'A以发生,在众多可能的'原因',到底是哪一个导致了这结果。"

————————————————————————————————————————————————————


全概率:Bi引发A发生的概率的和,即 P(B1)*P(A|B1)+P(B2)*P(A|B2)+……+P(Bi)*P(A|Bi)+……P(Bn)*P(A|Bn)

于是我们得到了更一般的贝叶斯公式:


       先验概率和后验概率变成了概率分布,全概率用求和的方式表示。

      似然函数:P(A|Bi)被叫作类条件概率,我觉得应该也是条件概率,只不过在这里条件是A,所以不能再叫作条件概率而已。所以,这里写成了f(A|Bi),是我们观测到的样本A的分布,叫作似然函数。

      B的分布是离散的,可以用求和来求全概率。当B的分布是连续的时,只能通过积分来求,所以,贝叶斯公式又演变成了下面这样:


       先验概率的引入,使得当时贝叶斯统计学并不被认可,这也正是贝叶斯统计最具创造性之处。有人说,人工智能的原理,就是基于大量的数据,按照某种规律,进行大量的计算,最终总会收敛到我们想要的结果,我觉得很对。但对于从先验概率开始,通过不断的迭代与修正最终得到了后验概率,这一观点我并不认同,但又总觉得那个原理一定指导着什么。我也不太清楚先验概率的取值对所求的后验概率究竟有怎样的影响。


继续深入:

       1. 先验:如果我们有领域知识,或者猜测模型参数应该是什么,那么我们可以将它们包括在我们的模型中,这与频率方法不同,后者假设所有参数都来自数据。如果我们没有提前做出任何估计,那么我们可以使用非信息性的先验来确定正态分布等参数。

       2. 后验:执行贝叶斯线性回归的结果是基于数据和先验的可能模型参数的分布。这使我们能够量化我们对模型的不确定性:如果数据少,后验分布将更加分散。


       随着数据点数量的增加,可能性会冲刷先验,并且在无限数据的情况下,参数的输出会收敛到从OLS获得的值。作为分布的模型参数的表达形式包含了贝叶斯的世界观:我们从最初的估计开始,即先验,并且随着我们收集更多的证据,我们的模型变得不那么错了。贝叶斯推理是我们直觉的自然延伸。通常,我们有一个最初的假设,当我们收集支持或反驳我们想法的数据时,我们改变了我们的世界模型。其实就是我们学习或认得某个东西的过程。


以下是朴素贝叶斯分类器的伪代码: 1. 训练阶段: (1)对于每个类别 i,计算先验概率P(Y=i)。 (2)对于每个特征 j,计算在每个类别 i 下该特征的条件概率P(Xj=x|Y=i)。 2. 测试阶段: (1)对于输入样本 x,计算该样本属于每个类别 i 的条件概率P(Y=i|X=x)。 (2)将样本分到概率最大的类别中。 下面是朴素贝叶斯分类器的 C++ 代码实现,其中假设特征和类别都是离散的: ``` #include <iostream> #include <vector> #include <map> #include <cmath> using namespace std; // 计算先验概率 map<int, double> cal_prior_prob(vector<int>& labels) { map<int, double> prior_prob; int total = labels.size(); for (int i = 0; i < total; i++) { int label = labels[i]; if (prior_prob.find(label) == prior_prob.end()) { prior_prob[label] = 0.0; } prior_prob[label] += 1.0; } for (auto iter = prior_prob.begin(); iter != prior_prob.end(); iter++) { iter->second /= total; } return prior_prob; } // 计算条件概率 map<int, map<int, double>> cal_cond_prob(vector<vector<int>>& features, vector<int>& labels) { map<int, map<int, double>> cond_prob; int total = labels.size(); int feature_num = features[0].size(); for (int i = 0; i < total; i++) { int label = labels[i]; if (cond_prob.find(label) == cond_prob.end()) { cond_prob[label] = map<int, double>(); } for (int j = 0; j < feature_num; j++) { int feature = features[i][j]; if (cond_prob[label].find(j) == cond_prob[label].end()) { cond_prob[label][j] = map<int, double>(); } if (cond_prob[label][j].find(feature) == cond_prob[label][j].end()) { cond_prob[label][j][feature] = 0.0; } cond_prob[label][j][feature] += 1.0; } } for (auto iter1 = cond_prob.begin(); iter1 != cond_prob.end(); iter1++) { int label = iter1->first; for (auto iter2 = iter1->second.begin(); iter2 != iter1->second.end(); iter2++) { int feature = iter2->first; int feature_total = iter2->second.size(); for (auto iter3 = iter2->second.begin(); iter3 != iter2->second.end(); iter3++) { iter3->second /= feature_total; } } } return cond_prob; } // 预测 int predict(vector<int>& feature, map<int, double>& prior_prob, map<int, map<int, double>>& cond_prob) { int label = -1; double max_prob = -1.0; for (auto iter = prior_prob.begin(); iter != prior_prob.end(); iter++) { int cur_label = iter->first; double cur_prob = log(iter->second); for (int i = 0; i < feature.size(); i++) { cur_prob += log(cond_prob[cur_label][i][feature[i]]); } if (cur_prob > max_prob) { max_prob = cur_prob; label = cur_label; } } return label; } // 测试 void test(vector<vector<int>>& features, vector<int>& labels, map<int, double>& prior_prob, map<int, map<int, double>>& cond_prob) { int total = labels.size(); int correct = 0; for (int i = 0; i < total; i++) { int predict_label = predict(features[i], prior_prob, cond_prob); if (predict_label == labels[i]) { correct++; } } cout << "Accuracy: " << (double)correct / total << endl; } int main() { // 读取数据,features存放特征,labels存放类别 vector<vector<int>> features; vector<int> labels; // 训练 map<int, double> prior_prob = cal_prior_prob(labels); map<int, map<int, double>> cond_prob = cal_cond_prob(features, labels); // 测试 test(features, labels, prior_prob, cond_prob); return 0; } ``` 注意:这里的代码只是朴素贝叶斯分类器的一种实现方式,可能还有其他实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值