该用ttest_ind当两组数据来自不同群体,如随机分组的a/b测试;ttest_rel适用于同一群体先后接受两种处理的配对设计。误用会导致p值失真,且ttest_ind要求输入连续变量、需检验方差齐性与正态性。

什么时候该用 ttest_ind 而不是 ttest_rel
关键看两组数据是否来自同一群人。比如你让一批用户先用版本A、再用版本B,测点击率变化,这是配对设计,得用 ttest_rel;但如果你随机分两组,一组只看A、一组只看B,那就是独立样本,必须用 ttest_ind。误用会直接导致 p 值失真——ttest_ind 默认假设方差相等,但现实中 A/B 组的转化率波动常不一致。
实操建议:
- 先跑
scipy.stats.levene检验方差齐性,p ttest_ind 时务必设equal_var=False - 如果样本量都 > 30,且分布不太偏(比如转化率在 1%–20% 之间),t 检验结果通常稳健;但若某组转化率接近 0% 或 100%,考虑换
proportions_ztest(来自statsmodels) - 别直接喂原始点击/曝光数进去——
ttest_ind要求输入是连续型观测值(如人均停留时长、订单金额),不是比例。算转化率后当连续变量用可以,但要警惕方差不稳定
用 ttest_ind 做转化率检验的常见翻车点
很多人把 A 组 1000 次曝光、80 次点击,B 组 1000 次曝光、95 次点击,直接塞进 ttest_ind([1]*80 + [0]*920, [1]*95 + [0]*905) ——这没错,但效率极低。10 万行数据构造布尔数组,内存和计算都浪费。
更稳妥的做法是用汇总统计近似:
- 只要每组 n > 50 且 p 不极端(0.1 ttest_ind 直接比较两组转化率数值(每个“观测”是一次实验的转化率,比如按天聚合)
- 如果只有单次实验的总点击/曝光数,别硬套 t 检验,改用
statsmodels.stats.proportion.proportions_ztest(count=[80, 95], nobs=[1000, 1000]) -
ttest_ind对离群值敏感。比如某天 A 组因缓存失效导致人均时长飙升到 2 小时,这一条就可能拉偏均值和方差——建议先用 IQR 或scipy.stats.zscore剔除 |z| > 3 的点
如何快速判断 t 检验结果是否可信
p 值小于 0.05 只是门槛,不代表效果真实。重点看三件事:效应量、置信区间、样本代表性。
- 用
scipy.stats.ttest_ind返回的statistic算 Cohen’s d:d = t_stat * np.sqrt(1/n1 + 1/n2),d > 0.2 才算有实际意义(哪怕 p=0.001,d=0.03 也没啥用) - 手动补上 95% 置信区间:
from scipy import stats; se = np.sqrt(s1**2/n1 + s2**2/n2); margin = stats.t.ppf(0.975, df) * se,如果区间跨零,谨慎下结论 - 检查分组是否真正随机:比如 A 组用户集中在 iOS,B 组集中在安卓,那差异可能来自系统而非版本——得加协变量做 ANCOVA,或直接切设备维度重跑
为什么有时候 ttest_ind 报 nan 或 inf
最常见原因是某组标准差为 0(全一样)或极小,导致 t 统计量分母趋近于 0。比如 A 组 100 个用户人均下单金额全是 299,B 组有波动,这时 ttest_ind 会返回 inf 和 nan p 值。
- 先检查
np.std(group_a)是否为 0;是的话,说明该指标在当前粒度下无变异,换指标(比如用是否下单代替金额)或换聚合粒度(按用户聚合变成按会话聚合) - 如果标准差极小(比如 1e-10),加一个微小扰动:
group_a = group_a + np.random.normal(0, 1e-8, len(group_a)),避免数值崩溃 - 还有一种情况是样本量太小(n1=1 或 n2=1),t 分布自由度不足,
ttest_ind无法计算;此时应停止检验,补数据
真实业务中,t 检验只是起点。显著性容易刷出来,但效应量、业务逻辑一致性、多维度交叉验证,才是决定是否全量的关键。别让 p 值替你做决策。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











