一粟 · yisu.app
· 12 min read
数据分析

数据分析中的采样偏差与置信区间

为什么「提升 5%」可能其实是统计噪声?怎么用置信区间和分位数代替均值来描述真实分布?本文以一份用户行为分析报告为引,谈工程师应该掌握的基本统计直觉。

一份让人吃惊的实验数据

去年我看到一份 A/B 实验报告:新版的「加入购物车按钮」让转化率提升 5.2%,p < 0.05。看起来很有说服力。但当我们拆分到 P75/P90 分位数时发现,转化率变化主要来自一两个异常样本的拉动。这种「有意义 ≠ 可信」的怪现象,在业务数据分析中很常见。

均值在长尾分布下是个有缺陷的统计量。我们需要分位数、置信区间、稳健估计。

为什么「采样偏差」无处不在

采样偏差(sampling bias)指你看到的数据不是总体的无偏代表。在生产环境里,这种情况几乎必然发生:

  • 自选择偏差:用户愿意点按钮的人 ≠ 所有用户。
  • 存活者偏差:分析活跃用户会把流失用户剔除。
  • 时间偏差:周末与周中的行为模式差异。
  • 设备偏差:移动 / PC 用户行为不同。

一个常见的错误是用「活跃用户」统计所有用户——但活跃用户的特征整体偏向「喜欢这个 app」。

置信区间:给数字加一份「不确定度」

均值只是一个点估计。配上置信区间,它才会告诉你「这个范围里我们有 95% 的把握」。例如:

import numpy as np
from scipy import stats

# 模拟 A/B 实验
np.random.seed(0)
A = np.random.binomial(1, 0.10, size=4000)
B = np.random.binomial(1, 0.105, size=4000)

mean_a, mean_b = A.mean(), B.mean()
se_a = np.sqrt(A.mean() * (1 - A.mean()) / len(A))
se_b = np.sqrt(B.mean() * (1 - B.mean()) / len(B))
print(f"A 95% CI: {mean_a:.4f} ± {1.96*se_a:.4f}")
print(f"B 95% CI: {mean_b:.4f} ± {1.96*se_b:.4f}")

p-value 是「证据强度」,不是「差异大小」

p < 0.05 经常被解读为「差异显著」,这是错的。它真正的意思是:在零假设成立下看到这样极端数据的概率 < 5%。但它没告诉差异有多大、可信度有多高。

更现代的统计做法:

  • 效应量:差异的大小本身(不止相对差异)。
  • 置信区间:差异所在的可能范围。
  • 贝叶斯视角:两组差异在先验下的后验概率。

分位数比均值更可靠

在长尾分布(用户时长、订单金额、页面数量等),均值会被极少数极端样本拉偏。比如分析「用户每日使用时长」:

统计量解读
均值22 分钟被少数长时间用户拉高
中位数12 分钟真实「典型」更近
P9055 分钟深度用户水平
P99120 分钟极少数极端用户

当我们想描述「典型用户」行为时,用中位数与四分位距;当我们想知道「极端情况」时,看 P95/P99。

SLO 应当用分位数定义

工程里的「稳定性」应该用分位数描述,而不是平均值。常见做法:

  • P99 错误率 < 1%。
  • P95 延迟 < 800ms。
  • P50 延迟 < 200ms。

这种描述比「平均错误率」要准确得多,因为它直接对应用户感受到的最差体验。

生存偏差下的留存分析

另一个常见坑是把「1 个月内仍然活跃」称作「留存率」,但忽略了「它们在统计窗口之后才注册」的情况。改进做法是用 cohort-based retention:把用户按注册周分组,观察他们后续 N 周的回访率。

抽样与权重:尽量靠近总体

如果你必须从样本推断总体,记得给样本做「权重校准」。例如:

  • 采样时老年人占比太低,加权匹配总体比例。
  • 新发布版本覆盖度偏向 iOS,要按平台做反比例加权。

这个动作在商业分析里叫 post-stratification,工程师通常能在 SQL 里就处理掉。

A/B 实验的最小样本量

在任何 A/B 实验启动前,先算最小样本量。计算公式:

from statsmodels.stats.power import NormalIndPower
from statsmodels.stats.proportion import proportion_effectsize

# 想检测 1% → 1.05% 的差异
effect = proportion_effectsize(0.01, 0.0105)
n = NormalIndPower().solve_power(effect, alpha=0.05, power=0.8)
print(f"每组至少需要样本: {n:.0f}")

更小的样本量意味着「即使有差异也可能检测不到」。这是经常被新手忽略的事。

几条工程实践建议

  • 所有 KPI 都配上「同环比」「置信区间」。
  • 报表里加上 P50 / P75 / P90 / P99 四个分位。
  • 任何「转化率提升」都要看分位变化。
  • 非用户主动上报数据要核对样本是否代表总体。
  • 多用差分指标与对照组,少用绝对值。

工程师对统计学的「基本掌握」比偶尔的「精通」更重要。前者会让你看起来「普通但稳定」,后者会让你「忽高忽低」。做好基本功,做业务的人会越来越尊重你。