共计 2366 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:为什么你的 AB 实验结果不可信?
在互联网产品迭代中,AB 实验是验证新功能效果的核心工具。但实践中常遇到三大经典问题:

- 样本偏差(Sample Bias):非随机分流导致实验组 / 对照组用户特征分布不均,比如将新用户全部划入实验组
- 混杂变量(Confounding Variables):未控制的隐藏变量同时影响实验分组和结果指标,例如用户活跃度既影响看到的 UI 版本又影响转化率
- 多重检验(Multiple Testing):同时检查多个指标时,5% 的显著性水平下至少出现一个假阳性的概率高达 40%(当检验 20 个指标时)
技术方案:从随机化到因果推断
实验设计选择
- 完全随机实验(Completely Randomized Experiment):
- 适用场景:用户特征均匀分布,无显著分层因素
-
实现方式:直接用
np.random.choice()进行分流 -
分层随机化(Stratified Randomization):
- 适用场景:存在已知重要协变量 (Covariate) 如用户等级、地理位置
- 实现示例:按用户城市分层后,在各层内独立随机分配
因果推断方法
- 双重差分法(Difference-in-Differences, DID):
- 核心思想:比较实验组 / 对照组在实验前后的指标变化差异
-
适用条件:平行趋势假设(Parallel Trends Assumption)
-
倾向得分匹配(Propensity Score Matching, PSM):
- 实现步骤:
- 用逻辑回归估计每个用户进入实验组的概率
- 为实验组用户在对照组寻找倾向得分最近的匹配用户
- 在匹配后的样本上计算处理效应
代码实现:从理论到 Python 实践
动态流量分配示例
import numpy as np
from typing import List, Dict
def thompson_sampling(rewards: Dict[str, List[float]],
n_arms: int = 2) -> int:
"""
Thompson Sampling 动态流量分配实现
Parameters
----------
rewards : dict
各实验组的历史奖励记录,格式为{"arm1":[1,0,1,...],...}
n_arms : int
实验分组数量
Returns
-------
int
本次请求分配的分组索引(0~n_arms-1)
"""
beta_params = []
for arm in range(n_arms):
key = f"arm{arm+1}"
successes = sum(rewards.get(key, []))
failures = len(rewards.get(key, [])) - successes
# 贝塔分布采样
sample = np.random.beta(successes + 1, failures + 1)
beta_params.append(sample)
return np.argmax(beta_params)
因果效应计算(使用 CausalML)
from causalml.inference.meta import LRSRegressor
import pandas as pd
# 生成模拟数据
n_samples = 1000
data = pd.DataFrame({'feature1': np.random.normal(size=n_samples),
'treatment': np.random.binomial(1, 0.5, n_samples),
'outcome': np.random.normal(loc=2, scale=1, size=n_samples)
})
# 计算平均处理效应(ATE)
lr = LRSRegressor()
ate = lr.estimate_ate(X=data[['feature1']],
treatment=data['treatment'],
y=data['outcome']
)
print(f"ATE 估计值: {ate[0]:.3f}, 标准误: {ate[1]:.3f}")
生产环境关键考量
样本量计算
所需最小样本量公式:
N = (Z_{1-α/2} + Z_{1-β})^2 * (σ^2/(p*(1-p))) / δ^2
其中:
– δ 为要检测的最小效应量(Minimum Detectable Effect)
– σ 为指标标准差
– p 为分流比例
– α 为显著性水平,β 为统计功效
新奇效应应对
- 冷启动期排除:剔除实验前 3 天的数据
- 用户分层分析:单独观察新老用户表现
- 渐进式发布:从 5% 流量开始逐步放大
常见陷阱与解决方案
辛普森悖论识别
- 现象:分组看结论与合并看结论相反
- 检测方法:
- 检查各分层下的效应方向
- 用因果图 (Causal Graph) 识别混淆变量
多重检验校正
from statsmodels.stats.multitest import multipletests
p_values = [0.01, 0.04, 0.03, 0.2] # 原始 p 值
reject, corrected_p, _, _ = multipletests(p_values, method='bonferroni')
print(f"校正后显著结果: {reject}") # [True, False, False, False]
延伸阅读
- 经典论文:《Mostly Harmless Econometrics》- Angrist & Pischke
- 开源项目:
- DoWhy(微软因果推断库)
- EconML(微软因果机器学习库)
- 在线课程:Udacity 的【A/B Testing】纳米学位
实践心得
在金融行业落地 AB 实验时,我们发现两个特别需要注意的点:首先是数据延迟问题——交易数据往往 T + 1 才能获取,这要求实验周期设计要拉长;其次是用户交叉影响,当实验涉及社交功能时,需要采用集群随机化 (Cluster Randomization) 代替个体随机化。这些经验都是在踩坑后总结出来的,希望对同行们有所启发。
正文完
