共计 2930 个字符,预计需要花费 8 分钟才能阅读完成。
概念辨析
1. 潜在结果框架与反事实假设
AB 实验(又称随机对照试验 -Randomized Controlled Trial)的核心数学表达是潜在结果框架(Potential Outcomes)。对于个体 i,其处理效应 τ 可表示为:

τ_i = Y_i(1) - Y_i(0)
其中 Y(1)和 Y(0)分别表示接受处理和不接受处理的潜在结果。由于个体无法同时处于两种状态,实践中我们估计平均处理效应(ATE):
ATE = E[Y(1) - Y(0)]
与因果推断的关键差异在于:
- AB 实验通过随机化满足 可忽略性假设(Ignorability):
(Y(1), Y(0)) ⊥ T - 因果推断中的观察性研究需额外控制混淆变量(Confounder)Z 来满足:
(Y(1), Y(0)) ⊥ T | Z
2. 混淆变量的可视化分析
通过有向无环图(DAG-Causal Graph)展示典型场景:
T → Y
↑
Z
在 AB 实验中,随机化会切断 Z 到 T 的边,而观察性研究中这条路径会导致偏差。这就是为什么电商场景中新用户占比变化(Z)可能扭曲人工分组(T)对转化率(Y)的影响评估。
实战代码
1. 双样本 t 检验实现
import numpy as np
from scipy import stats
def ttest_ab(data_A: np.ndarray, data_B: np.ndarray, alpha: float = 0.05) -> dict:
"""
执行双样本 t 检验
:param data_A: 对照组数据数组
:param data_B: 实验组数据数组
:param alpha: 显著性水平
:return: 包含统计量和 p 值的字典
"""
t_stat, p_val = stats.ttest_ind(data_A, data_B, equal_var=False)
return {
'statistic': t_stat,
'pvalue': p_val,
'significant': p_val < alpha
}
# 模拟数据示例
control = np.random.normal(5, 1, 1000)
treatment = np.random.normal(5.2, 1, 1000)
print(ttest_ab(control, treatment))
2. 样本量计算
from statsmodels.stats.power import tt_ind_solve_power
def calculate_sample_size(
effect_size: float,
alpha: float = 0.05,
power: float = 0.8
) -> int:
"""
计算每组所需最小样本量
:param effect_size: 标准化效应量(Cohen's d):param alpha: 第一类错误概率
:param power: 统计功效
:return: 每组样本量(向上取整)"""
n = tt_ind_solve_power(
effect_size=effect_size,
alpha=alpha,
power=power,
ratio=1.0
)
return int(np.ceil(n))
# 检测转化率从 10% 提升到 12% 所需样本量(效应量≈0.2)print(f"每组需要样本量:{calculate_sample_size(0.2)}")
生产建议
1. 新用户效应处理
当实验中新用户占比异常时:
- 使用分层分析(Stratification)分别计算新旧用户群体的处理效应
- 通过协变量调整(Covariate Adjustment)在模型中添加用户类型特征
- 延长实验周期至 2 - 4 周,待用户行为稳定后分析
2. 多重检验校正
from statsmodels.stats.multitest import multipletests
def bonferroni_correction(p_values: list, alpha: float = 0.05) -> list:
"""
Bonferroni 校正实现
:param p_values: 原始 p 值列表
:param alpha: 总体显著性水平
:return: 校正后的显著性判断数组
"""_, adj_p, _, _ = multipletests(p_values, method='bonferroni')
return adj_p < alpha
# 示例:同时测试转化率、客单价、留存率三个指标
pvals = [0.03, 0.01, 0.08]
print(bonferroni_correction(pvals)) # [False, True, False]
3. 倾向得分匹配
当无法随机分组时,可用 PSM 模拟 RCT:
from sklearn.linear_model import LogisticRegression
def propensity_score_matching(
X: np.ndarray, # 特征矩阵
y: np.ndarray, # 处理组标记
n_neighbors: int = 1
) -> np.ndarray:
"""
计算倾向得分并进行最邻近匹配
:return: 匹配后的处理组索引数组
"""
ps_model = LogisticRegression().fit(X, y)
ps_scores = ps_model.predict_proba(X)[:, 1]
# 简化的最邻近匹配(实际生产建议用专门的库如 causalml)treated_idx = np.where(y == 1)[0]
control_idx = np.where(y == 0)[0]
matched = []
for i in treated_idx:
dist = np.abs(ps_scores[control_idx] - ps_scores[i])
matched.append(control_idx[np.argmin(dist)])
return np.array(matched)
延伸思考
1. 差分法替代方案
当无法进行随机分组时,双重差分法(DID-Difference in Differences)的估计公式:
DID = (E[Y|T=1,Post] - E[Y|T=1,Pre]) - (E[Y|T=0,Post] - E[Y|T=0,Pre])
关键假设是平行趋势(Parallel Trends),可通过预处理期数据验证。
2. 辛普森悖论练习
动手任务:用以下数据集验证群体反转现象
import pandas as pd
data = pd.DataFrame({'group': ['A','A','B','B'],
'subgroup': [1,2,1,2],
'conversion': [0.5, 0.8, 0.7, 0.4],
'sample_size': [200, 100, 100, 200]
})
# 任务:分别计算总体和分组的转化率差异
参考文献
- Rubin, D.B. (2005). Causal Inference Using Potential Outcomes
- Imbens, G.W. (2015). Causal Inference for Statistics
- Kohavi, R. (2020). Trustworthy Online Controlled Experiments
通过本文的代码实践和理论对比,希望能帮助读者清晰区分 AB 实验与因果推断的应用边界。当面对 ” 观察数据能否替代实验 ” 的决策时,不妨先画出 DAG 图验证关键假设是否成立。
正文完
