用scipy.stats.proportions_ztest做两样本比例检验,设correction=false关闭连续性修正,输入[success_a, success_b]和[n_a, n_b],双侧p值需根据zstat符号转单侧;statsmodels无ab_test函数,可用confint_proportions_2indep计算绝对提升的95%置信区间。

怎么用 scipy.stats 做两样本比例检验(比如点击率)
直接用 proportions_ztest,别手写 z 分数——它默认做的是双侧检验,且自动处理小样本校正(加 0.5 连续性修正),但多数 A/B 测试里你其实不需要这个修正,反而会降低统计功效。
- 真实场景中,只要每组样本量 > 30 且成功数/失败数都 ≥ 5,就关掉连续性修正:
correction=False - 注意
count和nobs的顺序:必须是 [success_A,success_B] 和 [n_A,n_B],反了结果完全不可信 - 返回的 p 值是双侧的;如果你只关心“B 是否显著高于 A”,得自己转成单侧:
p_value / 2,但前提是zstat > 0
statsmodels 的 ab_test 没有内置函数,别搜这个关键词
很多人在文档里翻半天找 ab_test,其实 statsmodels 根本没这玩意儿。它提供的是底层工具链,比如 proportion 模块里的 ztest 或 confint_proportions_2indep,用来算置信区间更稳。
- 用
confint_proportions_2indep算绝对提升的 95% CI:比只看 p 值更能判断业务意义 - 如果转化率很低(scipy.stats.fisher_exact(2×2 列联表),虽然慢点,但准确
-
statsmodels默认用独立样本假设;如果实验是配对设计(比如用户级分流+前后对比),得换mcnemar或手动建配对差值序列
分层分析时,groupby 后直接调 proportions_ztest 会出错
因为 proportions_ztest 不接受 Series,也不支持向量化。常见错误是写成 df.groupby('country')['converted'].apply(...),结果报 ValueError: too many values to unpack。
- 正确做法:先用
agg提取每层的sum和count,组装成两个数组再喂给检验函数 - 分层后样本量可能不均——某国只有 20 个用户?跳过它,别强行合并或插值,否则假阳性飙升
- 如果要做 Bonferroni 校正,p 值阈值不是
0.05 / n_layers,而是0.05 / (n_layers - 1)(对照组不算一层)
时间衰减效应会让当天跑的 p_value 失真
新用户和老用户行为节奏不同,第 1 天的点击率常被短期激励拉高,但第 7 天的留存才反映真实效果。直接拿首日数据跑检验,大概率早停(early stopping)误判。
立即学习“Python免费学习笔记(深入)”;
- 至少等齐最小周期:电商看 7 日 ROI,SaaS 看 14 日激活,别卡在第 3 天就下结论
- 用
pandas.cut按曝光后小时分桶,画conversion_rate随时间变化曲线,确认是否已收敛 - 如果实验跑了 14 天但最后 2 天流量突降 40%,那这两天的数据权重该砍掉——不是删掉,是用
weights参数传给检验函数
最麻烦的不是算不准,而是把分层、时序、样本依赖这几个坑叠在一起——这时候单独看任一指标都没问题,合起来却系统性偏移。盯住原始事件流,比盯汇总表安全得多。










