第 03 章
第 1 周:30 次挂了 2 次,失败率在什么范围?
有失败时怎么算置信区间:教科书公式错在哪,Wilson 区间怎么用反证法修好它。一段讲解视频,一个可以拖参数的互动演示。
rule of three 只能处理"一次都没挂"。实际跑评测,挂几次是常态:30 次挂了 2 次,失败率是 6.7% 吗?这只是一轮的运气。同一个 Agent 重跑一轮,可能挂 0 次,也可能挂 5 次。这一章讲怎么给失败率算一个诚实的区间。
讲解视频
互动演示
拖动跑的次数 n 和失败次数 k,对比三种方法算出的区间,再看它们的实际覆盖率。页面底部有自动判分的练习。
教科书公式错在哪
大部分人最先学到的是 Wald 区间:
$$\hat p \;\pm\; z\sqrt{\frac{\hat p(1-\hat p)}{n}}$$\(z\) 由置信度决定:90% 对应 1.645,95% 对应 1.96,99% 对应 2.576。根号那一项叫标准误(SE)。
这里偷了一步懒:标准误本该用真实的 \(p\) 算,但 \(p\) 未知,于是直接拿观测值 \(\hat p\) 代替。在 Agent 评测里,这一步会带来三个问题:
- 0 次失败时区间缩成一个点。\(\hat p = 0\) 让 SE 也等于 0,区间是 [0, 0],等于断言失败率就是 0。
- 下界会变成负数。30 次挂 2 次,算出来是 [−2.3%, 15.6%]。
- 名义 95%,实际远不到。\(p\) 小、\(n\) 不大时,区间真正罩住真实值的比例(覆盖率)会掉得很低。n = 30 时,p 越接近 0,覆盖率越接近 0:p = 0.5% 时只有约 14%。互动演示里的覆盖率曲线能看到它一路往下掉(50% 以下压在了图的底边)。
Wilson 的思路:还是反证法
Wilson 换了个问法,和 rule of three 是同一个套路:
对每个候选的失败率 \(p\),问一句:如果真实失败率是 \(p\),观测到 \(\hat p\) 算不算离谱?不离谱就留下,离谱就排除。留下来的 \(p\) 构成的范围,就是置信区间。
“离谱"指的是 \(\hat p\) 离 \(p\) 超过了 \(z\) 个标准误。关键在于这里的标准误用候选的 \(p\) 来算:
$$|\hat p - p| \;\le\; z\sqrt{\frac{p(1-p)}{n}}$$跟 Wald 唯一的区别就是根号里写的是 \(p\),不是 \(\hat 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$$抛物线开口向上,满足不等式的就是两根之间那一段。\(p(1-p)\) 在 0 和 1 处都等于 0,所以解出来的区间一定落在 [0, 1] 里,不会出现负数。
公式
把求根公式整理成"中心 ± 半宽”:
$$\text{中心} = \frac{\hat p + \frac{z^2}{2n}}{1 + \frac{z^2}{n}} = \frac{k + z^2/2}{n + z^2}$$$$\text{半宽} = \frac{z}{1 + z^2/n}\sqrt{\frac{\hat p(1-\hat p)}{n} + \frac{z^2}{4n^2}}$$两个读法:
- 中心不在 \(\hat p\),被往 50% 拉了一点。95% 时 \(z^2 \approx 4\),相当于凭空多加 2 次失败、2 次成功再算比例。样本越少,拉得越多。这也是"加二加四"速算法(Agresti–Coull 区间)的来历。
- 半宽的根号里多了 \(z^2/4n^2\)。所以就算 \(\hat p = 0\),区间也有宽度。
手算一遍: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%] |
结论:30 次挂 2 次,不能只说"失败率约 7%",真实失败率到 20% 都说得通。想让区间变窄,只能加样本量。
和 rule of three 的关系
令 \(k = 0\),Wilson 上界化简为 \(z^2 / (n + z^2)\)。比较前要先对齐口径:rule of three 是单侧 95%,对应 \(z = 1.645\);双侧 95% 区间的上界相当于单侧 97.5%,会更宽。
| n = 30,0 次失败 | 上界 | 说明 |
|---|---|---|
| rule of three:3 / n | 10.0% | 单侧 95% 的速算 |
| 精确法:1 − 0.051/n | 9.5% | 单侧 95%,不做近似 |
| Wilson(z = 1.645) | 8.3% | 单侧 95%,略乐观 |
| Wilson(z = 1.96) | 11.4% | 双侧 95%,口径不同 |
选法:0 次失败用 rule of three 或精确法;有失败用 Wilson。Wilson 底层仍是正态近似,在 k = 0 附近上界偏低。门禁这种宁紧勿松的场景,就用精确法(Clopper–Pearson)。
代码
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)
wilson(2, 30) # (0.0185, 0.2132)
项目里可以直接用 statsmodels.stats.proportion.proportion_confint(k, n, method="wilson"),或者 scipy.stats.binomtest(k, n).proportion_ci(method="wilson")。
面试追问
- 为什么中心不是 \(\hat p\)?相当于加了 \(z^2/2\) 次成功和 \(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 一样:每次试验独立,失败率相同。同一个用例重跑 30 次,和 30 个不同用例各跑 1 次,并不是一回事,这是后面独立性那一章要讲的。
- 两个版本的区间有重叠,能说没差别吗?不能。区间重叠既不能证明没差别,也不能证明有差别:两个 95% 区间有重叠,差异照样可能显著。正确做法是直接对差异做检验;两个版本跑的是同一批用例时,用配对检验(McNemar)。
常见错误说法
- “失败率有 95% 的概率落在 1.8% ~ 21.3% 之间”:真实失败率是固定值,95% 描述的是这套方法,不是这一个区间。
- “挂了 2 次,所以失败率是 6.7%”:只报点估计,不报区间,等于没交代这个数字有多可信。
- 拿双侧区间的上界去跟 3/n 比:两者口径不同,一个是双侧,一个是单侧。