资讯动态

先验、似然、后验概率:从贝叶斯公式到机器学习实战

发布时间:2026/10/3 14:22:15 来源:尧图企业网站定制
先验概率、似然概率与后验概率这三个词几乎每个做机器学习和数据分析的人都在面试里见过。我在面试算法岗时最常问的一道题就是“一次检验结果呈阳性真正患病的概率是多少”能熟练背出公式的人不少但能说清楚为什么答案不是99%的人其实很少。这个问题的核心就是先验概率、似然概率、后验概率三者之间那条隐藏的更新链条。这篇文章会把三个概念从“考试知识点”拆成“能上手用的工具”用医学检验、文本分类、参数估计几个真实场景把公式背后的直觉讲透再附上我踩过的坑和排查方法。适合刚学贝叶斯理论的初学者也适合在工作中用概率做决策但总被“反直觉”结果困扰的从业者。1. 先把底层思路拆开三个概率不是并列关系是一条“证据更新链”1.1 先别背公式你手里有旧判断来了新证据然后得到新判断我第一次接触贝叶斯公式时被一堆符号绕晕了。后来我用一句话记住了它在拿数据之前你心里有一个初始信念拿到数据之后你根据这个数据把信念修正成新的判断。这句话里天然就装着三个概率先验概率是拿到数据前你对某个假设有多相信的初始估计。它可能来自历史统计、业务经验甚至是行业常识。似然概率是“如果某个假设成立”你观察到当前这组数据的可能性有多大。它衡量的是证据和假设之间的匹配程度。后验概率是看完数据后你被修正过的新信念。也就是“在数据面前这个假设现在到底还有多可信”。三者串起来就是著名的贝叶斯公式P(H|E) P(E|H) × P(H) / P(E)其中 H 代表假设E 代表观测到的数据。公式看着冷冰冰但它干的事非常朴素把“事前想法”和“新证据”两个来源的信息揉到一起得到一个更合理的事后判断。1.2 三个概率的真实分工用一张表理清楚很多教程把这三个概念分开讲导致读者觉得它们是三个独立的知识点。其实它们服务于同一个推理链条只是分工不同。我用下面这张表给自己学生梳理过效果还不错概率数学表示回答的问题信息来源先验概率P(H)拿到证据之前假设有多可信历史统计、业务经验、均匀假设似然概率P(E|H)如果假设为真看到这个证据的概率有多大实验数据、观测统计、模型假设后验概率P(H|E)看到证据之后假设还有多可信先验与似然的组合按贝叶斯公式计算直观理解先验是你点餐前的“口味画像”——有的人无辣不欢有的人滴辣不沾似然是“菜端上来之后你觉得这道菜对胃口的可能性”后验则是“你尝了一口之后的真实感受”。桌上那盘菜不会变但你对它的判断会跟着“先前预期”和“实际口感”两条线索一起更新。1.3 为什么直觉总在“阳性完蛋”这里掉链子藏起来的分母是关键医学检测那个经典问题里人们最大的直觉误区是检验准确率99%结果阳性那患病概率不就该是99%问题出在只看了似然概率没看先验。贝叶斯公式里那个分母 P(E)在二分类场景下会展开成P(E) P(E|H) × P(H) P(E|¬H) × P(¬H)它把“假设成立且看到证据”和“假设不成立且仍然看到证据”两条路径的贡献全部加起来。如果参与检验的人群里患病本身是很小概率的事件那么哪怕“不患病但有误报”的比例只有一点点也会在分母里占据极大份额。这正是后验结果和直觉相反的根本原因直觉只算了分子里刺眼的部分忽略了分母里那些“骗子”证据带来的稀释效应。搞懂了这条“证据更新链”后面再看任何具体案例都会顺很多。下面我就用最经典的医学检验场景把整个计算过程一步步摊开。2. 用一个医学检测案例亲手算一遍先验、似然和后验2.1 设定病种参数先验来自人群似然来自实验后验来自计算假设我们对付的是一种发病率很低的罕见病普通人群中患病率是1%。这意味着随机抽一个人他在没有做任何检查前患病的先验概率是P(患病) 0.01 P(未患病) 0.99再假设医学检测试剂盒的性能参数如下灵敏度一个人确实患病检测出阳性的概率是99%即 P(阳性|患病) 0.99特异度一个人确实没病检测出阴性的概率是95%相当于假阳性率只有5%注意重要定义特异度对应的是“没病且查出来阴性”所以没病但被误判成阳性的概率就是 1 - 0.95 0.05即 P(阳性|未患病) 0.05。有了这两个参数似然概率就齐了。现在问题来了一个人去医院做检测报告显示“阳性”。他真实患病的后验概率是多少2.2 阳性报告拿到手后验到底是多少一步步算给你看不要着急套公式先把贝叶斯公式里每个部分都存在哪先验 P(患病) 0.01似然 P(阳性|患病) 0.99分母 P(阳性) 需要分两条路径累加患病且阳性加未患病但阳性分母计算过程P(阳性) 0.01 × 0.99 0.99 × 0.05 0.0099 0.0495 0.0594然后计算后验P(患病|阳性) 0.01 × 0.99 / 0.0594 0.0099 / 0.0594 ≈ 0.167也就是说即使拿到阳性报告真正患病的概率也只有大约16.7%远远不是直觉中的99%。第一次算这个结果时我盯着计算器看了好一会儿一个99%准确率的检测怎么阳性后只有16.7%的概率患病关键在于人群里99%的人都是未患病者而这99%的人里有5%都会贡献一个假阳性信号。相比之下真正患病且在人群中占比只有1%的人就算100%都能查出阳性它贡献的分子也才0.01左右。假阳性的人群基数太大把真阳性的信号完全淹没了。这也是我在教别人时反复强调的一点先验概率会强烈影响后验概率。高准确率的检测工具解决的是“假设成立时证据有多强”却改变不了“假设本身在人群中有多常见”。2.3 同一套逻辑再推一步后验变成下一次的先验动态更新很多人不知道贝叶斯公式还有一个漂亮特性它可以反复使用。第一次计算得到的后验概率可以作为第二次观测之前的先验概率形成连续更新。还是用刚才的例子。第一次检测阳性后这个人患病的后验概率大约是 0.167。他为了确认诊断结果换了一家医院再用同样性能的试剂盒重新检测一次结果仍然阳性。这时候新一轮计算里的先验不再是当初的0.01而是上次留下的后验0.167P(患病) 0.167 P(未患病) 0.833 P(第二次阳性) 0.167 × 0.99 0.833 × 0.05 0.16533 0.04165 0.20698 P(患病|第二次阳性) 0.16533 / 0.20698 ≈ 0.799两次独立检测都是阳性患病概率从16.7%猛升到约79.9%。这就是动态贝叶斯更新的力量每新增一条证据我们对世界的判断就收缩一点。而实际操作中很多概率系统比如推荐系统、垃圾内容拦截器都是靠这种“后验变先验、再引入新证据求新后验”的迭代方式运转的。3. 落到机器学习实战从文本分类到参数估计三个概率怎么当工具用3.1 垃圾评论识别一个词能锁定多少嫌疑我最早把贝叶斯公式用到业务里是做评论区垃圾内容识别。二分类问题本质上和医学检测完全同构把“垃圾评论”当“患病”把“正常评论”当“未患病”把“出现某个特征词”当“检测阳性”。假设现在只有一条训练数据统计信息评论是垃圾的先验概率 P(垃圾) 0.2正常评论的概率 P(正常) 0.8词“加我VX”出现在垃圾评论里的概率 P(加我VX|垃圾) 0.4这个词出现在正常评论里的概率 P(加我VX|正常) 0.0001那么一条包含“加我VX”的评论它是垃圾评论的后验概率P(垃圾|加我VX) 0.2 × 0.4 / (0.2 × 0.4 0.8 × 0.0001) 0.08 / 0.08008 ≈ 0.999一个词就把命中概率从20%拉到了99.9%。原因和医学例子里相反这个词在垃圾评论里出现频率较高而在正常评论里极其罕见所以它的鉴别力非常强。这里要特别提醒一句现实中不要只依赖单个词词与词之间通常有强相关性同时出现时不能简单相乘。朴素贝叶斯之所以叫“朴素”正是因为它对特征独立性做了简化假设。工程上大家依然接受这种简化是因为它在大量场景下表现足够稳定、计算又便宜。3.2 朴素贝叶斯落地代码从公式到第一版可用实现有了公式我们很快可以把分类逻辑写成 Python。下面是一个极简版示例核心就是统计先验和似然然后取对数相加防止极端概率下溢import math from collections import defaultdict class NaiveBayes: def __init__(self): self.log_prior {} self.log_likelihood defaultdict(lambda: {}) self.vocab set() def fit(self, docs, labels, smoothing1.0): class_docs defaultdict(list) for doc, label in zip(docs, labels): class_docs[label].append(doc) total_docs len(labels) for label in class_docs: self.log_prior[label] math.log(len(class_docs[label]) / total_docs) word_counts defaultdict(lambda: defaultdict(int)) class_word_total defaultdict(int) for label, corpus in class_docs.items(): for doc in corpus: for word in doc.split(): word_counts[label][word] 1 class_word_total[label] 1 self.vocab.add(word) for label in class_docs: total class_word_total[label] smoothing * len(self.vocab) for word in self.vocab: count word_counts[label].get(word, 0) smoothing self.log_likelihood[label][word] math.log(count / total) def predict(self, doc): scores {} for label in self.log_prior: scores[label] self.log_prior[label] for word in doc.split(): if word in self.log_likelihood[label]: scores[label] self.log_likelihood[label][word] return max(scores, keyscores.get)这段代码里有几个工程细节很重要拉普拉斯平滑某个词如果在训练集里从没出现过它的统计概率是0多个0乘起来会把整个后验清零。代码里给所有词频加了默认1次的平滑就是为了避免这种情况。取对数多个词的似然连乘后数值会极小直接计算会下溢变成0。先取对数再相加结果不会丢失精度。类先验直接来自样本比例如果训练集里垃圾评论只有2%先验就是0.02。这一步看似简单但它决定了模型对类别不平衡的敏感度。3.3 MLE和MAP的取舍当证据不可靠时先验站出来兜底机器学习里有两个和贝叶斯紧密绑定的参数估计方法极大似然估计MLE和最大后验估计MAP。它们的区别恰好就是“看似然”和“看后验”的区别。MLE的思路是把出现的观测数据当作全部真相找出让当前数据出现概率最大的那组参数。MAP则多走一步不仅看当前数据还要结合先验在“数据说什么”和“我之前怎么想”之间取平衡。举个例子。抛一枚硬币10次里出现8次正面、2次反面。MLE对正面概率的估计是0.8。但如果你凭生活经验认为硬币大概率是公平的正面概率应该在0.5附近那么MAP估计出来的正面概率不会直接落到0.8而是会在0.5和0.8之间被拉扯具体偏向哪边取决于样本量和先验强度。实际项目中MLE在小样本下特别容易过拟合训练数据里出现某种偶然规律会被当成铁的规律。MAP相当于给参数估计套了一个约束让它在数据极端时保持克制。我的经验是样本量小于几百条时必须用带先验的MAP样本量上万时MLE和MAP的结果几乎一样这时候再去纠结先验设置就没有太大意义了。3.4 冷启动场景里先验就是你的第一桶数据做推荐系统或者内容审核时最难受的是冷启动阶段系统刚上线一条业务数据都没有似然根本无从谈起。这时候先验就是唯一能用的信息源。比如给一个新的内容社区做垃圾评论拦截初始阶段可以直接把行业平均水平当作先验比如估算垃圾率10%然后设定一个比较保守的拦截阈值。随着人工标注数据积累用一批真实标注重新估计似然再用公式更新先验模型就会越跑越准。我第一次做这种系统时吃过一个亏上线前以为自己没数据就在代码里把先验写死成0.5。结果误杀率特别高因为真实评论里垃圾比例远低于一半。后来我改成“先验来自运营经验上线后前三天的标注数据重估”效果马上不一样了。记住没有显式设置先验不是空白的开始而是在用均匀分布假装自己什么都不知道。均匀先验本身也是一个很强的假设尤其在类别极度不平衡的业务场景里它会带来糟糕的初始表现。4. 我踩过的坑实况记录这些误区让项目多跑了两周4.1 误区一把似然函数当成概率直接加和归一化有一段时间我做贝叶斯调参把似然函数的输出直接当成“概率分布”来理解甚至试图让所有参数下的似然值加起来等于1。这是不对的。似然函数 L(θ|x) 是“固定观测数据看不同参数下观测结果出现的可能性”它并不满足概率分布的归一化条件。可以这样直观理解概率是在参数固定的时候讨论不同观测样本出现的可能性似然是在观测样本固定的情况下讨论不同参数取值的相对合理性。面向的对象完全不同。如果代码里发现“似然值加起来不等于1”就开始怀疑自己算错了大概率是方向错了。真正要归一化的是后验不是似然。4.2 误区二数据太少了却自以为“客观”我见过一些刚入行的同学在样本量只有几十条的时候仍然用MLE去估计似然然后问“为什么模型一上线就崩”。原因很简单小样本下MLE估计出来的参数方差极大一点噪声都会被放大。正确的做法是给参数加先验或者用平滑方法。说得更直白一点当你的证据不足以推翻经验时先验会帮你避免被偶然现象带偏。数据量越少先验的作用越重要数据量越多先验的作用越弱。记住这两个极端就能理解为什么贝叶斯方法是小数据场景的王牌。4.3 误区三后验概率显著却忘了检查先验是否符合当前场景另一个我踩过的坑是后验算出来很高但上到新场景之后表现很差。后来排查发现先验P(垃圾)用的是“全年平均垃圾率”但实际线上某个时段垃圾评论会突然飙升比如大促活动后广告轰炸。全年的平均先验在高峰时段根本不适用。这种情况的修正方法很简单用一个时间窗口内重新统计的类别占比去替代固定先验让模型具备“跟随环境变化”的能力。贝叶斯的魅力就在这先验不是一次性算完就锁死在代码里的常量它本身就应该随着新证据不断更新。4.4 常见问题排查速查表基于这么多年的实践我整理了一个速查表碰到贝叶斯相关模型表现异常时可以直接对照症状可能原因处理办法后验总是极端接近0或1多个似然连乘导致下溢或特征间强相关被重复计算取对数相加做特征独立性校验必要时去重新词进来后判断完全失控该词在训练集中出现次数过少似然估计方差大对词频做拉普拉斯平滑设置最小词频阈值上线后误杀率飙升先验没跟上业务场景变化仍使用历史固定值用最近时间窗口的实际类别占比重估先验小样本下参数估计异常用了MLE没有引入先验约束改用MAP根据业务知识设置合理的先验计算结果和业务直觉冲突严重业务方只关注似然没有把先验显式放进讨论把P(H)、P(E|H)、P(H|E)做成一张结果表逐项解释写到这里还是想分享一个个人体会这几年做文本识别和概率建模最关键的转折点不是背下公式而是真正接受“后验本身就是下一次的先验”这句话。第一次在项目里手动完成那个迭代循环时我突然觉得手里模型不再是静态的分类器而是一个会随着数据不断自更新的判断系统。如果你现在也正在被这三个概念绕晕我的建议是别在符号里打转找一个具体的业务问题手动算三遍理清每个数字对应的是先验还是似然最后再看后验。算过一遍比读十遍教材都有用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