Wilson 下界判定:给通过率配一把诚实的尺子
上篇留了个尾巴:我们说判定要看”保底分”(置信区间下界),别看表面通过率。问题来了——保底分怎么算出来的?算通过率的区间有好几种算法,尺子本身就有好坏之分。这篇把尺子的事说清楚。
一、三把尺子,量出三个”保底分”
同样一份证据(30 把过 27 把),三种常见算法给出三个下界:
| 算法 | 30 把过 27 把的区间 | 特点 |
|---|---|---|
| Wald(正态近似) | 约 [0.793, 1.000] | 最乐观,也最容易骗人 |
| Clopper-Pearson(精确法) | 约 [0.735, 0.979] | 最保守,尺子刻度故意放大 |
| Wilson(计分法) | [0.744, 0.965] | 居中,小样本下依然稳 |
Wald 给的保底分是 0.793,Wilson 给的是 0.744——尺子不同,结论的诚实程度就不同。Wald 是教科书里最常见的算法,但它是大样本时代的产物,样本一少就失真。
最能说明问题的例子是满分情形——30 把全过:
- Wald 会算出区间 [1.00, 1.00]:宽度为零,意思是”真实通过率就是 100%,千真万确”。30 把全过就敢这么声称,这把尺子显然在撒谎;
- Wilson 算出 [0.887, 1.000]:30 把全过,保底分 0.887——诚实,而且和直觉吻合:才 30 把,离”板上钉钉的 99%”还远。
二、为什么判定只看下界
区间有两个端点,为什么验收只盯左边那个?因为验收承诺是单向的。
“通过率 ≥ 0.90”是一句单向承诺:你只关心”真实水平会不会比 0.90 低”,不关心它高到哪去。三个端点各有各的读者:
- 上界给乐观派:理想情况能有多好;
- 中心给写新闻稿的:看起来最漂亮的数;
- 下界给签字的人:最保守情况下也不会跌破的线——承诺只能立在下界上。
签字的人用下界,这就是”下界判定”的全部理由。
三、Wilson 的直觉:证据不足时,往”五五开”靠一点
Wilson 算法不用背公式,记住它的脾气就行:样本越少,它越把你的成绩往 50% 的方向拉。
道理很朴素:只测 2 把全过,真实水平是 100% 吗?Wilson 说:证据太少,先当你是枚普通硬币(50%),等样本多了再相信你。样本量越大,这个”拉回”越弱,估计值越贴近实测值。——所以它在小样本和满分附近都不会失真,恰好是 Wald 摔跤的两个地方。
(想看公式和五行的 Python 实现,见文末附录 A。)
四、一个八卦:这把尺子 Reddit 也在用
2009 年,工程师 Evan Miller 写了篇著名文章《如何不按平均评分排序》,指出一个普遍的愚蠢:按平均分排序,”1 条五星评价”的商品会排在”100 条评价平均 4.8 分”的商品前面——前者样本太小,根本不配。
解法正是 Wilson 下界:不按平均分排,按保底分排。Reddit 评论区的”最佳”排序用的就是它。
注意这和测试判定是同一道数学题:一个用例 1 跑 1 过(通过率 100%)和一个用例 100 跑 96 过(96%),谁的证据更硬?按表面数字前者赢,按保底分后者赢。你购物时都会防”刷出来的五星”,测通过率时别忘了用同一把尺。
五、一张速查表:全过 N 把,保底分是多少
满分情形最常遇到,直接查表(Wilson,95%):
| 全过把数 | 保底分 | 能撑住的声明 |
|---|---|---|
| 10 | 0.723 | 失败率 < 28%(基本没说服力) |
| 30 | 0.887 | 失败率 < 11% |
| 50 | 0.929 | 失败率 < 7% |
| 100 | 0.963 | 失败率 < 3.7% |
| 300 | 0.987 | 可靠性 ≥ 0.99 的门槛区 |
| 1000 | 0.996 | 0.996 |
收藏这张表,下次再有人拿”跑了 30 把全过”来证明可靠性 0.99,你一眼就能看出差着数量级。
六、三个常见的抬杠,先替你回答
“这也太严了吧?” 不是严,是诚实。保底分不是惩罚,它随样本量自然上升——证据攒够了,线自然过。觉得严的人,真正想说的是”不想补样本”。
“为什么用 95%,不用 99%?” 置信度越高,尺子刻度越宽,保底分越低。95% 是行业默认的平衡点;涉及安全签核可以上 99%,但要对”需要更多样本”有预算。
“能不能用单侧区间再宽松一点?” 可以,而且说得通:验收是单向的,用单侧 95% 下界(z 取 1.645 而不是 1.96)略微宽松且理由正当。但先把双侧用熟,再谈这个优化。
七、这把尺子已经装在引擎里
Cyclone Core 判定引擎的默认判定方式就是 Wilson 下界判定(已支持):场景 YAML 里写 {metric: task_success, op: gte, value: 0.90},引擎判的是”95% 下界 ≥ 0.90”,而不是表面通过率——工程师写门槛,统计学管尺子,谁也别拿手气冒充证据。
下篇预告:判定不仅要”准”,还可以”快”——SPRT 序贯检验如何让证据攒够就提前收卷,平均省下三到五成的执行量。
附录 A:公式与五行实现(给想动手的人)
Wilson 区间(置信度对应 z 值,95% 时 z = 1.96):
p̂ + z²/(2n) ± z·√( p̂(1−p̂)/n + z²/(4n²) )
区间 = ─────────────────────────────────────────────
1 + z²/n
其中 p̂ = 通过次数 ÷ 总次数,n = 总次数。判定只取减号那一半(下界)。
def wilson_lower(k, n, z=1.96):
"""k 次通过 / n 次试验 → 95% 置信下界(保底分)"""
p = k / n
denom = 1 + z * z / n
center = (p + z * z / (2 * n)) / denom
half = z * ((p * (1 - p) / n + z * z / (4 * n * n)) ** 0.5) / denom
return center - half
print(round(wilson_lower(27, 30), 3)) # 0.744
print(round(wilson_lower(300, 300), 3)) # 0.987
附:名词解释(按出场顺序)
| 名词 | 通俗解释 |
|---|---|
| 保底分(下界) | 最保守情况下真实通过率也不会跌破的线;判定该看它 |
| 置信区间 | 根据样本算出的范围,真值大概率住在里面 |
| Wald(正态近似) | 最经典的区间算法,大样本才准;小样本/满分时会撒谎(如 30 把全过算出 [1.00, 1.00]) |
| Clopper-Pearson(精确法) | 保证不低估风险的”精确”算法,代价是偏保守、区间偏宽 |
| Wilson(计分法) | 本文推荐的算法:小样本稳、满分附近不失真,直觉是”证据少就往五五开拉” |
| 单侧 / 双侧区间 | 双侧给上下两个界;只关心”不低于多少”时可用单侧下界,略宽松 |
| z 值 | 置信度的换算系数:95% 对应 1.96,99% 对应 2.58,单侧 95% 对应 1.645 |
| 收缩(shrinkage) | 样本少时把估计往中立值(50%)拉一点的做法,防小样本吹牛 |
| 速查表 | 全过 N 把对应的保底分对照表,评审时随手查 |
| 下界判定 | 验收线作用在保底分上而不是表面通过率上的判定方式 |
| SPRT(序贯检验) | 下篇主角:边跑边算证据,够了提前下判的检验方法 |
(文中区间数值为对应算法的统计学计算结果,Clopper-Pearson 值为近似值;产品能力以 Cyclone Core 当前版本为准。)
下一步:
了解 Cyclone 判定引擎