常见统计陷阱
问题
数据分析中有哪些常见的统计误区和陷阱?如何避免得出错误结论?
答案
1. 相关不等于因果
陷阱:看到两个变量相关就下因果结论。
伪相关示例
import pandas as pd
import numpy as np
# 两个完全无关的时间序列可能高度相关
months = pd.date_range('2020-01', periods=36, freq='M')
ice_cream_sales = np.array([10,12,20,35,50,60,55,45,30,15,10,8] * 3) # 季节性
drowning_deaths = np.array([5,6,12,20,30,35,32,25,15,8,5,4] * 3) # 也有季节性
r = np.corrcoef(ice_cream_sales, drowning_deaths)[0,1]
print(f"相关系数: {r:.3f}") # 很高!
# 但冰淇淋不会导致溺水 → 共同受"气温"影响
避免方法
- 寻找混淆变量(温度、季节等)
- 用随机对照实验(A/B 测试)验证因果
- 使用因果推断方法(DID、RDD、PSM)
2. 辛普森悖论(Simpson's Paradox)
陷阱:总体趋势和分组趋势方向相反。
辛普森悖论
import pandas as pd
# 两个医院的手术成功率
data = {
'医院': ['A', 'A', 'B', 'B'],
'病情': ['轻症', '重症', '轻症', '重症'],
'手术数': [800, 200, 200, 800],
'成功数': [720, 140, 175, 560],
}
df = pd.DataFrame(data)
df['成功率'] = df['成功数'] / df['手术数']
print(df)
# A 医院轻症 90%, 重症 70% → 各组都比 B 好
# B 医院轻症 87.5%, 重症 70%
# 但总体成功率:
# A: (720+140) / 1000 = 86%
# B: (175+560) / 1000 = 73.5% ← 等等...
# 换一组数据让悖论出现:
# A 接收更多重症 → 总体被拉低
# B 接收更多轻症 → 总体被拉高
print("→ 分组看 A 更好,但总体可能 B 更好(取决于病人分布)")
避免方法
- 按维度下钻分析,不要只看总数
- 业务分析中先看用户构成是否变化
- 留存率、转化率等指标,先看各群体的变化再看总体
3. 幸存者偏差(Survivorship Bias)
陷阱:只分析"存活"的数据,忽略已流失/失败的样本。
| 场景 | 偏差 | 正确做法 |
|---|---|---|
| "成功企业都做了 X" | 忽略了做 X 但失败的企业 | 对比成功/失败企业 |
| "活跃用户满意度高" | 不满意的已经流失 | 包含流失用户的调研 |
| "二战飞机加固机翼" | 返航飞机机翼中弹→修机翼 | 没返航的才是关键部位 |
4. 多重比较问题
陷阱:同时做多次假设检验,假阳性率急剧上升。
做 20 次测试(α=0.05)→ 的概率出现至少一个假阳性!
多重比较校正
from statsmodels.stats.multitest import multipletests
import numpy as np
# 假设同时跑了 20 个指标的 A/B 测试
p_values = [0.03, 0.08, 0.01, 0.15, 0.04, 0.52, 0.02, 0.23,
0.07, 0.91, 0.005, 0.33, 0.06, 0.44, 0.02, 0.11,
0.85, 0.04, 0.09, 0.67]
# Bonferroni 校正(最保守):α' = α / n
reject_bonf, pvals_bonf, _, _ = multipletests(p_values, alpha=0.05, method='bonferroni')
print(f"Bonferroni 校正后显著个数: {sum(reject_bonf)}")
# BH 校正(FDR 控制,推荐)
reject_bh, pvals_bh, _, _ = multipletests(p_values, alpha=0.05, method='fdr_bh')
print(f"BH 校正后显著个数: {sum(reject_bh)}")
5. 基数率谬误(Base Rate Neglect)
陷阱:忽略先验概率(基数率),被条件概率误导。
例:某广告"精准人群"点击率 5%,远高于全站 1%。但如果这个精准人群只有 100 人(5 次点击),而全站有 100 万人(1 万次点击),5% 可能只是小样本波动。
避免方法
- 关注绝对量,不只看比率
- 小样本的比率不可靠,计算置信区间
- 结合贝叶斯思维评估概率
6. 选择偏差
| 类型 | 说明 | 示例 |
|---|---|---|
| 自选择偏差 | 参与者自愿加入 | 调查问卷只有热心用户回复 |
| 时间偏差 | 不同时间段的用户不同 | 早期用户 vs 最新用户 |
| 覆盖不全 | 数据没覆盖所有群体 | 只分析 App 用户,遗漏 Web |
| 删失偏差 | 数据被截断 | 只看已完成订单,忽略取消的 |
7. 过度拟合已有数据
(数据挖掘中的"事后诸葛亮")
过度拟合分析
# 反面教材:在同一份数据上反复筛选条件,总能找到"显著"结果
import numpy as np
np.random.seed(0)
# 纯随机数据
data = np.random.randn(1000, 50) # 1000 行, 50 个特征
target = np.random.randint(0, 2, 1000) # 随机标签
# 如果对 50 个特征逐一做 t 检验,p<0.05 的约有 2-3 个
# 但这些都是假阳性!→ 需要用训练集/测试集分离验证
8. 数据分析常见错误清单
常见面试问题
Q1: 如何避免 A/B 测试中的假阳性?
答案:
- 提前确定样本量,不能"跑到显著就停"(p-hacking)
- 多指标测试时进行多重比较校正(BH/Bonferroni)
- 设定主要指标和次要指标,只对主要指标做显著性判断
- 使用序贯检验(Sequential Testing)如果确实需要提前查看
Q2: 辛普森悖论在业务中有什么例子?
答案:
- DAU 增长但留存下降 → 新用户大量涌入(低留存)稀释了老用户的高留存
- 总转化率提升但各渠道都下降 → 高转化渠道占比降低
- 对策:始终按渠道/人群/时段下钻分析,不只看 Total
Q3: p-hacking 是什么?如何避免?
答案:
- p-hacking:反复尝试不同分析方法/子集/指标,直到找到 p < 0.05
- 常见手法:删除异常值直到显著、增加/删除控制变量、选择性报告
- 避免方法:
- 提前注册分析计划(预注册)
- 报告所有分析过的指标
- 使用校正后的 p 值
- 区分探索性分析和验证性分析
Q4: 平均值陷阱有哪些?
答案:
- 均值 vs 中位数:收入分布右偏,均值被极端值拉高,中位数更代表"普通人"
- 平均数悖论:A 和 B 两组合并后均值可能误导(辛普森悖论)
- 百分比的均值:不能直接对百分比求均值(需加权)
- 建议:同时报告均值、中位数、分位数,展示分布而非单一数字
Q5: 面对一份分析结论,你会如何质疑/检验?
答案(框架):
- 数据来源:数据采集是否有偏差?覆盖面是否完整?
- 样本量:是否足够大?置信区间有多宽?
- 混淆变量:是否控制了关键变量?
- 因果方向:相关 ≠ 因果,有没有反向因果?
- 子群分析:总体结论在各子群中是否一致?(辛普森悖论)
- 时间因素:是否考虑了季节性、趋势变化?