【背景】
做了三年数据分析与指标体系,我见过至少四家团队(包括自己前东家)在 A/B 实验的"判定节奏"上完全是靠手感:
- 实验上线后,数据同学每天早上刷一次看板;
- 某天看到 p 值 < 0.05,群里喊一声"显著了,可以推全量";
- 实际上实验才跑到设计样本量的 60%,剩余流量还在进。
这在统计学里叫 peeking problem(偷看问题):反复用同一份数据做假设检验,每次都有 5% 的"误判"概率,但你看了 20 次,至少误判一次的概率就飙到 ~64%(1 - 0.95^20)。换句话说,你"显著了"的结论,有将近三分之一的概率是运气。
补充一个对照表,让"偷看代价"更直观(α=0.05、H0 为真、每次独立检验的最坏情形):
| 偷看次数 k | 至少一次假阳性的概率 1-(0.95)^k | |-----------|-------------------------------| | 1(跑满再看一次) | 5.0% | | 3(每周看一次) | 14.3% | | 7(每天看一次跑一周) | 30.2% | | 14(每天看两次跑一周) | 51.6% | | 20(每天看两次跑 10 天) | 64.2% | | 30(每小时刷一次看板 30 次) | 78.6% |
注意:这是最坏情形(每次检验独立、样本量不变),实际上序贯检验中各次 look 的样本量递增,相关性会让真实假阳性率略低于上表——但量级不变,偷看次数翻倍,假阳性率不是线性增长而是加速增长。
而另一边的极端是:有些团队坚持必须跑满预设天数才能看,哪怕第 3 天数据已经一边倒,也要等到第 7 天——理由是"防止偷看"。代价是:如果新版本真的有明显回归(比如 P99 飙升),你也要等 4 天才能止损。
【常见分歧 / 几种做法】
我梳理了一下业内我接触到的三种主流做法:
-
固定样本量 + 一次判定(Frequentist fixed-horizon)
- 事前算好所需样本量(power analysis),跑满后看一次 p 值。
- 优点:统计性质干净,false positive 严格控制在 α。
- 缺点:实验周期长,中途不能止损;对"非劣效"或"早停"场景不友好。
- 典型用户:偏保守的金融、医疗团队。
-
序贯检验 / Alpha-spending(Sequential Testing)
- 用 O'Brien-Fleming、Pocock 或 Lachin-Freidman 等 alpha 分配函数,允许在多个"look"时点做检验,但每次的判定阈值动态收紧。
- 优点:可以早停(both 方向:有效停、无效停),false positive 仍受控。
- 缺点:实现复杂(需要预设 look 次数或连续监控),很多开源 AB 平台不支持;团队需要理解 alpha 分配函数的含义。
- 典型用户:大厂实验平台(Optimizely、VWO 的 sequential mode,字节/美团的实验平台都有类似能力)。
-
贝叶斯 A/B(Bayesian / Probability of Improvement)
- 不看 p 值,而是算"新版本优于旧版本的概率"(P(improvement)),或期望损失(Expected Loss)。
- 优点:解读直觉("有 93% 概率新版更好"),天然支持 anytime stopping,不需要预设样本量。
- 缺点:先验选择有主观性;对"方向正确但幅度极小"的场景可能给出"93% 概率更好"但业务上无意义的结论;团队需要校准对概率数字的直觉。
- 典型用户:增长团队、产品实验偏多的公司。
【我的倾向与理由】
我倾向于 "固定样本量做主判定 + 序贯检验做安全网" 的混合策略:
- 主判定:跑满预设样本量后,用固定样本量的 Frequentist 检验做最终决策(p < 0.05 或贝叶斯 P(improvement) > 0.95,两者选一个作为团队标准)。
- 安全网:在实验中间设置 1-2 个"止损检查点"(比如第 3 天、第 5 天),用序贯检验的 alpha-spending 判定。如果某个指标(如 P99、错误率)显著劣化,允许提前止损——这不是"偷看",而是预设了检查点和判定规则的安全机制。
- 为什么不纯用贝叶斯:不是说贝叶斯不好,而是我观察到很多团队对"93% 概率更好"这个数字的解读会滑向"93% 的把握可以推全量",把概率和决策脱钩了。Frequentist 的"拒绝 / 不拒绝 H0"虽然不直观,但至少把"证据不足"和"证据充分"分开了。
核心原则:判定规则必须在实验开始前写死,而不是数据出来后再定。 这是避免偷看问题的根本。
【落地实现提示】
- R 语言:
gsDesign包的hPower()可以直接算 O'Brien-Fleming 边界。设 2 个 look(第 3 天 + 第 7 天),hPower(K=2, alpha=0.05, beta=0.2)会给出每个 look 的 z 临界值(约 2.498 和 1.960),比"每次都用 1.96"严格得多。 - Python:
statsmodels没有原生序贯检验,但scipy.stats.norm.ppf(1 - alpha_spent)可以手动实现。推荐用rpy2调 R 的gsDesign,或者直接用alwaysvalid库(支持 mSPRT,即 always-valid p-value,不需要预设 look 次数)。 - SQL 层:如果你们的实验平台是自研的,在判定表里加一列
look_number和alpha_spent_so_far,每次 look 时查alpha_spent_so_far来决定本次的 p 值阈值,而不是写死 0.05。 - 最简单的"土办法":如果团队没有序贯检验能力,至少做到"止损检查点只允许判负不允许判正"——即第 3 天看数据,如果 P99 劣化 >20% 就停(这是安全动作,不需要精确的统计阈值),但如果正向指标"看起来显著",仍然等到跑满才做正向判定。这比"每天刷看板看到 p<0.05 就推"安全得多,虽然不够优雅。
【补充:序贯检验落地时我踩过的两个实操失败模式】
之前只讲了"该用什么方法",没讲"用对了方法但工程实现上还是会翻车"的两种典型情况,补上:
失败模式 1:样本计数器被 bot / 重放流量污染,I(t) 虚高
信息分数 I(t) = n(t) / n_target 的前提是 n(t) 是"有效实验样本量"。但很多团队的 n(t) 直接取自网关的 request 计数——如果实验期间撞上一次爬虫高峰或压测误打,n(t) 会突然膨胀 2-3 倍,I(t) 直接跳过 0.5 的 look 点到 0.8。此时:
- OBF 的 alpha 分配是按"恰好跨到 0.5"设计的,跳到 0.8 后你实际消耗的 alpha 比设计值大(OBF 前段 alpha 分配少、后段多,跳过中间段等于"后段 alpha 提前花");
- 更隐蔽的是:bot 流量的 effect size 和真实用户不同(通常更极端),如果 bot 恰好落在实验组,会人为放大 effect size,让"提前显著"变成"真显著"——你以为序贯检验保护了你,实际上它只是提前触发了一次被污染的显著判定。
我的修复:n(t) 的口径从"网关 request 数"改成"通过去重 + 异常流量过滤后的有效 session 数",并在 I(t) 计算时加一条硬规则:if I(t) - I(t-1) > 0.15, flag_this_look_as_anomalous,flag 后该 look 的判定阈值在 OBF 基础上再收紧 10%(即 z 阈值 ×1.1)。不完美,但比"流量污染后照常判显著"安全。
失败模式 2:"止损检查点只判负不判正"的土办法,在业务方压力下 3 周内就会被绕过
我前东家就是这条路线:写了 SOP 说"检查点只能判负",但第 3 周产品经理就找到了绕过方式——他把"正向判定"改名为"中期数据 review",拉了一个 30 分钟的会,会上"讨论"了正向指标并"口头决定"提前推全量。事后没人能证明这个决策违反了 SOP,因为 SOP 只约束了"系统判定",没有约束"人工讨论"。
我的教训:如果团队的序贯检验能力不足以支撑严格的 alpha-spending,那么"土办法"的约束力取决于执行机制而不是文档。具体做法:
- 把"检查点只判负"写进实验平台的代码逻辑(正向指标在检查点时不显示 p 值,只显示"样本量不足,请等待"),而不是写在 wiki 里;
- 如果平台改不了,至少把"正向判定"的权限从数据分析师手里收走,交给"实验 owner"(通常是 PM),并且 PM 推全量时必须填一个"提前推全量理由"表单(哪怕只有一行字),留痕。留痕不是为了惩罚,是为了让绕过成本从 0 变成 30 秒——30 秒的摩擦足以让大部分"我觉得差不多了"的冲动被拦住。
【想听大家聊的】
- 你们团队的 A/B 实验判定流程是什么?是"跑满 N 天看一次"还是"边跑边看、显著就停"?有没有出过因为偷看导致误推全量的事故?
- 如果你们用的是序贯检验或贝叶斯方法,alpha-spending 函数 / 先验分布是怎么选的?有没有踩过"先验太宽 / 太窄"的坑?
- 对于"非核心指标"(比如一个辅助 UV 指标),你们是否也要求同样的统计严谨度?还是允许"方向对就行"?
- 有没有人在用"最小可检测效应(MDE)"来反向决定实验时长?MDE 设多大算合理——是业务方拍一个数,还是有更系统的推导方式?
欢迎带具体场景来聊,哪怕只是"我们就是看了 3 天觉得差不多就推了"也行——我想听听不同规模团队在统计严谨度和业务节奏之间的实际取舍。