Skip to content

p 值 0.03,这个功能就该上线吗 ​

两组完全相同的页面做 A/B 实验,按常规的 0.05 判断,每 20 次里有 1 次会得出「有显著差异」。如果实验期间每天打开看板看一眼、p 值一低于 0.05 就宣布结果,这个比例是每 5 次里 1 次。真实存在 1 个百分点提升的功能,每组 2000 人的实验 83% 的时候会告诉你「不显著」。

A/B 实验的统计结论,回答的问题比看上去窄得多。p 值是「假设两组没有差别,观察到这么大(或更大)差值的概率」;它不是「这个功能有效的概率」,也不是「结论出错的概率」。在这个定义之上,实验怎么做、数据怎么看、看几次,都会改变结论的可靠程度,而看板上那个数字不会告诉你这些。

本文用模拟来说明。每个场景把「做一次实验」重复几千次,数其中有多少次得出显著的结论。指标是转化率,检验是两比例 z 检验(双侧,显著性水平 0.05),随机种子固定,结果可以逐字复现。实验见文末。

一、5% 的含义:没有差别时,也有 5% 显著 ​

先做 A/A:两组的真实转化率都是 10%,每组 10000 人,重复 4000 次。203 次得到 p < 0.05,占 5.1%。

这就是显著性水平的定义:两组没有差别时,仍然有 5% 的实验会被判为显著。它是事先接受的误报率。由此可以推出几件事:

  • 一次显著的结果,可能就是那 5%。团队一年做 100 个没有效果的改动,会有 5 个左右显示显著;
  • p = 0.03 不表示「有 97% 的把握功能有效」。功能有效的可能性还取决于这类改动通常有多大比例真的有效,p 值里没有这个信息;
  • p = 0.03 和 p = 0.06 之间没有本质的界线,0.05 只是约定。

二、中途偷看:误报率从 5% 到 20% ​

同样的 A/A,但不等样本攒够,每进来一批用户就算一次 p 值,第一次低于 0.05 就停下来宣布结果:

只在结束时看 1 次5.1%中途看 5 次14.5%中途看 10 次20.2%中途看 20 次24.3%显著性水平 5%
图 1 · 两组完全相同的 A/A 实验,每组 10000 人,模拟 4000 次(固定随机种子)。只在结束时检验一次,5.1% 的实验被判为显著,这就是显著性水平 5% 的含义;每进来一批用户看一次、一显著就停,这个比例升到 14.5%—24.3%。p 值会随数据上下波动,看的次数越多,碰到一次小于 0.05 的机会越大
看的次数被判为显著的实验
只在结束时看 1 次5.1%
5 次14.5%
10 次20.2%
20 次24.3%

p 值会随着数据进来上下波动。只承诺在一个固定的时刻看,它低于 0.05 的概率是 5%;允许在很多个时刻里挑一个最低的,概率就大得多。「显著了就停、不显著就再跑几天」是同一件事的另一种说法。

做法:

  • 实验开始前定好样本量(或运行时长),到了再做判断;
  • 中途可以看数据是否异常(分流比例、报错、核心指标暴跌),但不据此宣布「胜出」;
  • 确实需要提前停止的,用为此设计的方法(序贯检验),它们在每次查看时使用更严格的门槛,把总的误报率控制在 5%。实验平台如果提供「随时可看」的结论,要确认它用的是这类方法。

三、样本量:实验之前就能算 ​

真实存在提升时,实验能检出它的概率叫功效(power)。它由三个量决定:基线转化率、想检出的最小提升、样本量。基线 10%、想检出提升到 11%、功效 80% 时:

text
每组样本量 ≈ (1.96 + 0.84)² × [p1(1-p1) + p2(1-p2)] / (p2 - p1)²
          = 7.85 × (0.09 + 0.0979) / 0.0001
          ≈ 14749

1.96 对应显著性水平 0.05(双侧),0.84 对应功效 80%。差值在分母上是平方:想检出的提升减半,样本量变成 4 倍。

检出真实提升的实验占比显著结果里观察到的平均提升每组 2000 人17.4%2.44每组 10000 人64.1%1.26每组 14749 人80.6%1.12真实值 1.00 个百分点功效 80%
图 2 · 真实提升是 1 个百分点(10% → 11%)。每组 2000 人时只有 17.4% 的实验能检出;而这些「显著」的实验观察到的平均提升是 2.44 个百分点,是真实值的两倍多:样本小时,只有碰巧抽到偏大差值的实验才过得了显著性门槛。样本量按公式取到 14749 人,检出率 80.6%,夸大也降到 1.12
每组样本量检出提升的实验显著结果里观察到的平均提升(真实值 1.00 个百分点)
200017.4%2.44
1000064.1%1.26
1474980.6%1.12

样本不够有两个后果。第一个是漏报:每组 2000 人时,真实有效的功能 5 次里有 4 次被判为「不显著」。第二个更隐蔽:显著的那些结果,效果被夸大了。样本小时误差大,只有碰巧抽到偏大差值的实验才能跨过显著性门槛,所以被筛选出来的都是高估的。按 2.44 个百分点去做收益预估,上线后看到的是 1 个百分点。

