Agent 跑 30 次挂了 2 次,失败率到底在什么范围?
用 Wilson 区间:30 次挂 2 次,95% 置信区间约 1.8% ~ 21.3%。
教科书上的 p̂ ± 1.96·SE 在样本少、失败率低时会出错,而 Agent 评测大多就是这种情况。
1问题:rule of three 只能处理 0 次失败
上一个概念里,rule of three 回答的是:n 次全过,失败率最高可能是多少。但实际跑评测,很少一次都不挂。
跑了 \(n\) 次,挂了 \(k\) 次,点估计是:
$$\hat p = \frac{k}{n} = \frac{2}{30} \approx 6.7\%$$但 6.7% 只是这一次抽样的结果,重跑一轮可能挂 0 次,也可能挂 5 次。我们要的是一个区间:真实失败率 \(p\) 可能落在哪个范围。
2教科书公式(Wald 区间),以及它哪里不对
大部分人第一次学的是这个:
$$\hat p \;\pm\; z\sqrt{\frac{\hat p(1-\hat p)}{n}}$$\(z\) 是置信度对应的常数:90% → 1.645,95% → 1.96,99% → 2.576。根号那一项叫标准误(SE),衡量 \(\hat p\) 这个估计会抖多少。
它背后的想法是:\(\hat p\) 大致服从正态分布,以真实的 \(p\) 为中心。但有一步偷懒了:标准误本该用真实的 \(p\) 算,可 \(p\) 是未知的,于是直接拿 \(\hat p\) 代替。
这一偷懒,在 Agent 评测里会造成三个问题:
毛病 2:下界会变成负数。30 次挂 1 次:\(\hat p = 3.3\%\),SE \(= 3.3\%\),下界 \(= 3.3\% - 1.96 \times 3.3\% < 0\)。失败率不可能是负数。
毛病 3:名义上 95%,实际不到 95%。\(p\) 很小、\(n\) 不大的时候,这个方法实际能罩住真实值的比例(覆盖率)可能只有 80% 左右,甚至更低。下面第 5 节的覆盖率曲线可以直接看到。
3Wilson 的思路:还是反证法
Wilson 不再用 \(\hat p\) 代替 \(p\),而是换个问法,和 rule of three 的套路一样:
不算离谱的 \(p\) 留下,离谱的排除。留下来的所有 \(p\),就是置信区间。
"离谱"的标准是:\(\hat p\) 离 \(p\) 超过 \(z\) 个标准误。关键在于,这里的标准误用的是假设的 \(p\),不是 \(\hat p\):
$$|\hat p - p| \;\le\; z\sqrt{\frac{p(1-p)}{n}}$$这就是跟 Wald 唯一的区别:根号里是 \(p\),不是 \(\hat p\)。
推导(可以跳过,只看结论)
- 两边平方:\((\hat p - p)^2 \le \dfrac{z^2}{n}\,p(1-p)\)
- 展开,按 \(p\) 整理成一元二次不等式: $$\Big(1+\tfrac{z^2}{n}\Big)p^2 \;-\; \Big(2\hat p+\tfrac{z^2}{n}\Big)p \;+\; \hat p^2 \;\le\; 0$$
- 开口向上的抛物线 \(\le 0\),解就是两个根之间的那一段。用求根公式解出两个根,就是区间的上下界。
因为 \(p(1-p)\) 在 \(p=0\) 和 \(p=1\) 时都是 0,解出来的区间天然在 [0, 1] 里,不会出现负数。
4Wilson 区间公式
把求根公式整理成"中心 ± 半宽"的形式:
$$\text{中心} = \frac{\hat p + \dfrac{z^2}{2n}}{1 + \dfrac{z^2}{n}} \qquad \text{半宽} = \frac{z}{1 + \dfrac{z^2}{n}}\sqrt{\frac{\hat p(1-\hat p)}{n} + \frac{z^2}{4n^2}}$$ $$\text{区间} = [\,\text{中心} - \text{半宽},\;\; \text{中心} + \text{半宽}\,]$$怎么读这个公式
① 中心不是 \(\hat p\),而是往 50% 拉了一点。把中心的分子分母同乘 \(n\):
$$\text{中心} = \frac{k + z^2/2}{n + z^2}$$95% 时 \(z^2 \approx 3.84 \approx 4\),相当于凭空多加了 2 次失败、2 次成功再算比例。30 次挂 2 次,中心大约是 \((2+2)/(30+4) \approx 11.8\%\),比 6.7% 高。样本越少,这个拉动越明显;样本多了,加的这 4 次可以忽略。
这正是"加 2 个成功、加 2 个失败"这个速算法(Agresti–Coull 区间)的来源。
② 半宽的根号里多了一项 \(z^2/4n^2\)。所以即使 \(\hat p = 0\),半宽也不是 0。这就修掉了 Wald 的毛病 1。
手算一遍:30 次挂 2 次,95%
| 量 | 算式 | 值 |
|---|---|---|
| \(\hat p\) | 2 / 30 | 0.0667 |
| \(z^2/n\) | 3.8416 / 30 | 0.1281 |
| 中心 | (0.0667 + 0.0640) / 1.1281 | 0.1159 |
| 根号里 | 0.0667×0.9333/30 + 3.8416/3600 | 0.003141 |
| 半宽 | 1.96 / 1.1281 × √0.003141 | 0.0974 |
| 区间 | 0.1159 ± 0.0974 | [1.8%, 21.3%] |
对比 Wald:\(0.0667 \pm 1.96\times0.0455 = [-2.3\%, 15.6\%]\)。下界是负数,上界也偏低了。
5互动演示
三种方法算出的区间
覆盖率:名义上 95%,实际是多少?
固定 n 和置信度,横轴是真实失败率 p。对每个 p,把所有可能的 k 都考虑进去,精确算出"这个方法的区间罩住真实 p"的概率。好方法应该贴着虚线(名义置信度),掉到虚线下面就是在骗人。
锯齿是正常的:k 只能取整数,覆盖率会随 p 跳动。重点看两条线整体离虚线有多远。p 很小时 Wald 会掉得很低;Wilson 大体贴着虚线上下波动,但在 p 极小处也会下探到 85% 左右(这是 Wilson 在边界附近已知的弱点)。
6和 rule of three 的关系
令 \(k=0\)(\(\hat p=0\)),Wilson 上界化简为:
$$p_{\text{上界}} = \frac{z^2}{n + z^2}$$要跟 rule of three 比,先对齐"单侧 / 双侧"。rule of three 是单侧 95% 上界(只关心最高可能多少),对应 \(z = 1.645\)。双侧 95% 区间的上界,其实相当于单侧 97.5%(\(z = 1.96\)),会更宽。
| n = 30,0 次失败 | 上界 | 说明 |
|---|---|---|
| rule of three:3 / n | 10.0% | 单侧 95% 的速算 |
| 精确法:1 − 0.051/n | 9.5% | 单侧 95%,不做近似 |
| Wilson 单侧(z = 1.645) | 8.3% | 比精确值略乐观 |
| Wilson 双侧(z = 1.96) | 11.4% | 口径不同,不能直接跟上面比 |
Wilson 在 \(k=0\) 附近略偏乐观(上界偏低),因为它底层还是正态近似。门禁这种"宁紧勿松"的场景,要求严格就用精确法(Clopper–Pearson)。
7面试要点与常见错误
一句话讲清楚
Wald 用观测值 \(\hat p\) 去估标准误,样本少、失败率低时会失真;Wilson 反过来,逐个检验候选的 \(p\),用候选 \(p\) 自己的标准误判断观测值离不离谱,所以区间不会出负数,0 次失败时也有宽度,覆盖率接近名义值。
追问准备
- 为什么中心不是 \(\hat p\)?相当于多加了 \(z^2/2\) 次成功和失败,把估计往 50% 拉,n 越小拉得越多。
- 什么时候 Wald 也能用?n 大且 \(\hat p\) 不靠近 0 或 1,常见经验是 \(n\hat p \ge 10\) 且 \(n(1-\hat p) \ge 10\)。Agent 评测一般不满足。
- 前提是什么?和 rule of three 一样:每次试验独立、失败率相同。同一个 prompt 重跑 30 次,和 30 个不同用例各跑 1 次,含义不一样(概念 4 会讲)。
- 两个版本的区间重叠,能说没差别吗?不能直接下结论。区间重叠不等于差异不显著;如果两个版本跑的是同一批用例,应该用配对检验(McNemar),后面会学。
常见错误说法
❌ "挂了 2 次 / 30 次,失败率 6.7%":只报点估计不报区间,等于没说可信度。
❌ 拿双侧区间的上界跟 rule of three 的 3/n 比:口径不同。
8练习
9代码
手写一遍(面试写这个就够):
import math
def wilson(k: int, n: int, z: float = 1.96) -> tuple[float, float]:
"""k 次失败 / n 次试验的 Wilson 区间,z=1.96 对应双侧 95%。"""
if n <= 0 or not 0 <= k <= n:
raise ValueError(f"需要 0 <= k <= n 且 n > 0,收到 k={k}, n={n}")
p = k / n
denom = 1 + z**2 / n
center = (p + z**2 / (2 * n)) / denom
half = z / denom * math.sqrt(p * (1 - p) / n + z**2 / (4 * n**2))
return max(0.0, center - half), min(1.0, center + half)
print(wilson(2, 30)) # (0.0185, 0.2132)
print(wilson(0, 30)) # (0.0, 0.1135)
项目里直接用库:
from statsmodels.stats.proportion import proportion_confint
proportion_confint(count=2, nobs=30, alpha=0.05, method="wilson")
from scipy.stats import binomtest
binomtest(2, 30).proportion_ci(confidence_level=0.95, method="wilson")
公式显示依赖 KaTeX(CDN),断网时公式会显示成原始 LaTeX 源码,交互部分不受影响。