假设检验最容易让人误解的地方,是它并不回答“哪个假设更可能为真”,而是在原假设成立的前提下,评估当前数据出现的极端程度。这个判断顺序一旦颠倒,后续的显著性、功效、置信区间都会跟着走样。本文以一个线上转化率对比场景为例,把假设检验拆成提出假设、设计实验、分析结果和结论解读四个环节,说明每一步的统计依据与常见错误。

一、提出假设:把业务问题翻译成统计命题
很多分析走到最后才发现假设写反,是因为一开始没有区分研究假设和统计假设。研究假设通常带有方向,例如“新版落地页的注册转化率高于旧版”。统计假设必须成对出现:原假设 H0 表示没有差异或没有达到预设方向,备择假设 H1 表示存在差异或达到方向性提升。
在转化率场景中,如果把 p_new 记为新版转化率、p_old 记为旧版转化率,单侧检验可以写为:H0: p_new ≤ p_old;H1: p_new > p_old。单侧检验的优势是功效更高,但前提是业务上有充分理由只关心“提升”而不关心“下降”。如果新版本可能因为设计失误导致转化率明显下降,通常应使用双侧检验:H0: p_new = p_old;H1: p_new ≠ p_old。假设方向不能根据收集到的数据临时修改,否则显著性水平会失真。
提出假设时还要明确检验对象。比如“推荐算法调整后用户平均停留时长是否变化”适合 t 检验;“两个页面转化率是否一致”适合比例 z 检验或卡方检验;“三个及以上版本的点击率是否存在差异”适合方差分析。对象类型决定了后续数据收集方式和检验统计量。
二、设计实验:样本量、显著性与功效
设计实验的核心不是采样越多越好,而是让样本量同时满足第一类错误和第二类错误的控制要求。显著性水平 α 通常取 0.05,表示在原假设为真时,平均每 20 次检验会错误拒绝一次。功效 1-β 通常取 0.8,表示在备择假设实际为真时,检验有 80% 的概率能识别出来。β 越小,需要的样本量越大。
另一个关键参数是最小可检测效应 MDE。如果两版转化率只相差 0.1%,业务上可能毫无意义,即使检验显著也不值得上线。因此实验前应根据业务判断确定最小有意义的提升幅度。样本量计算需要同时输入 α、功效和效应量。以下 Python 示例用 statsmodels 估算两组比例差异所需的每组样本量:
from statsmodels.stats.proportion import proportion_effectsize from statsmodels.stats.power import NormalIndPower baseline = 0.12 lift = 0.006 target = baseline + lift effect = proportion_effectsize(baseline, target) analysis = NormalIndPower() n = analysis.solve_power(effect_size=effect, alpha=0.05, power=0.8, ratio=1, alternative='two-sided') print(n)
假设旧版转化率为 12%,最小可检测提升为 0.6 个百分点,则每组大约需要 11000 个样本。若把 MDE 缩小到 0.3 个百分点,样本量会接近 44000。这说明实验精度越高,成本上升越快。样本量不足的实验即使得到显著结果,也可能因为功效过低而不可信。
两类错误可以用一张表概括:第一类错误是假阳性,即原假设为真但被拒绝;第二类错误是假阴性,即备择假设为真但未被拒绝。二者在样本量固定时通常存在权衡。降低 α 会减少假阳性,但会增加假阴性;提高功效需要更多样本。实验设计阶段把这些参数固定下来,可以避免分析阶段随意调整。
三、选择检验方法并分析结果
数据收集完成后,应根据变量类型和实验组数选择检验方法。连续变量两组比较用独立样本 t 检验,多组用单因素方差分析;分类变量的比例比较用 z 检验或卡方检验;不满足正态性或方差齐性假设时,可以用 Mann-Whitney U 检验等非参数方法。下面以比例 z 检验为例,手动计算检验统计量和 p 值。
假设新旧版本各收集了 10000 个用户,旧版转化 1200 人,新版转化 1260 人。合并比例公式和标准误计算如下:
import numpy as np
from scipy import stats
n_old = 10000
n_new = 10000
p_old = 0.12
p_new = 0.126
p_pool = (p_old * n_old + p_new * n_new) / (n_old + n_new)
se = np.sqrt(p_pool * (1 - p_pool) * (1 / n_old + 1 / n_new))
z = (p_new - p_old) / se
p_value = 2 * (1 - stats.norm.cdf(abs(z)))
print(f"z = {z:.3f}, p = {p_value:.5f}")
上面的双侧检验得到 z 约为 1.297,p 值约为 0.1947。若使用 0.05 的显著性水平,p 值大于 α,不能拒绝原假设。也就是说,在以原假设为真的前提下,出现当前 0.6 个百分点差异或更极端结果的概率并不低,不能据此认为新版转化率存在统计显著变化。
只报告 p 值还不够,应同步给出差异的置信区间。比例差的标准误和 95% 置信区间可以用以下代码计算:
se_diff = np.sqrt(p_old * (1 - p_old) / n_old + p_new * (1 - p_new) / n_new) ci_low = (p_new - p_old) - 1.96 * se_diff ci_high = (p_new - p_old) + 1.96 * se_diff print(ci_low, ci_high)
如果置信区间包含 0,则与不拒绝原假设的结论一致;如果不包含 0,说明差异在 α=0.05 水平上显著。置信区间还能反映差异的可能范围,帮助判断统计显著是否具有业务价值。
四、从 p 值到结论:避免常见误读
p 值经常被错误解释为“原假设为真的概率”或“备择假设为真的概率”。实际上 p 值是条件概率:P(观察到当前或更极端数据 | H0 为真)。它不能直接告诉我们 H0 为真的概率。假设检验也不回答“哪个假设更可能正确”,只是提供一种在 H0 框架下衡量证据强度的方式。
另一个常见问题是 p-hacking。分析师在得到不显著结果后,尝试更换指标、调整样本范围、增加协变量,或者中途查看数据后提前停止实验,这些操作都会使 p 值偏离名义显著性水平。多重比较同样会放大假阳性,例如同时检验 20 个指标,即使所有指标实际上都没有差异,也有约 64% 的概率至少出现一个 p 小于 0.05 的指标。可以用 Bonferroni 校正或 FDR 控制来缓解,但更推荐的做法是实验前确定一个主要指标和一套分析计划。
结论落地时,应把统计语言和业务语言分开。如果检验拒绝原假设,可以写成:在 α=0.05 的显著性水平下,数据提供足够证据支持新版转化率有提升;同时报告差异点估计和置信区间。如果未拒绝原假设,应写成:当前数据不足以证明存在差异,而不是“证明没有差异”。未拒绝可能因为效应确实为零,也可能因为样本量不足、功效过低。此时需要检查实验设计是否达到预设 MDE 的检测能力。
假设检验推理的完整流程可以总结为:先定义研究问题,再写清 H0 和 H1,确定 α、功效和 MDE 并计算样本量,随后固定分析方案收集数据,最后基于检验统计量、p 值和置信区间综合判断。任何一步用数据倒推参数,都会破坏推理链条。