流量不够检出想要的提升时,可选的做法是延长实验、放大实验的改动幅度,或者接受这个实验只能发现较大的效果。跑一个功效 17% 的实验再解读结果,无论显著与否都得不到可靠的结论。

四、「不显著」不等于「没有差别」 ​

接着上面每组 2000 人的场景:82.8% 的实验不显著。这些实验的 95% 置信区间平均宽 3.8 个百分点,也就是典型的结果类似「提升 1.0,区间 -0.9 到 +2.9」。这个区间同时包含「没有效果」和「提升接近 3 个百分点」,实验没有能力区分它们。

把这种结果汇报成「实验证明没有差别」是错的,准确的说法是「没有检出差别,区间是多少」。区间的含义也可以用模拟验证:4000 次实验里,95% 置信区间包含真实差值的占 95.0%。

汇报实验结果时给出差值和置信区间,而不只是「显著 / 不显著」。区间窄且不含 0,结论可靠;区间很宽,说明样本不够,结论是「不知道」。

反过来,样本量极大时,很小的差别也会显著。统计显著只说明「差值不太可能是 0」,值不值得上线要看差值本身有多大、成本多高。事先定一个「小于它就不值得做」的最小提升,比事后争论更有用。

五、分析单位要和分流单位一致 ​

按用户分流,每个用户可能访问多次。把每次访问当作一个独立样本来检验,样本量看起来大了好几倍。模拟一个 A/A:每组 2000 个用户,每人访问次数不等,每个用户有自己的转化倾向。

检验方式被判为显著的实验
把每次访问当作独立样本17.9%
按用户(是否转化过)4.6%

同一个用户的多次访问不是独立的:爱买的用户每次都更可能买。按访问计算时,检验以为自己有几万个独立样本,把误差估小了,于是把用户之间的自然差异当成了组间差异。

分流按什么单位,分析就按什么单位。按用户分流,就先把数据聚合到每个用户一行,再比较两组。这和 SQL 里「一行代表什么」是同一个问题,见 JOIN 之后,合计从 480 变成了 880。具体数值取决于用户行为的分布,这里的 17.9% 只说明方向。

六、指标多了,总有一个显著 ​

一次实验通常会看很多指标。A/A 实验同时看 20 个互不相关的指标:

做法至少一个指标显著的实验
每个指标都按 0.05 判断63.9%(理论值 1 - 0.95²⁰ = 64.2%)
显著性水平除以指标数(0.0025)4.8%

没有任何效果的改动,三分之二的时候能找到一个「显著变好」的指标。按人群、渠道、设备拆开看也是一样的效果,每多一个切片就多一次机会。

实验开始前指定一个主要指标,用它做决策。其余指标用来理解发生了什么、检查有没有副作用;要用它们下结论,就做校正(除以指标数是最简单的一种,偏保守),或者把它当作下一个实验的假设。

七、不要先按天汇总再检验 ​

一种常见的做法是把每组每天的转化率算出来,得到两列各 10 个数,再做 t 检验。模拟真实提升 1 个百分点、每组每天 1000 人、跑 10 天,每天的基础转化率不同(周中周末有 ±3 个百分点的波动,两组一起波动):

检验方式检出提升的实验
按用户做两比例检验(每组 10000 人)63.5%
每组压成 10 个日转化率再做 t 检验0.1%

压成日转化率之后,每组只剩 10 个数,日与日之间的波动(±3 个百分点)远大于要检出的差别(1 个百分点),提升被淹没了。同一天里两组的波动是同步的,这个信息在分别求两列的方差时被丢掉了。

用原始粒度(分流单位)的数据做检验。按天看趋势图没有问题,但不要用它做显著性判断。

八、检查清单 ​

实验开始前:

  1. 写下假设、一个主要指标、想检出的最小提升。
  2. 算出样本量和需要运行的时长;流量不够就调整预期。
  3. 确定分流单位,分析时用同一个单位。
  4. 至少跑满一个完整的周期(通常是一周),覆盖周中和周末。

实验运行中:

  1. 检查分流比例是否与设定一致。50:50 的实验实际分成 52:48,说明分流或埋点有问题,结果不能用。
  2. 看异常,不看胜负。

实验结束后:

  1. 报告差值和置信区间。
  2. 「不显著」时看区间宽度,区分「没有效果」和「样本不够」。
  3. 次要指标和分人群的结果,当作线索而不是结论。
  4. 小样本上得到的大提升,按「很可能被夸大」来预估收益。

模拟的是理想条件:用户相互独立、转化率稳定。真实实验还有新奇效应、用户之间相互影响、分流故障,这些问题统计检验本身发现不了。


配套实验

参考资料

文章以 CC BY-NC-SA 4.0 授权 · 代码片段以 MIT 授权