上周一个做增长的朋友把测试报告甩到我桌上说这次改版“统计显著”了p 值 0.03可以全量推了吧。我随口问了三句这个实验原计划跑多久、中间你看过几次数据、0.03 是双尾还是单尾。他愣了两秒反问我这些重要吗。这一问一答基本就是统计显著性在真实工作里的处境——它是被引用最多、被理解最少的一个数字很多人把它当成“结论合格证”但它实际回答的问题比大家想的要窄得多也苛刻得多。p 值讲的从来不是“你的改动有多厉害”而是在“什么都没发生”的前提下你看到眼前这组数据或更极端数据的概率有多小。这篇文章就是想把这件事彻底讲透p 值到底在检验什么、显著性水平是谁定的、样本量和功效怎么倒推、为什么“显著”经常和“重要”是两码事、以及实操里最容易踩的那些坑。不管你是刚接触假设检验的学生还是天天看 A/B 测试报告的产品、运营、数据分析同学看完都应该能自己算一遍、也能在评审会上问出对的问题。1. 统计显著性到底在显著什么先把问题问对1.1 一次评审会上的三个追问我参加过很多次这种评审有人投出一页 PPT两组数字并排A 组 10%B 组 12%底下小字写着 p0.03然后会议室里的默认反应是“成了”。但如果把这份报告拆开看它至少藏了三个没有交代的前提第一这个 p 值是拿哪个检验算出来的比例 z 检验、卡方、还是 Fisher 精确检验不同检验在小样本下结果能差出一截第二检验是单尾还是双尾同样一组数据单尾的 p 值通常是双尾的一半0.03 和 0.06 可能就是“上线”和“再等等”的区别第三也是最关键的——这个实验中途被查看过几次如果看了五次才等到 0.03那这个 0.03 就已经不是原始意义上的 p 值了。我那位朋友后来承认这个实验原本计划跑两周但第五天看到曲线“有戏”就提前终止了后面又补了一周数据凑数。这种操作在行业里极其常见它带来的问题不是“造假”而是把一个设计好的固定样本检验悄悄变成了一个多重检验问题。你以为自己只做了一次检验实际上你在第五天、第六天、第七天各做了一次每一次看到“不显著就再等等”的决定都在抬高最终出现假阳性的概率。所以这篇东西的起点不是公式而是提问方式。你得先问清楚这个数字是在什么假设下、用什么方法、看了几次数据算出来的。问不清这三件事p 值就只是一个装饰性的小字。1.2 p 值的严格定义以及定义里的三个关键词把定义摆出来p 值是在原假设为真的前提下观察到当前样本结果或比当前结果更极端的结果的概率。这句话短但每个词都有分量拆开看是三个关键词。第一个关键词是“在原假设为真的前提下”。这是一个条件概率条件就是“假设两组没有差异”或者“假设这个变量和结果无关”。很多人读这句话时会自动把它反转成“原假设为真的概率”这是最常见也最致命的误读。p0.03 不等于“原假设只有 3% 的概率成立”它说的是“如果原假设成立出现这种数据的概率是 3%”。这两句话在逻辑上完全不同前者是关于假设的概率后者是关于数据的概率而频率学派这套框架只对后者负责。第二个关键词是“或比当前结果更极端”。这就是所谓“尾部概率”的来源。你观察到的只是一个点但 p 值算的是一条尾巴也就是所有“比现在这个结果更偏离原假设”的可能情况加起来的概率。这也是为什么检验统计量的分布形状那么重要——t 分布、正态分布、卡方分布尾巴的厚度不一样同样一个统计量算出来的 p 值就不一样。第三个关键词是“概率”而且这个概率是关于数据的。它衡量的是数据的稀有程度不是效应的大小不是结论的可靠程度也不是结果可重复的概率。一个效应巨大但样本极小的实验p 值可能很大一个效应微小但样本极大的实验p 值可以小到 1e-10。这一点后面还会反复提到。提示把定义背下来不算理解能用一句大白话复述才算。我的版本是——“假如这个世界根本没变化我抽到这么离谱的一批样本概率有多大”。1.3 为什么它反直觉无罪推定的逻辑假设检验的整套逻辑其实是照搬法庭的。法庭上不证明“无罪”只判断“现有证据是否足以推翻无罪推定”。原假设就是那个“无罪推定”它默认“没有差异”“没有效果”“这个变量没用”。你要做的不是证明它对而是看手上的证据够不够把它的台子掀了。这个结构决定了三件事。第一你永远无法“证明”原假设为真只能“没有足够证据拒绝它”。这就像法庭判无罪不等于确认清白只是证据不足。很多报告里写“证明了 A 和 B 没有差异”这是错的正确的说法是“在当前的样本量和效应量下没有检测到统计学显著的差异”。第二拒绝的门槛是人设的不是自然给的。α0.05 不是物理常数它是一个约定俗成的容忍度——允许自己有 5% 的概率冤枉好人。你要把它理解成一种成本权衡而不是真理的分界线。第三证据的强度取决于样本。同样是“B 比 A 高 2 个百分点”100 人一组的实验和 10000 人一组的实验p 值能差两个数量级。所以任何只报 p 值、不报样本量和效应量的报告信息都是残缺的。这种“反证法”结构天生反直觉因为人的大脑习惯正向推理看到 12% 比 10% 高就想直接得出“B 更好”。而假设检验要求你反过来想如果两者其实一样我有多大可能看到这个差距。这个思维转弯是新手和老手最明显的分水岭。1.4 一张表看清 p 值不是什么负面清单比正面定义更好记我整理了一张常见的误读对照表基本上每个做数据的人都至少踩过其中三条。常见说法是否成立正确的表述p0.03 表示原假设成立的 probability 是 3%错原假设成立时出现当前或更极端数据的概率是 3%p0.05 说明效应很大错p 值只反映“相对于噪声的偏离程度”效应大小要看差值本身p 值大说明两组一样错只能说没有足够证据拒绝可能是真没差异也可能是样本不够p0.05 和 p0.049 有本质差别错阈值是人为划的0.049 和 0.051 的实际信息量几乎相同1-p 就是结论为真的概率错这是把条件概率反过来了贝叶斯因子才能谈这种“假设的概率”p 值小说明结果可重复错可重复性还取决于样本量、效应量、实验条件和偏倚控制双尾 p 值除以 2 就是单尾有条件成立仅当效应方向与预期一致时成立方向相反时不能这么换算显著就等于业务上值得做错还要看提升幅度、实现成本、长期影响和副作用这张表里最容易翻车的是第一行和最后一行。第一行是概念性错误会污染所有下游判断最后一行是决策性错误会让团队为一个统计上显著、业务上无感的改动投入大量资源。举个例子某内容平台做过一次按钮颜色测试样本量到了几百万p 值小到几乎可以忽略但点击率只提升了 0.02 个百分点折算下来对核心指标的影响还不如一次运营活动。这种情况在超大样本的业务里太常见了——当样本足够大时任何微小的差异都会变得“显著”因为标准误随着样本量下降统计量自然上去。2. 显著性检验的骨架假设、α、两类错误与功效2.1 四步流程一步都不能省不管用什么工具一个完整的假设检验都跑不出这四步顺序也不能乱。第一步明确原假设 H0 和备择假设 H1。这一步决定了你后面所有的计算方向也决定了解读口径。H0 通常是“没有差异”“没有关联”“系数为零”这类保守陈述H1 则是你想验证的方向。第二步选检验统计量并确定它在 H0 下的分布。比例数据用 z 检验或卡方均值比较用 t 检验小样本分类数据用 Fisher 精确检验分布未知可以用置换检验。选错检验不会让结果变得“差不多”在小样本或者极端比例下不同检验的 p 值可以差出好几倍。第三步根据数据算出统计量的观测值再换算成 p 值。换算的过程就是查分布表或者调用函数本质上是在问“这个观测值在 H0 的分布里处于多靠边的位置”。第四步拿 p 值和事先定好的 α 比较做出拒绝或不拒绝的决策同时报告效应量和置信区间。第四步里“事先定好”这四个字很关键α 必须是实验开始前就写进方案里的而不是看到 p0.06 之后改成 0.1。这四步看着机械但每一步都有可以操作失误的地方。我见过最典型的失误是第二步和第四步有人用卡方检验算出一个 p 值又用 t 检验算出一个然后挑小的那个报也有人在报告里同时写“p0.05”和“接近显著”把 α 当成了可以讨价还价的东西。2.2 原假设怎么写决定了你后面所有结论原假设写错后面全废。这里有三个实操层面的讲究。第一H0 必须包含等号。写成“H0: μ1 μ2”或者“H0: p1 ≤ p2”都行但不能写成“H0: μ1 μ2”因为 p 值的计算需要一个明确的参照点。这个参照点就是“没有差异”的那个世界。第二H0 和 H1 必须互斥且穷尽。很多新手会写成 H0: 两组相等H1: B 组大于 A 组这就漏掉了“B 组小于 A 组”的情况。漏掉的部分会直接影响单双尾的选择也会影响结论的完整性。第三也是最容易被忽略的一点H0 要写得足够具体具体到能算出概率。比如“转化率没有变化”就不如“两组的真实转化率都等于 10.5%”好用因为后者给了你一个明确的参数值可以直接代入二项分布算概率。在业务场景里我通常建议把假设写成带方向的形式但检验仍然用双尾。原因是方向性的先验判断经常是错的如果强行用单尾一旦实际方向和预期相反你连“显著”的资格都没有只能报告一个没有意义的结果。稳妥的做法是先做双尾检验如果显著且方向符合预期再在报告里说明“效应方向与假设一致”。2.3 α 是谁定的0.05 为什么成了默认值α 是你在实验开始前给自己设定的“假阳性容忍度”也就是当 H0 其实为真时你错误地拒绝它的概率上限。0.05 这个数字没有数学上的神圣性它更像是一个历史形成的行业习惯背后是一套成本权衡把标准定得太松假阳性满天飞定得太严样本量需求暴涨很多真实效应根本测不出来。这里有个容易被忽略的换算α 是单次检验的错误率不是你整个项目组的错误率。如果你一年做 100 次 A/B 测试每次都卡 α0.05那么即使所有改动其实都没用你平均也会收获 5 个“显著”的结果。这 5 个结果会被写进汇报、变成案例、指导下一轮决策而那个 95 次“没效果”的部分没人记得。这就是所谓“文件抽屉问题”的现代版本。不同场景下 α 的选择应该不一样。探索性的用户研究、早期的变量筛选α 可以放宽到 0.1目的是别漏掉可能的信号涉及资金、安全、合规的决策α 要收到 0.01 甚至更严做多重比较时还要在 0.05 的基础上再做校正。把 α 当成一个需要论证的参数而不是一个抄来的常数是走向专业的第一步。2.4 被大多数报告忽略的另一半β 与统计功效绝大多数人只记得 α忘了 β。β 是第二类错误的概率——当真实存在效应时你没检测出来的概率。和它对应的概念叫统计功效power等于 1-β通常要求做到 0.8 以上意思是“如果真有效果我有 80% 的把握能抓出来”。这两类错误的性质完全不同。第一类错误是“冤枉好人”代价是你把一个没用的改动推上线第二类错误是“放走坏人”代价是你把一个真正有效的改动砍掉了。很多团队对第一类错误严防死守把 α 压到 0.01但完全不看功效结果样本量严重不足真实存在的 10% 提升被埋在噪声里最后得出“这个方向没戏”的结论这其实是更贵的错误。功效由四个因素共同决定效应量、样本量、α、数据的变异程度。它们的关系可以概括成一句话想抓到更小的效应就得多取样、降噪声或者放宽 α。这四个因素里只有样本量是你能自由控制的所以功效分析在实操中基本等同于“算我到底需要多少样本”。一个具体的感受当效应量很小的时候功效对样本量的要求会急剧上升而且不是线性的。检测 5% 的相对提升可能需要每组几千样本检测 2% 的相对提升可能就要几万。这也是为什么很多团队喊着“数据驱动”但实际上只能检测到大改动——小优化的信号根本浮不出水面。2.5 单尾还是双尾一个影响 p 值一半的选择单双尾之争在学术圈有过很长一段争论在业务场景里反而更实际。规则本身很简单双尾检验的备择假设是“不相等”p 值算两侧尾巴单尾检验的备择假设是“大于”或“小于”p 值只算一侧。关键点在于双尾的 p 值通常是单尾的两倍。同样一组数据双尾算出 0.06单尾可能就是 0.03。这就给了人操作空间——先做双尾不显著就改口说“我们本来就想验证提升方向”换成单尾。这种做法在方法上站不住脚因为假设的方向应该在看到数据之前就定好。我的实操建议是默认双尾理由有三个。一是业务决策通常需要知道“变差了没有”只关注单侧会让你对负面效果失去敏感二是方向性先验很容易错特别是涉及用户行为的改动反直觉的结果比比皆是三是双尾在沟通上更省事不用向别人解释“为什么你只算了半边”。只有一种情况我会用单尾检验的目的是纯粹的“非劣性”或“安全性”比如验证新流程的耗时没有超过旧流程的某个阈值。这时候方向是先验确定的单尾才有意义而且要在方案里写明白。3. 动手算一遍把 p 值从黑箱里拉出来3.1 手算一个二项检验20 次抛硬币先从一个能心算的例子开始把 p 值的来路彻底看清楚。假设一枚硬币抛 20 次出现 15 次正面。问题是这枚硬币是否公平。原假设 H0正面概率 p 0.5。备择假设 H1p ≠ 0.5双尾。检验统计量就是正面次数 X在 H0 下 X 服从二项分布 B(20, 0.5)。现在算“比 15 次更极端”的部分。双尾要算两边X ≥ 15 和 X ≤ 5。因为对称两边概率相等算一边乘 2 就行。X ≥ 15 的概率是 k 从 15 到 20 的组合数之和除以 2 的 20 次方C(20,15) 15504C(20,16) 4845C(20,17) 1140C(20,18) 190C(20,19) 20C(20,20) 1加起来是 21700。2 的 20 次方是 1048576。21700 ÷ 1048576 ≈ 0.0207。双尾 p 值 2 × 0.0207 ≈0.0414。小于 0.05拒绝原假设。这个例子里有几个细节值得盯住。第一如果你做的是单尾检验H1: p 0.5p 值就是 0.0207结论一样但数字差一倍。第二如果你把“极端”理解成“正好 15 次”概率只有 0.0148那就完全错了——p 值算的是尾巴不是点。第三这个 0.0414 距离 0.05 很近如果换成抛 14 次正面p 值会跳到 0.115直接不显著。20 次试验的样本量太小结论对一两次结果的波动极其敏感这就是小样本实验的通病。3.2 真实业务场景1000 人 vs 1000 人的转化率换成业务语言。某电商团队做了一次落地页改版A 组旧版1000 人访问100 人下单转化率 10%B 组新版1000 人访问120 人下单转化率 12%。看上去提升了 20%值得上线吗。先算合并比例p̂ (100120) / (10001000) 0.11。标准误 SE √[p̂(1-p̂)(1/n1 1/n2)] √(0.11 × 0.89 × 0.002) √0.0001958 ≈ 0.01399。z (0.12 - 0.10) / 0.01399 ≈1.429。查标准正态分布单侧尾部概率约 0.0765双尾 p 值约0.153。远大于 0.05不显著。这个结果和很多人的直觉冲突因为 12% 对 10% 看起来差距挺明显。但把不确定性算进去就明白了1000 人的样本转化率的抽样误差本身就有 ±1 个百分点左右两组各带 1 个百分点的噪声2 个百分点的差距完全可能是噪声的叠加。再看置信区间差距的 95% 置信区间是 0.02 ± 1.96 × 0.01399即[-0.0074, 0.0474]换算成百分比是 [-0.74%, 4.74%]。区间跨过了 0意思是“真实差异可能为负也可能高达 4.74 个百分点”。这个区间比 p 值有信息量得多——它同时告诉你方向和不确定性的范围。这个例子还引出一个重要判断如果这个改版的真实效应就是 2 个百分点那么 1000 人一组根本不够。要检测出这个量级的差异每组大概需要 3800 人下一节会算。3.3 Python 复现z 检验、置信区间与置换检验手工算一遍是为了理解实际工作里当然用代码。下面这段可以直接跑。import numpy as np from statsmodels.stats.proportion import proportions_ztest # 两组数据先 B 后 A count np.array([120, 100]) nobs np.array([1000, 1000]) z_stat, p_value proportions_ztest(count, nobs, alternativetwo-sided) print(fz {z_stat:.3f}, p {p_value:.4f}) # 输出z 1.429, p 0.1529置信区间可以用 statsmodels 里的两独立比例区间函数from statsmodels.stats.proportion import confint_proportions_2indep low, high confint_proportions_2indep( count1120, nobs11000, count2100, nobs21000, methodwald, comparediff ) print(f95% CI: [{low:.4f}, {high:.4f}]) # 大约 [-0.0074, 0.0474]如果不想依赖分布假设置换检验是个很实用的替代方案尤其适合指标分布奇形怪状、或者样本量偏小的场景。它的思路极其朴素如果两组真的没差别那把两组的标签随机打乱重新分组算出来的差异应该和原来差不多。import numpy as np rng np.random.default_rng(2024) # 构造 0/1 转化数据 a np.concatenate([np.ones(100), np.zeros(900)]) b np.concatenate([np.ones(120), np.zeros(880)]) obs_diff b.mean() - a.mean() pooled np.concatenate([a, b]) diffs np.empty(10000) for i in range(10000): rng.shuffle(pooled) diffs[i] pooled[:1000].mean() - pooled[1000:].mean() p_perm np.mean(np.abs(diffs) abs(obs_diff)) print(f观测差异 {obs_diff:.4f}, 置换 p {p_perm:.4f}) # 大约 0.15 上下和 z 检验基本一致置换检验的好处是不用担心正态近似在小样本或极端比例下失效缺点是计算量大而且它检验的是“两组分布是否相同”这个更宽泛的假设。两种方法结果接近时说明数据没有触碰近似假设的边界可以放心如果差很多就要警惕了。3.4 样本量怎么定从 MDE 倒推样本量不该拍脑袋应该从一个明确的最小可检测效应MDE倒推。MDE 的意思是这次实验我至少要能稳定抓到的效果有多大。它的取值不是统计学问题而是业务问题——低于这个幅度的提升即使真实存在也不值得投入研发资源去实现。假设基线转化率 10%团队认为至少要有 2 个百分点的绝对提升相对提升 20%才值得做α0.05功效 0.8双侧检验。用正态近似公式n (z_{1-α/2} z_{1-β})² × [p1(1-p1) p2(1-p2)] / (p1-p2)²代入z_{0.975}1.96z_{0.8}0.8416和为 2.8016平方得 7.849。分子部分 p1(1-p1)0.09p2(1-p2)0.1056加起来 0.1956。分母是 0.02 的平方等于 0.0004。n 7.849 × 0.1956 / 0.0004 ≈3838也就是每组大约 3840 人总共 7680 人。用代码验证一遍from statsmodels.stats.power import NormalIndPower from statsmodels.stats.proportion import proportion_effectsize h proportion_effectsize(0.12, 0.10) power_analysis NormalIndPower() n power_analysis.solve_power( effect_sizeh, alpha0.05, power0.8, ratio1.0, alternativetwo-sided ) print(f每组所需样本量: {n:.0f}) # 大约 3830 上下与手算的 3838 差异来自舍入和效应量度量方式这个数字很能说明问题1000 人一组的实验功效大概只有 0.3 左右也就是说即使 2 个百分点的提升真实存在你有七成概率测不出来。在这种情况下得出“改版无效”的结论本质上是把样本量不足误判成了效果不存在。再算一下如果想把 MDE 压到 1 个百分点样本量会变成多少。粗略地讲样本量和效应量的平方成反比效应减半样本量变成四倍也就是每组一万五千人左右。这就是为什么精细优化的测试成本高得吓人。3.5 一次完整 A/B 测试的执行清单把前面所有零件拼成一个能落地的流程我通常按这八步走缺一步都容易在复盘时说不清。明确唯一的核心指标和护栏指标。核心指标只留一个主检验其他都算辅助避免多重比较。用历史数据估基线结合业务判断定 MDE。MDE 定不下来就别开实验。用功效分析算样本量同时算实验需要跑多少天注意覆盖完整的周期比如至少包含一个完整周规避周末效应。写分析计划把假设、检验方法、α、单双尾、分组方式、异常数据处理规则全部写死实验开始后不改。上线前做 AA 测试确认分流机制本身没有偏倚。运行期间不偷看主指标或者改用事先设计的序贯检验方法。达到预定样本量后停止先做数据质量检查样本比例是否失衡、埋点是否缺失、有无异常流量再跑主检验。报告里同时给出效应量、置信区间、p 值、样本量、实验周期以及业务影响换算。第 5 步的 AA 测试经常被跳过但它是性价比最高的一步。分流如果本身有偏比如新用户被不均匀地分到某一组后面所有统计都是空中楼阁。第 7 步的数据质量检查也一样很多“显著”的结果最后被证明是某个渠道的埋点重复上报导致的。4. p 值被玩坏的六种方式与排查手册4.1 高频误读速查表我在实际工作中整理过一份误读清单基本覆盖了大部分沟通冲突的源头做成了一个可以拿去对照的表格。现象描述背后真实原因处理办法p0.049 就上线0.051 就砍掉把连续证据当成二元开关用置信区间和效应量辅助决策阈值附近不做激进决策样本量很大时什么改动都显著标准误随样本量下降引入实际显著性判断设定最小业务可感知幅度报告只写“显著”不写差值混淆统计显著与业务重要强制要求报告绝对差值、相对差值和置信区间换个指标就显著了指标挑选导致的多重比较实验前锁定主指标辅助指标做校正分组后某个子群显著分层挖掘造成的假阳性子群分析标注为探索性用校正后的阈值或独立验证p 值很大就说“证明无差异”把不拒绝当成接受改用等效性检验或者报告置信区间说明能排除多大效应表格里第一行最值得展开。0.049 和 0.051 在数学上的差别微乎其微它们对应的证据强度几乎一样但决策结果却可能完全相反。这种做法本质上是把一个连续的证据刻度硬掰成二元开关而真实世界的决策成本并不是对称的——有时候上线一个效果存疑的改动成本很低有时候成本极高。所以我会建议在阈值附近设置一个“灰区”比如 0.01 到 0.1 之间不直接下结论而是结合效应量和业务判断或者干脆补数据。第六行也特别常见。p0.3 并不等于“两组一样”它只说明“在现有样本量下没测出来”。如果这个实验的 MDE 是 5 个百分点那么 p0.3 只排除了“差异大于 5 个百分点”这种可能对于 1 个百分点的差异依然一无所知。说“证明了没差别”是过度解读的结果。4.2 偷看数据与 p-hacking偷看数据是 p 值被污染的最主要来源也是最难自查的一种。它的机制不复杂假设 H0 为真你在实验期间反复检验每次看到不显著就继续跑看到显著就停止。这种做法的假阳性率远高于 5%在有多次查看的情况下实际错误率可能翻两三倍。我做过一个模拟用完全随机、没有任何真实效应的两组数据每 100 个样本检验一次一旦 p0.05 就停止重复 10000 次实验统计有多少次“显著”。结果远超 5%。这就是为什么“跑到显著为止”这种做法在方法论上是有问题的——它保证你能拿到显著结果但那个显著性是你自己造出来的。p-hacking 是个更大的筐泛指一切为了让 p 值变小而做的、没有事先声明的操作。常见的包括删掉几个“明显异常”的样本、换一个更宽松的指标、把连续变量切成有利的分组、去掉某个表现不好的渠道、延长或缩短实验周期直到显著。这些操作单独看都“有理由”但组合起来就是在数据里钓鱼。排查的方法有几个。一是看实验方案和最终分析的差异凡是方案里没写的分析都要标注为探索性。二是看 p 值分布如果一个团队报上来的 p 值大量集中在 0.04 到 0.05 之间而 0.05 到 0.1 几乎空白那基本可以怀疑有选择性报告。三是做 p 值均匀性检验当 H0 为真时p 值应该在 [0,1] 上均匀分布任何系统性的偏离都是信号。这段代码可以帮你直观感受“H0 为真时 p 值长什么样”import numpy as np from scipy import stats rng np.random.default_rng(123) ps [] for _ in range(5000): a rng.normal(0, 1, 30) b rng.normal(0, 1, 30) ps.append(stats.ttest_ind(a, b).pvalue) ps np.array(ps) print(fp0.05 的比例: {(ps 0.05).mean():.4f}) # 约 0.05 print(fp0.01 的比例: {(ps 0.01).mean():.4f}) # 约 0.01这两行输出应该接近 0.05 和 0.01。如果你在自己的数据上算出明显更高的比例而实验本身又没有真实效应那就该查一查分析流程了。4.3 多重比较做 20 次检验必然撞鬼多重比较是 p 值被误用最严重的地方也是最容易被忽略的。原理很简单一次检验的假阳性率是 5%两次独立检验至少有一次假阳性的概率就是 1-0.95² ≈ 9.75%做 20 次就是 1-0.95²⁰ ≈64%。换句话说只要你从 20 个指标或 20 个子群里挑大概率能挑出一个“显著”的结果而这个结果跟真实效应可能毫无关系。业务场景里的多重比较往往藏得很深。看五个渠道分别有没有差异、看新老用户分别有没有差异、看三档价格分别有没有差异、看四个时间段分别有没有差异这一套组合下来就是十几次检验而报告里通常只会展示那几个显著的分组。处理方法有两类。一类是控制族错误率最常用的是 Bonferroni 校正把 α 除以检验次数。做 20 次检验就把阈值收到 0.0025。这个方法保守但简单可靠适合检验次数不多、假阳性代价很高的场景。另一类是控制错误发现率FDR代表方法是 Benjamini-Hochberg 过程它允许一定比例的假阳性但在大量检验时功效更高适合基因表达、大规模指标扫描这类场景。不管用哪种方法更根本的做法是减少检验次数。实验开始前就锁定一个主指标其他指标只作为辅助观察不做正式的显著性宣称。分层分析如果确实重要就应该在方案里预先声明分几层、每层看什么而不是跑完数据再到处挖。还有一个隐蔽的多重比较来源同一批用户被反复用于多个实验。如果几个实验的重叠度很高它们的检验结果就不独立校正公式也要相应调整。这一点在流量紧张的平台上尤其需要注意。4.4 样本比例失衡与数据质量排查在跑主检验之前有个检查几乎必做叫样本比例失衡检查SRM。逻辑是如果你设计了 50/50 的分流实际进入分析的两组人数应该接近这个比例偏差过大说明分流或埋点可能出了问题这时候任何 p 值都不可信。用卡方检验做个快速判断from scipy import stats observed [51_200, 48_800] # 实际进入分析的两组人数 expected [50_000, 50_000] # 设计上的期望人数 chi2, p_srm stats.chisquare(observed, expected) print(f卡方 {chi2:.2f}, p {p_srm:.4g}) # p 很小说明分流异常先别急着看主指标这里的判断逻辑和常规检验反过来了我们希望 p 值大大说明实际比例和设计比例没有显著偏差分流正常。如果这个 p 值很小第一件事不是分析效果而是去查分流代码、缓存、埋点重复上报、某个渠道的流量被错误路由这些问题。除了 SRM还有几项数据质量检查值得固化到流程里。一是样本量是否达到预定值中途有没有大批量流量涌入或流失。二是核心指标缺失率缺失率如果在两组间不一致那就是系统性偏倚。三是极端值的分布特别是金额、时长这类长尾指标一组多几个极端值就能把均值拉偏。四是实验周期是否覆盖完整业务周期只跑三天很可能撞上某天的促销活动。我踩过的一个坑是缓存导致的重复计数。某个版本的前端把曝光事件重复上报了两次而另一组没有结果 B 组的样本量虚高指标被稀释p 值难看。光看统计结果完全看不出问题是 SRM 检查把这条线索引出来的。4.5 结果不显著时该说什么不显著的结果同样是有价值的但报告里不能只写一句“无显著差异”。合格的写法要回答三个问题这次实验能排除多大的效应、观察到的点估计是多少、下一步该怎么走。第一用置信区间表达“能排除什么”。如果差值的 95% 置信区间是 [-1.2%, 1.8%]那说明大于 1.8 个百分点的正向提升基本可以排除但小的提升依然有可能。这比“无显著差异”有用得多。第二报告点估计和它的方向性。哪怕不显著如果点估计一直是正向的而且多个相关指标方向一致这本身就是弱证据值得在后续实验里继续验证而不是一笔勾销。第三区分“确实没效果”和“这次没测出来”。判断依据是功效如果实验功效只有 0.3那不显著几乎是必然的结论应该是“样本不足无法判断”而不是“改动无效”。这种情况正确的动作是补样本或者重新设计而不是换方向。如果确实想宣称“两者等效”那就不能用常规的显著性检验得用等效性检验——事先定义一个等效区间然后检验差异是否落在这个区间内。这套方法在医药和流程改造里用得很多业务场景里用得少但在“我们要证明新流程不比旧流程差”这类问题上是唯一站得住脚的做法。5. 跳出 p 值效应量、置信区间和另外几种思路5.1 效应量显著不等于重要效应量回答的是“差多少”p 值回答的是“这个差相对于噪声有多显眼”。这两件事在样本量足够时会被彻底解耦样本越大噪声越小任何微小的差异都能变得显眼。常用的效应量指标有这么几类。连续变量比较用 Cohens d即两组均值差除以合并标准差比例比较用绝对差、相对差或者 Cohens h分类变量的关联强度用 Cramérs V 或者优势比。这些指标的好处是不随样本量膨胀同一个真实效应不管样本多大效应量的估计值都稳定在同一个水平附近。我判断一次改动值不值得推通常看三层。第一层是统计显著作为入场券第二层是效应量看绝对差值是否超过业务上可感知的门槛第三层是成本收益把效应量换算成收入、留存或者人力节省再对比实现和维护成本。三层都过了才叫“值得做”只过第一层的我一般建议先放着。举个具体的换算某功能改动把次日留存从 30% 提到 30.3%样本量百万级p 值极小。绝对提升 0.3 个百分点相对提升 1%。如果这个产品日活十万那就是每天多留 300 人按生命周期价值折算可能是一笔不小的钱那就值得做如果日活只有一千每天多留 3 人那这点收益还不够一次发布的沟通成本。5.2 置信区间比 p 值信息量大得多置信区间是被严重低估的工具。它同时给出三个信息效应的点估计、估计的不确定性范围、以及这个范围是否跨过零或跨过某个业务阈值。p 值只给一个数字置信区间给的是一个区间信息密度完全不在一个量级。看区间的时候除了看是否跨零还要看区间的宽度。宽度反映精度宽度大说明样本不足或数据噪声大这时候即便区间没跨零结论也不稳。两个实验都显著一个区间是 [0.5%, 1.5%]另一个是 [0.1%, 8%]前者明显更可信。还有一个进阶用法把区间和业务阈值对比。假设你的决策规则是“提升超过 1 个百分点才值得推”那区间是 [0.5%, 1.5%] 时虽然显著但下限低于阈值说明效果可能不够需要更多数据区间是 [1.2%, 2.0%] 时整个区间都在阈值之上这才是干净利落的“可以推”。置信区间的计算方法要和检验方法匹配。比例差异用 Wald 区间在极端比例下会失真这时候用 Wilson 或者 Newcombe 方法更稳连续变量在小样本下要用 t 分布而不是正态分布。这些细节在报告里不用展开但算的时候不能糊弄。5.3 贝叶斯方法与序贯检验的适用场景p 值不是唯一的路。有两种思路在实际工作里越来越常见各自解决不同的问题。贝叶斯方法直接回答很多人真正想问的问题在看到这组数据之后B 优于 A 的概率是多少。它需要给参数设一个先验分布然后通过数据更新到后验分布。好处是解释直观、可以随数据累积持续更新、不依赖“跑到固定样本量”这个约束。坏处是先验的选择会影响结果而且“先验从哪来”这件事在业务场景里经常说不清。我的经验是当你有大量历史实验数据可以做先验时贝叶斯方法很有优势从零开始的新业务先验基本靠拍反而不如频率学派的方法透明。序贯检验解决的是另一个痛点不想等到固定样本量希望在有明确结论时尽早停止同时又不破坏错误率控制。它的思路是预先设定一系列检验边界随着数据累积不断调整阈值使得整体的第一类错误率仍然控制在 α 以内。这种方法特别适合流量大、决策周期短、试错成本低的场景比如推荐策略的在线调参。要提醒的是序贯检验的边界必须在实验开始前算好事后再套用就不成立了。选哪种方法取决于你要回答的问题和能接受的成本。做一次性的、结论要写进正式文档的验证经典假设检验够用且沟通成本最低做持续迭代、每天都要决策的在线系统序贯方法或者贝叶斯更新更合适。5.4 工具选型对照表最后给一张工具对照表覆盖从手算到工程化的常见选择。场景推荐工具关键函数或方法注意事项快速手算、教学演示纸笔加分布表二项分布、正态分布表只适合小样本别用来做正式结论Python 日常分析scipy.statsttest_ind、chi2_contingency、binomtest注意默认是双尾方差齐性要自己判断比例类 AB 测试statsmodelsproportions_ztest、confint_proportions_2indep极端比例下改用精确检验小样本分类数据scipy 或 Rfisher_exact计算量随样本增长很快大样本别用分布未知或指标畸形自写置换检验打乱标签重采样迭代次数建议一万次以上样本量与功效statsmodelsNormalIndPower、TTestIndPower效应量口径要和检验方法匹配多重比较校正statsmodelsmultipletests明确是要控制族错误率还是 FDR大规模实验平台内部平台或开源实验框架分流、SRM 检查、序贯边界优先保证分流正确和指标口径统一选工具的优先级我的排序是分流正确 指标口径统一 检验方法正确 计算精度。前两项出问题后面算得再精细都是白搭后两项出问题通常是结论偏差几个百分点比前两项的错误要好修。6. 几个我反复被问到的具体问题6.1 p 值刚好卡在 0.05 附近怎么办这是最高频的问题没有之一。我的处理方式是不在这个点上做二元判断而是看三件事效应量的点估计是否稳定、置信区间的下限离零有多远、以及这个决策的犯错成本是否对称。如果区间是 [0.02%, 1.8%]点估计在中间那基本可以认为是正向的只是精度不够如果区间是 [-1.5%, 2.0%]那点估计本身就不可靠补数据是唯一正解。冒进上线一个 0.051 的改动和误砍一个 0.049 的改动哪个代价大答案因团队而异这个判断不该由 p 值替你做。6.2 实验能不能提前停能但要用对方法。常规的固定样本检验不允许中途反复查看这一点前面说过。如果业务上确实需要早停就用序贯检验把边界预先算好然后按边界执行。判断标准不是“p 值小于 0.05 就停”而是“统计量越过了事先设定的边界”。还有一种折中的做法是设定一个最短观察期和最长观察期在区间内只在预设的检查点看数据检查点数量控制在两三次以内并且用 Bonferroni 之类的方法对多次查看做校正。这比“天天看看到显著就停”要严谨得多。6.3 大样本下什么都显著还有必要做检验吗有必要但重点要转移。大样本下 p 值几乎必然很小这时候它的信息量趋近于零真正该看的是效应量和置信区间宽度。检验的作用从“判断有没有差异”变成“确认差异的方向和量级”。大样本还有一个隐性风险数据质量问题会被放大。埋点重复、机器人流量、跨设备重复计数在小样本里可能只是噪声在百万级样本里会变成系统性偏差制造出一个漂亮的假阳性。所以样本越大越要在数据清洗上花时间。6.4 指标是偏态分布均值检验还能用吗能但要小心。t 检验对偏态的稳健性依赖于样本量样本量足够大时中心极限定理会兜底但“足够大”的门槛取决于偏态的程度。金额、时长、访问深度这类长尾指标几千样本可能都还不够。两个处理方向一是改用对分布假设要求更低的方法比如置换检验、Bootstrap 置信区间或者对指标做对数变换后再比较二是干脆换指标口径比如把“平均订单金额”换成“下单率”或者“人均 GMV 的中位数”牺牲一点信息换取稳健性。我的偏好是先做变换或者用 Bootstrap保持指标原义的同时降低假设依赖。7. 我个人在实际操作中的几点体会第一个体会是p 值的价值不在于给出答案而在于逼你把问题问清楚。你得先定义什么叫“有效果”、能接受多大的误判、愿意为此付多少样本量然后才轮得到算 p 值。跳过前面这些直接算得到的数字再精确也没有决策价值。第二个体会是报告里最有用的往往不是 p 值那一栏而是效应量和置信区间。我现在的习惯是先看差值、再看区间宽度、最后瞄一眼 p 值确认方向反过来做容易被那个小数字带偏。第三个体会是关于沟通。跟非技术同事讲 p 值我一般不用公式就说“假设这个改动完全没用我们有多大概率看到今天这个结果”。这句话通常能让对方一秒理解也能顺带解释为什么样本量小的时候“看不到效果”不代表“没效果”。第四个体会是流程比方法重要。再严谨的统计方法放进一个允许中途偷看、允许换指标、允许反复重跑的分析流程里都会被玩坏。把分析计划写死、把 SRM 检查做成必过项、把多重比较校正固化到工具里这些工程化的动作比争论用不用贝叶斯更能提升结论的可信度。
阅读完成 · 觉得有帮助?