不平衡数据下不可直接用 ttest_ind,因样本量悬殊易违反假设导致假阳性;应优先检验正态性与方差齐性,改用 mann-whitney u 检验,并结合 cliff’s delta 等效应量解释结果。

不平衡数据下不能直接用 scipy.stats.ttest_ind
业务中常见的“不平衡”指两组样本量差异极大(比如转化用户 50 人 vs 未转化用户 5000 人),此时 ttest_ind 的假设前提(方差齐性、近似正态、样本独立)极易被违反,statistic 值可能失真,pvalue 显著偏小——不是真有差异,而是被大样本“带偏”了。尤其当小样本组分布偏斜或含离群值时,ttest_ind 很可能给出假阳性结论。
- 先检查两组的
len()和scipy.stats.shapiro()结果,若任一组p 且 <code>n ,拒绝使用 t 检验 - 用
scipy.stats.levene()检查方差齐性;若p ,说明方差不等,<code>ttest_ind应设equal_var=False(即 Welch’s t-test) - 但即使加了
equal_var=False,小样本组若严重非正态,检验力仍极低——这时 t 检验本身就不适用
优先用 scipy.stats.mannwhitneyu 替代参数检验
mannwhitneyu 是非参数检验,不依赖正态分布假设,对样本量悬殊更鲁棒,适合业务中常见的“少量高价值用户 vs 大量普通用户”场景。它检验的是两组是否来自同一分布(原假设:P(X > Y) = 0.5),而非均值相等。
- 必须设
alternative='two-sided'(默认是'two-sided',但显式写出更安全) - 当任一组
n 且存在大量相同值(如评分都是 5 分),要加 <code>method='exact',否则scipy默认用正态近似,小样本下 p 值不准 - 注意它默认会自动处理
nan:删掉含nan的配对,但不会警告——务必提前用np.isfinite()清洗 - 示例:
from scipy.stats import mannwhitneyu<br>stat, p = mannwhitneyu(group_a, group_b, alternative='two-sided', method='exact' if min(len(group_a), len(group_b))
小样本 + 分类目标?别硬套连续型检验
如果“不平衡”指的是二分类结果(如付费/未付费,正样本仅 30 人,负样本 10000 人),而你想比较两组转化率差异,scipy 里根本没有现成的“不平衡比例检验”函数。强行用 ttest_ind 对 0/1 变量做检验,本质是把伯努利分布当正态用——当正样本数 normaltest 必然失败,p 值完全不可信。
- 正确做法是用
scipy.stats.fisher_exact(2×2 列联表)或scipy.stats.chi2_contingency(样本量大时) -
fisher_exact要求输入二维数组:[[a, b], [c, d]],其中a=付费且实验组,b=未付费且实验组,以此类推 - 若任意单元格期望频数 chi2_contingency 的卡方近似失效,必须切回
fisher_exact - 不要用
proportions_ztest(来自statsmodels),它底层仍依赖正态近似,在 n₁p₁
校正多重检验时,scipy.stats.false_discovery_control 不是万能解
业务常需同时检验多个指标(如点击率、停留时长、复购率),这时即使单个 mannwhitneyu p false_discovery_control,但它只适用于独立检验,而业务指标间往往强相关(如点击高的人停留也长)。
- 若指标间相关性 > 0.3(用
np.corrcoef粗估),false_discovery_control会过度校正,把真实信号压成不显著 - 更稳妥的做法是:先用
scipy.cluster.hierarchy对指标做层次聚类,每类选一个代表性指标再校正 - 或者直接改用
statsmodels.stats.multitest.multipletests的'holm'方法——它对相关性不敏感,比 FDR 更保守但更可靠
scipy.stats.rankdata 计算的 Cliff’s delta)一起看。p 值告诉你“是不是偶然”,delta 才告诉你“差多少”。没效应量的显著性,在业务决策里基本等于无效信息。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











