M6 配对显著性检验
Day 167 把 A/B 实验设计好、双模型各跑一遍、落了两组 per-task transcript。
阶段: B17 · outcome 指标仪表盘 + A/B(Day 161-170) 标签: #statistical-significance #paired-test #bootstrap-ci #eval-rigor
今日导引(由浅入深)
Day 167 把 A/B 实验设计好、双模型各跑一遍、落了两组 per-task transcript。 今天回答那个真正决定「能不能写进作品集」的问题:这个差异,统计上站得住吗? 在 B1→B18 能力曲线上,这一步是整套 eval 严谨度的「试金石」——它把「V4-Pro 看起来比 V4-Flash 强 10 个点」这种朴素观察,逼成「Δ +10.3pp,95% CI [0, 20.7],N=29,不显著」这种诚实结论。 今天的最小可判定产出是:对 167 的两组结果算出 Δ均值与置信区间,并得出本 block 最重要的一条 eval-rigor 教训——方向性好 ≠ 统计显著。
1. 机理精读
配对数据要用配对检验,不能用独立两样本检验。 Day 167 的设计让 A、B 跑同一批任务,于是每个任务都有一对结果 (a_i, b_i)。 正确的检验对象是成对差值 d_i = a_i − b_i,而不是把 A 的所有分和 B 的所有分当两堆独立样本比。 配对检验有两条主流路径:
- paired t-test:假定成对差值 d_i 近似正态,检验 mean(d) 是否显著偏离 0。小样本 + 0/1 二值数据时正态假定很弱,慎用。
- Wilcoxon signed-rank:非参数,对差值的符号和秩排序,稳健于偏态和小样本,不假定正态。N<30 或数据偏态时优先它。
必须同时报 p 值和效应量(Δ均值 + CI),只看 p 值会误判。 p 值只告诉你「差异是否可能由随机产生」,不告诉你「差异有多大」。 一个 N 极大的实验可以把 +0.5pp 的微小差测成「p<0.001 显著」,但这点差毫无业务意义; 反过来 N 小的实验可以有很大的真实 Δ 却 p>0.05。 效应量(Δ均值)回答「多大」,CI 回答「这个估计有多准 + 是否跨 0」。 所以 outcome 报告的标准句式是「Δ = X pp,95% CI [lo, hi]」,而非只有一个 p。
本仓用 bootstrap CI 而非解析公式算区间,原因是 0/1 二值 + 小样本下解析正态近似不可靠。 Bootstrap 的逻辑:把成对差值 d 这个向量「有放回地重采样」很多次(本仓默认 2000 次),每次算一个 mean,得到 mean 的经验分布,取 2.5 / 97.5 百分位作 95% CI。 这不假定差值正态,对小样本更稳。
显著性的判据是「CI 是否跨过 0」。 若 95% CI 整段在 0 以上 → A 显著更好; 整段在 0 以下 → B 显著更好; 只要 CI 跨过 0(下界 ≤ 0 ≤ 上界)→ 不显著。 本仓真实结果 CI = [0.0, 20.7],下界恰好触 0——这是「不显著」最典型的形态:方向是正的(点估计 +10.3pp),但区间没把 0 排除掉。
这就是本 block 的核心教训:directionally better ≠ statistically significant。 N=29、26 个 tie,意味着真正提供区分信息的任务只有 3 个(3 wins / 0 losses)。 这么少的有效信号撑不起一个把 0 排除的窄区间。 要把 Δ+10.3pp 这个差测显著,估计需要 ~70 task 才有足够 power(明天 Day 169 仍会强调这一点)。 诚实地写「不显著」,比硬把方向性差包装成「赢」,更符合这套笔记的严谨标准。
为什么 N=29 不够?用 requiredNForDelta 反推。 所需配对样本量的正态近似是 n = ((z_{α/2}+z_{β})·sd_diff / |Δ|)²。
代入 alpha=.05 双侧(z≈1.96)、power=.8(z≈0.84),系数和 ≈2.80。
本仓 Δ≈0.103。
成对差值的 SD 受「26 个 tie(差值 0)+ 3 个 win(差值 1)」支配——差值向量大量为 0、少量为 1,sd_diff 不小(相对 Δ 而言)。
把这个 sd_diff 代进去,所需 n 落在 ~70 量级。
这就是「需 ~70 task 才有 power」的定量来源,而非拍脑袋。
与 GRPO(arXiv:2402.03300)的关系:GRPO 的组内相对优势(advantage)本质也是「同 prompt 内配对比较」,与这里「同任务内配对差值」共享降方差直觉; 但 GRPO 是用于训练信号,今天用于离线显著性判定——同一统计直觉,两个用途。
2. 推导 / 手算 / 代码走读
今天 seed 说「A/B 的统计已内置在 src/agent/eval/abCompare.ts」,底层是 src/agent/eval/stats.ts。
走读真实实现:
pairedBootstrap(a, b, opts)(stats.ts):先if (a.length !== b.length) throw(强制配对等长),再const diffs = a.map((x, i) => x - b[i]!)(成对差值)。iters = opts.iters ?? 2000,rng = opts.rng ?? Math.random(RNG 可注入 → 单测可确定性复现)。- 重采样核心:循环
iters次,每次内层for (let i = 0; i < n; i++) acc += diffs[Math.floor(rng() * n)]——有放回地从 diffs 里抽 n 个求和,means.push(acc / n)。最后means.sort(...),返回{ deltaMean: mean(diffs), ci95: [percentile(means, 2.5), percentile(means, 97.5)], n, iters }。这就是 95% bootstrap CI。 percentile(sorted, p):线性插值分位,idx = (p/100)*(len-1),lo/hi = floor/ceil(idx),加权sorted[lo]*(1-w) + sorted[hi]*w。单元素直接返回,便于小样本不崩。mean/sd(stats.ts):sd用样本标准差(分母n-1),xs.length < 2时返回 0——这正是requiredNForDelta在sdDiff <= 0时返回 2 的兜底前提(n<2 时 sd=0,所需 N 退化为最小 2)。requiredNForDelta(delta, sdDiff):算「要检出 delta、给定差值 SD,alpha=.05 双侧、power=.8 所需的配对 N」。正态近似公式n = ((z_{α/2} + z_{β})·sd / |delta|)²,代码里zAlpha = 1.959963985、zBeta = 0.841621234,return Math.max(2, Math.ceil(...))。delta=0 时返回Infinity(差为 0 永远测不出)。这就是「~70 task 才有 power」的来源工具——把真实 Δ 和差值 SD 代进去就得到所需 N。abCompare(Day 167 已走读)调pairedBootstrap(av, bv, opts)拿deltaMean与ci95,连同 wins/losses/ties 一起返回。scripts/ab-compare.ts的 verdict 逻辑:r.ci95[0] > 0 ? 'A significantly better' : r.ci95[1] < 0 ? 'B significantly better' : 'not significant (CI crosses 0)'——代码层面就用「CI 跨 0」判显著,与机理一致。
手算验证「CI 跨 0 = 不显著」:本仓 deltaMean = +0.103(+10.3pp),ci95 = [0.0, 20.7]。
- 下界 = 0.0,不满足
r.ci95[0] > 0(严格大于); - 上界 20.7 不满足
r.ci95[1] < 0; - → 落到第三分支
'not significant (CI crosses 0)'。
点估计为正、区间含 0,正是教科书式的「方向性好但不显著」。
再对比一个反事实:若同样 Δ+10.3pp 但 N 扩到 ~70、tie 比例下降,bootstrap 的 mean 分布会收窄,CI 可能变成 [3.1, 17.5] 这种整段 >0 的区间——那时下界 >0 成立,verdict 才翻成「A significantly better」。
同一个点估计,N 决定它是不是显著,这就是 power 的直观含义。
诚实校准:seed 提到「独立 paired-t/Wilcoxon 模块若新增可加单测验公式」——本仓当前 stats.ts 实现的是 bootstrap CI + 所需样本量公式,尚未单独实现 paired t-test / Wilcoxon signed-rank 函数。
机理小节讲它们是为补全方法论谱系;
若要落地,应作为新模块加单测,不得声称已存在。
一个易忽略的实现细节:bootstrap 的 iters(默认 2000)影响 CI 估计的稳定性,但不影响 CI 的「宽度」本质。
增大 iters(如到 10000)只让 2.5/97.5 百分位的蒙特卡洛噪声更小,CI 边界更稳定;
它不会把一个跨 0 的区间变成不跨 0——区间宽度由数据(N 和差值分布)决定,不由重采样次数决定。
所以「CI 触 0 不显著」加更多 iters 也救不了,唯一解是增 N。
单测里要固定 opts.iters + opts.rng 两者,才能得到确定性可断言的 CI 边界(只固定 rng、不固定 iters,不同 iters 下边界会微变)。
3. 今日实战
- 取 Day 167 的两组 per-task 0/1 向量,调
pairedBootstrap(av, bv)算deltaMean+ci95(或直接看abCompare返回的deltaMean/ci95)。 - 用
stats.ts的requiredNForDelta(0.103, sdDiff)(sdDiff 取成对差值的sd())估算检出 Δ+10.3pp 所需的配对 N,验证「~70 task」量级。 - 给
pairedBootstrap写/补单测:注入固定 RNG(opts.rng),用已知样本断言ci95的下界/上界落在期望区间——这是「固定输入断言 CI 边界」的可测做法。 - 在 A/B 报告里同时记 Δ均值、95% CI、N、
significant标志,不只记一个 p 值。
为什么本仓选 bootstrap 而非先上 Wilcoxon:二值(0/1)成对差值只有 {−1, 0, +1} 三种取值,且 26/29 是 0。
Wilcoxon signed-rank 在「大量并列 0 差值」时秩处理会退化(零差通常被剔除,剩 3 个非零差秩检验功效极低),paired t-test 的正态假定更是直接破产。
bootstrap 对这种离散、零膨胀、小样本的分布最稳健——它不假定任何参数形式,直接重采样经验分布。
所以本仓的工程选择是对的:对二值小样本,bootstrap CI 是首选,Wilcoxon/t-test 作方法论对照而非主用。这也是为什么 stats.ts 先实现了 bootstrap 而把 paired-t/Wilcoxon 留作可选新增。
4. 今日实测 / 产出
- 真实结果:Δ +10.3pp,95% CI [0.0, 20.7],N=29 → directionally better 但在 N=29 不显著(CI 下界触 0)。
- 这是核心 eval-rigor 教训:方向性好 ≠ 统计显著,需 ~70 task 才有 power。
- 统计函数为已测纯函数(
pairedBootstrap/percentile/requiredNForDelta在 423 绿测内);独立 paired-t / Wilcoxon 模块若新增可加单测验公式(当前未实现)。
5. 常见误区 / 陷阱
- N<30 只报 p 值不报 CI:本仓 CI[0,20.7] 正说明问题——只报 p 会丢掉「区间触 0」这条关键信息。小样本必须报 CI。
- 把方向性差当显著:点估计 +10.3pp 看着不小,但 CI 含 0 就是不显著。硬包装成「赢」违反严谨标准。
- 用独立两样本检验比配对数据:丢掉配对带来的降方差,CI 会更宽,更难显著。
- 小样本裸用 t-test:0/1 二值 + N<30,正态假定弱,应优先 Wilcoxon + bootstrap,而非裸 paired t-test。
- 靠加 iters 救不显著:增大 bootstrap 重采样次数只降蒙特卡洛噪声,不缩窄 CI 本质宽度;区间宽度由 N 和数据分布定,触 0 只能靠增 N。
- 只报点估计省略 CI/N:「V4-Pro 比 V4-Flash 高 10 个点」单独一句没有 CI 和 N,读者无法判断可信度——outcome 报告三件套(Δ、CI、N)缺一不可。
把这条 block 的核心教训再钉一次:directionally better ≠ statistically significant。本仓 Δ+10.3pp 方向对,但 N=29、CI[0,20.7] 触 0 不显著,诚实结论是「方向性更好,需 ~70 task 取 power」,绝不包装成「V4-Pro 显著胜出」。这是 eval-rigor 与营销腔的分水岭。
6. 学习资源(每条带 YYYY-MM)
- DeepSeekMath / GRPO 论文,arXiv:2402.03300(2024-02)——配对/组内相对范式,降方差直觉同源。
- Anthropic, "Demystifying evals / A statistical approach to model evaluations"(2026-01)——bootstrap CI 与显著性在模型评测中的标准用法。
- 本仓
src/agent/eval/stats.ts源码(AICAP-180 B3,Pillars P2/P5)——pairedBootstrap/percentile/requiredNForDelta实现(2026-06)。 - Efron & Tibshirani, "An Introduction to the Bootstrap"(经典,作打底)——bootstrap CI 原理;非主线,仅作通识背景。
SOTA检查 (2026-06 更新)
- 当前主流:bootstrap CI / 配对检验仍 SOTA。小样本优先 Wilcoxon signed-rank + bootstrap,而非裸 t-test。
- 2026 LLM-eval 方法论的共识(Anthropic 2026-01 等):模型对照必须报区间而非单点;配对设计 + bootstrap 是离线评测的默认起手式,这一点近 12 个月未被取代。
- 避免:在 N<30 时只报 p 值不报 CI——本仓 CI[0,20.7] 正是反面教材;把 CI 跨 0 的方向性差宣称为显著。
- 过时黑名单:用解析正态近似给 0/1 二值小样本算 CI(不稳);模型 id 引 legacy
deepseek-chat/-reasoner(2026-07-24 退役)。 - 下次复查:若新增 paired-t/Wilcoxon 模块,须配单测验公式;B18 全局 SOTA 复核时复盘「~70 task 取 power」是否已补任务集。
衔接
- 昨天:Day 167 — M6 A/B 实验设计(配对、指标、样本量;V4-Pro vs V4-Flash 各跑一遍)。
- 今天:配对显著性检验——bootstrap 95% CI 判「CI 跨 0 = 不显著」,真实 Δ+10.3pp CI[0,20.7] N=29 不显著,核心教训「方向性好 ≠ 显著」。
- 明天:Day 169 — A/B 落仪表盘(把赢家/Δ/CI/N/significant 接进 dashboard snapshot 的 experiment 字段,诚实记录「不显著」)。