首页 / 资讯中心 / 文章详情

二项分布实战:抽检、A/B实验与异常检测阈值

二项分布实战:抽检、A/B实验与异常检测阈值 ★ FEATURED ARTICLE
1. 为什么二项分布值得反复琢磨我第一次真正把二项分布用明白不是在课本上而是在一个抽检场景里。当时业务方给了一批货说抽 20 件看看有多少件不合格问我抽到 3 件以上不合格就退货这个规则靠不靠谱。我一开始凭直觉说20 件里 3 件不合格15% 的不良率有点高吧结果被反问了一句如果这批货真实不良率只有 5%你抽 20 件出现 3 件以上不合格的概率有多大我当场卡住了。这个问题的答案就是二项分布要解决的事。二项分布描述的是在 n 次独立重复的伯努利试验中成功次数所服从的概率分布。一句话拆开有三个硬条件试验次数 n 是固定的、每次只有成功/失败两种结果、每次成功的概率 p 保持不变且各次之间互不影响。满足这三条成功次数 X 就服从参数为 (n, p) 的二项分布记作 X ~ B(n, p)。它解决的是一类非常具体的问题在重复做同一件事若干次的前提下我想知道成功几次这件事的概率有多大。抛 10 次硬币正面朝上几次、100 个用户里有多少人点广告、一批零件抽 50 个有几个次品、投篮 20 次命中几个本质上都是同一个模型。适合谁看如果你是需要做质量抽检、A/B 实验评估、转化率判断、风控阈值设定的从业者或者只是被n 选 k 的概率绕晕过的学生这篇内容都能给你一条从头算到尾的清晰路径。我下面不光讲公式长什么样更重要的是讲清楚每个参数怎么来的、什么时候这个模型会失效、以及我在实操中踩过的那些坑。公式背下来十分钟就够但知道它什么时候不能用往往要花好几年。2. 把二项分布拆开看从一次抛硬币到 n 次重复2.1 伯努利试验整个模型的原子单位二项分布的地基是伯努利试验名字听着唬人其实简单到不能再简单一次试验只有两种结果成功或者失败成功概率记作 p失败概率就是 1-p。抛一次硬币、点一次广告、检查一个零件这些都是伯努利试验。这里有个新手最容易忽略的点成功不代表好事。在质量抽检里成功往往指的是抽到次品因为我们关心的就是次品出现的次数。在医学统计里成功可能指的是出现不良反应。所以看到 p 的时候千万别默认它代表好消息一定要回到具体场景确认 p 到底是谁的概率。我在早期做过一个错误判断就是因为把合格率当成了 p 代进去算不合格件数方向整个反了结论自然也全错。另一点是 p 必须固定。一个人投篮体力下降后命中率会变那就不满足固定 p 的要求一台设备连续运行会升温不良率会漂移也不满足。伯努利试验强调的是同一个人、同一状态、同一条件下重复这个同一是模型成立的前提不是修辞。2.2 独立性的真实含义为什么它比 p 固定更容易被破坏独立性说的是各次试验之间互不影响前一次的结果不会改变后一次的概率。听起来理所当然实际场景里反而是它更容易被违反。举个生活化的例子从一副牌里有放回地抽每次抽到红桃的概率都是 1/4各次独立可以套二项分布但如果是无放回地抽第一张抽走了红桃剩下的牌里红桃比例就变了第二次的概率不再是 1/4这时候要用的是超几何分布不是二项分布。这个差别在样本量小的时候特别明显总数 20 张抽 5 张无放回和有放回算出来的概率能差出好几个百分点但总数 10000 抽 5 张差别小到可以直接忽略工程上就常拿二项分布近似替代。还有一种隐蔽的不独立群体效应。比如一个班级里问是否支持某个方案学生之间会互相讨论前一个人的回答影响后一个人这时候独立就破了。或者一条生产线上相邻的零件共用同一批原料、同一个模具缺陷往往是成簇出现的一个出问题后面几个也容易出问题。这类数据用二项分布算出来的概率会偏乐观因为它低估了波动。提示拿到一个问题先问自己三件事——n 是不是事先固定的每次是不是只有两种结果各次之间有没有互相影响三个都是是再往下用二项分布。2.3 组合数从哪来概率公式的前半截假设 n3p0.5问恰好 1 次成功。成功可能发生在第 1 次、第 2 次或第 3 次这是三种不同的排列。每种排列的概率都是 p × (1-p) × (1-p) 0.5 × 0.5 × 0.5 0.125三种加起来 0.375。这里的三种就是组合数 C(3,1) 3。一般地n 次里恰好 k 次成功成功位置的选法是 C(n,k) 种每种选法对应的概率都是 p^k × (1-p)^(n-k)因为 k 次成功各贡献一个 pn-k 次失败各贡献一个 1-p乘法交换律保证顺序不影响结果。所以P(X k) C(n,k) × p^k × (1-p)^(n-k)我建议你把这个公式读成一句话先挑位置再算这一种情况的概率最后相乘。C(n,k) 管挑位置p^k 管成功那几次 (1-p)^(n-k) 管失败那几次。这样记比死背符号有用得多也不容易把指数搞反。顺便说一个常见的手算错误C(n,k) 是对称的C(10,3) C(10,7) 120很多人在算至少类问题时会用错端点比如算 P(X ≥ 8) 时只算了 P(X8)忘了 9 和 10。这种错误在实际报告里出现过不止一次而且因为结果看起来合理很难被肉眼发现。2.4 期望与方差两个数字看透分布形态二项分布的期望是E(X) np方差是Var(X) np(1-p)。这两个式子不用推但要理解它们的含义。期望 np 是长期平均会发生多少次成功。100 次试验、p0.2平均成功 20 次这符合直觉。方差 np(1-p) 描述的是波动大小它有个很有意思的性质p0.5 时方差最大p 越靠近 0 或 1方差越小。翻译成人话当你做一件成败各半的事结果的波动最剧烈当你做一件几乎必成或几乎必败的事结果非常稳定几乎每次都一样。这个性质在实操里很关键。同样是 n100p0.5 时标准差是 5意味着结果常在 45 到 55 之间晃p0.01 时标准差约 1结果基本就在 0 到 2 之间。所以我做监控告警阈值时一定会先看 np(1-p) 有多大波动大的指标阈值要给宽波动小的可以收紧绝不能所有指标用同一套阈值。这一点我在早期吃过亏给小概率事件设了对称的上下限结果天天误报。3. 手算一遍5 分钟把公式跑通3.1 一个完整的手算示例还是用开头那个抽检场景抽 20 件真实不良率 5%问恰好 3 件不合格的概率。第一步确认条件n20p0.05k3各件之间独立假设是从大批量里随机抽无放回的影响可忽略。第二步算组合数 C(20,3) 20×19×18 ÷ (3×2×1) 1140。第三步算 p^k 0.05^3 0.000125。第四步算 (1-p)^(n-k) 0.95^17。这个数手算麻烦实际用计算器0.95^17 ≈ 0.4181。第五步相乘1140 × 0.000125 × 0.4181 ≈ 0.0596。所以恰好 3 件不合格的概率约 5.96%。回到业务方的问题3 件以上不合格就退货需要算 P(X ≥ 3) 1 - P(X ≤ 2)kP(Xk) 计算结果00.95^200.3585120 × 0.05 × 0.95^190.37742190 × 0.0025 × 0.95^180.1887P(X ≤ 2) ≈ 0.9246所以 P(X ≥ 3) ≈ 0.0754也就是 7.5% 左右。换句话说即使这批货完全合格不良率就是 5%也有约 7.5% 的概率会被这个规则判为退货。这就是第一类错误业务方看到这个数字后才意识到规则定得偏严。3.2 用代码替代手算手算适合理解生产环境肯定用代码。Python 里 scipy 是标准选择from scipy.stats import binom n, p 20, 0.05 # 恰好 3 件不合格 print(binom.pmf(3, n, p)) # 0.05958... # 3 件及以上 print(binom.sf(2, n, p)) # 0.07548... (sf 1 - cdf) # 不超过 2 件 print(binom.cdf(2, n, p)) # 0.92451... # 期望与标准差 print(n * p, (n * p * (1 - p)) ** 0.5) # 1.0 0.9747这里有两个细节值得说。第一求至少 k 件用 sf(k-1) 而不是 1-cdf(k)。cdf(k) 是 P(X≤k)所以要 P(X≥k) 应该用 1-cdf(k-1)或者直接用 sf(k-1)。写成 1-cdf(k) 会漏掉恰好等于 k 的那一项这是极高频的 bug我自己写过也在别人的代码里见过好几次。第二p 很小时 pmf 的数值会非常小做报告时记得转成每万次之类的量级不然读者看到 1.2e-08 会直接失去判断力。如果不想装 scipy用 math 库手搓也行逻辑更透明from math import comb, pow def binom_pmf(k, n, p): return comb(n, k) * (p ** k) * ((1 - p) ** (n - k)) def binom_cdf(k, n, p): return sum(binom_pmf(i, n, p) for i in range(0, k 1))小样本下自己写反而更可控也方便在不能装第三方库的环境里跑。但要提醒一句n 大了以后直接用 comb 算组合数会有大整数溢出风险工程上一般会转到对数空间用 lgamma 算这个在 n 超过几百时就要考虑了。3.3 参数怎么定n 和 p 的确定顺序实操中很多人卡在p 从哪来。我的经验是先定 n再估 p不要反过来。n 是由实验设计决定的抽检 20 件就是 20跑 7 天每天 1000 次曝光就是 7000。n 应该是一个你事先就说清楚、事后不能改的数字。这点特别重要因为事后调整 n 会让整个概率解释失效。我见过一种做法先看数据发现第 30 次的时候效果最好就报前 30 次的结果这在统计上是不成立的因为 n 变成了一个随结果变化的东西。p 的估计有两条路。有历史数据就用历史频率比如过去三个月平均不良率 5%就取 0.05没有历史数据就做保守假设取最坏情况或者做敏感性分析把 p 从 0.01 扫到 0.10 看结论稳不稳。我强烈建议后者因为单一 p 值算出来的结论往往给人一种虚假的确定感而实际上 p 本身就有误差。注意如果 n 很大、p 很小、np 在 5 到 10 之间可以用泊松分布近似计算会简化很多如果 n 很大而 p 接近 0.5可以用正态近似。但近似的适用边界要守住np 小于 5 的时候正态近似误差会很明显尤其是尾部概率。4. 实操场景三个真实感的落地案例4.1 质量抽检把验收规则算清楚抽检是二项分布最经典的应用。假设一批货 5000 件约定不良率不超过 1% 就算合格验收方案是抽 50 件不合格数超过 2 件就退货。我们要评估这个方案的两种风险。第一种风险叫弃真货其实是好的p0.01却被判退货。算 P(X ≥ 3 | n50, p0.01)binom.sf(2, 50, 0.01) # 约 0.0138只有 1.4% 左右说明误伤概率很低这个方案对好货比较友好。第二种风险叫存伪货其实不行比如 p0.05却被判合格。算 P(X ≤ 2 | n50, p0.05)binom.cdf(2, 50, 0.05) # 约 0.5405高达 54%意味着不良率 5% 的货有超过一半的概率能蒙混过关。这个结果一出来业务方立刻明白 50 件的样本量太小了后来把方案改成抽 200 件、不合格超过 6 件退货再算一遍两种风险才达到可接受的水平。这个案例我想强调的是抽检方案的设计本质是在两条错误概率之间做权衡而不是拍脑袋定一个看起来合理的数字。样本量越大两条错误概率可以同时压低但成本上升。二项分布在这里的作用是让你在拍板之前就能看到每种方案的代价而不是等出了事故再复盘。4.2 转化率判断A/B 实验里最容易踩的坑假设某功能改版对照组 1000 次曝光 100 次转化10%实验组 1000 次曝光 120 次转化12%。直觉上提升了 20%要不要全量上线用二项分布的角度看我们要问的是如果两组真实转化率一样都是 11% 左右出现一组比另一组多 20 次这种差异的概率有多大。这里可以用两组独立二项分布之差来判断也可以在单组内做近似检验。import numpy as np from scipy.stats import binom, norm n, p0 1000, 0.11 # 单组标准差 sd (n * p0 * (1 - p0)) ** 0.5 # 约 9.9 # 两组差异的标准差 sd_diff (2 * n * p0 * (1 - p0)) ** 0.5 # 约 14.0 z (120 - 100) / sd_diff print(z) # 约 1.43z 大约 1.43对应的单侧 p 值约 0.076双侧约 0.15。这个差异在统计上并不显著仅凭这组数据全量上线是有风险的。很多团队在这里犯错是因为只看百分比不看绝对量和波动12% 对 10% 看起来漂亮但 1000 的样本量下这点差异完全可能是随机波动造成的。我在实操中的做法是先把 p 的历史值和 n 摆出来算出要检测出多大的提升才需要多少样本量再去决定实验要跑多久。这个顺序反过来——先跑一周再看数据够不够——就会陷入数据不够但不想再等的尴尬最后往往靠主观判断收场。4.3 异常检测给监控指标设合理阈值线上系统每天有 10000 次请求历史失败率 0.3%问每天失败次数在什么范围内算正常。期望是 10000 × 0.003 30 次标准差是 √(10000 × 0.003 × 0.997) ≈ 5.47。按正态近似的经验法则95% 的情况下失败次数落在 30 ± 1.96×5.47也就是大约 19 到 41 之间。n, p 10000, 0.003 lo binom.ppf(0.025, n, p) # 约 20 hi binom.ppf(0.975, n, p) # 约 41 print(lo, hi)所以阈值可以设成单日失败超过 41 次告警这样正常情况下误报率控制在 2.5% 左右。如果按固定比例设阈值比如失败率超过 0.5% 就告警对应 50 次那就太松了真有问题的日子也可能不报如果按固定次数比如超过 35 就报又太紧天天误报。这个场景里我想说的是阈值的合理性来自于对分布的定量理解而不是凭经验感觉。p 和 n 一确定正常波动范围就确定了剩下只是选一个你能接受的误报率。而且这里还有个隐含前提每天的请求互相独立。如果某次故障会导致连续多天失败率偏高那独立性就破了这时候应该考虑用更复杂的模型或者直接看趋势而不是套二项分布。5. 常见误区与排查实录5.1 五个高频错误对照表我在带人和做评审的过程中反复见到的错误其实就那么几类整理成表方便对照错误表现根本原因正确做法用 1-cdf(k) 求 P(X≥k)混淆了 cdf 的定义端点用 sf(k-1) 或 1-cdf(k-1)把至少一次成功算成 np把期望当成概率P(X≥1) 1-(1-p)^n无放回抽样直接套二项分布忽略了独立性被破坏样本占比小于 5% 时可近似否则用超几何p 用了合格率去算不合格数没有确认 p 的语义明确成功事件到底是什么事后改变 n 或筛选数据破坏了 n 的预先固定性n 必须在看数据前确定并记录第三行的5% 经验法则值得展开一句当抽样比例不到总体 5% 时无放回带来的概率变化很小二项分布的误差可以接受超过这个比例就该换模型或者加有限总体校正。这个 5% 不是铁律但在工程上足够用。5.2 一个我排查了很久的数值问题有次做小概率事件的概率计算n500p0.001要算 P(X ≥ 5)。用 1-cdf(4) 算出来是 0.0002 左右但换成 sf(4) 却是 0.00018 左右两者对不上差了 10%。原因是浮点数相减的精度损失。cdf(4) 的值接近 0.9998用 1 去减有效数字被吃掉了一大截。这种情况下必须用 sf它是直接从尾部累积计算的不经过1 减这一步。from scipy.stats import binom n, p 500, 0.001 print(1 - binom.cdf(4, n, p)) # 0.000200... 精度受损 print(binom.sf(4, n, p)) # 0.000183... 更准确这个坑的教训是凡是算尾部概率一律优先用 sf 而不是 1-cdf。同理算 P(X ≤ k) 用 cdf 没问题但算接近 1 的概率时要留意精度。这类问题在报告里不会报错只会给你一个看起来合理但偏差不小的数字特别难发现。5.3 模型失效的三个信号有几个信号出现时就该怀疑二项分布不适用了信号一方差明显大于 np(1-p)。这就是统计学里说的过度离散。真实数据里非常常见比如用户行为有聚集性、缺陷有成簇性。检验方法很简单拿多组观测算样本方差跟理论方差比如果大出一截说明独立性假设不成立。这时候可以考虑用贝塔二项分布它允许 p 本身是个随机变量能吸收掉额外的波动。信号二p 随时间漂移。做时间序列图如果成功率有明显趋势或周期性那 p 就不是常数。这时候应该分段建模或者引入时间因素而不是把整段数据揉成一个 p。信号三n 不固定。比如每天记录当天发生的成功次数但每天的试验次数本身是随机的那这其实是泊松过程的场景不是二项分布。两者的区别在于 n 是否事先固定n 固定用二项n 随机用泊松。提示判断一个场景该用哪个分布最简单的问法是试验次数是我定的还是自然发生的我定的是二项自然发生的是泊松。5.4 报告里怎么把概率讲清楚最后一个坑是沟通。算出来 P(X ≥ 3) 7.5%直接丢给业务方对方很可能没感觉。我的做法是换三种说法各讲一遍第一种用频率每 100 次抽检大约有 7 到 8 次会被误判第二种用对比这比你要求的 5% 误判率还高一点规则得放宽第三种用代价按每月抽检 20 批算一年会误退大约 18 批。把概率翻译成次数和代价决策者才能做判断。这一步看着不像技术活但我认为它比公式推导更影响项目的实际价值。毕竟算得再准如果没人能拿它做决定这个分析就等于没做。6. 我个人在实际操作中的几点体会用二项分布这些年我最大的感受是它的难点从来不在公式而在条件校验。公式四则运算就能算完但要确认 n 固定、p 恒定、各次独立这三条往往需要跟业务方来回问好几轮甚至要去看数据是怎么采的、抽样是不是真的随机。我现在的习惯是动笔算之前先在纸上写三行n 是多少、p 是什么事件的概率、各次之间有没有关联。这三行写不出来就先别算。写出来了后面基本是机械劳动。另外就是前面反复提到的尾部概率一律用 sf多组比较先算样本量再跑实验这两条能避免掉大部分低级但致命的错误。如果你要往下延伸贝塔二项分布、泊松分布、超几何分布是三个自然的下一站它们分别对应p 不确定、n 不固定、无放回这三种二项分布失效的情形。把这几条边界搞明白比多背十个公式有用得多。
阅读完成 · 觉得有帮助?
咨询建站