实战项目

第34课:A/B测试

实验设计、样本量计算、统计检验、多重比较、序贯分析

1. A/B测试流程

定义假设→确定指标→计算样本量→随机分组→运行→统计检验→决策

2. 实验设计

H₀: μ_B=μ_A, H₁: μ_B≠μ_A

指标选择:OEC(核心业务指标)、数据指标(直接受影响)、护栏指标(不能恶化)

随机化:用户级/会话级/分层随机化

陷阱:Simpson悖论、溢出效应、新手效应

3. 样本量

n = (Z_α/2+Z_β)²σ²/(μ_A-μ_B)²

4. 统计检验

比例→Z检验/卡方检验。连续→t检验/Welch's t。非参数→Mann-Whitney U

报告置信区间比p值更有用。

5. 多重比较

Bonferroni(保守FWER) vs BH(FDR更不保守)

序贯分析:预定义检查点+α消耗函数

Python代码实现与验证

💡 代码说明:以下代码使用 Python / Scikit-learn 实现,已实机运行验证。

完整代码


import numpy as np
from scipy import stats
from statsmodels.stats.power import TTestIndPower
from statsmodels.stats.proportion import proportions_ztest
from statsmodels.stats.multitest import multipletests
np.random.seed(42)

print("=== 样本量计算 ===")
pa = TTestIndPower()
baseline = 0.10; mde = 0.005
es = mde/np.sqrt(baseline*(1-baseline)*2)
n = pa.solve_power(effect_size=es, power=0.8, alpha=0.05)
print("基线{:.0%} MDE{:.1%} 每组需{}样本".format(baseline,mde,int(n)+1))

print("\n=== 模拟A/B测试 ===")
N = 10000
ca = np.random.binomial(1, 0.10, N)
cb = np.random.binomial(1, 0.105, N)
z,p = proportions_ztest([cb.sum(),ca.sum()], [N,N], alternative='larger')
diff = cb.mean()-ca.mean()
se = np.sqrt(cb.var()/N+ca.var()/N)
print("A={:.4f} B={:.4f} diff={:.4f} z={:.4f} p={:.4f}".format(ca.mean(),cb.mean(),diff,z,p))
print("95%CI: [{:.4f},{:.4f}]".format(diff-1.96*se, diff+1.96*se))

print("\n=== 多重比较 ===")
pvals = [0.02,0.03,0.15,0.008,0.04]
r1,_,_,_ = multipletests(pvals,method='bonferroni')
r2,_,_,_ = multipletests(pvals,method='fdr_bh')
print("原始p: {} Bonferroni拒绝: {} BH拒绝: {}".format(pvals, list(r1), list(r2)))

print("\n=== 连续指标 ===")
ra = np.random.exponential(50,N)+10
rb = np.random.exponential(55,N)+10
t,p = stats.ttest_ind(ra,rb)
tw,pw = stats.ttest_ind(ra,rb,equal_var=False)
print("A={:.2f} B={:.2f} t={:.4f} p={:.4f} Welch p={:.4f}".format(ra.mean(),rb.mean(),t,p,pw))

运行结果

=== 样本量计算 === 基线10% MDE0.5% 每组需113025样本 === 模拟A/B测试 === A=0.0961 B=0.1078 diff=0.0117 z=2.7342 p=0.0031 95%CI: [0.0033,0.0201] === 多重比较 === 原始p: [0.02, 0.03, 0.15, 0.008, 0.04] Bonferroni拒绝: [np.False_, np.False_, np.False_, np.True_, np.False_] BH拒绝: [np.True_, np.True_, np.False_, np.True_, np.True_] === 连续指标 === A=59.81 B=64.70 t=-6.6340 p=0.0000 Welch p=0.0000
✅ 验证通过

深入理解:从项目到产品的关键步骤

ML项目成功的关键因素

  1. 定义清晰的目标:业务指标 > ML指标(提升AUC不是目的,提升收入才是)
  2. 数据质量:Garbage in, garbage out。花80%时间在数据上是正常的
  3. 简单优先:简单基线 > 复杂模型(如果简单就够了)
  4. 持续监控:模型上线不是终点,漂移检测和重训练是必须的
  5. 沟通能力:能向非技术人解释模型为什么做某个预测

项目时间分配建议

阶段时间占比关键产出
问题定义10%明确的评估指标和成功标准
数据获取/清洗30%干净可用的数据集
特征工程25%强特征集
模型训练/调优20%最优模型
评估/部署15%上线模型+监控方案

从竞赛到生产的差距

Kaggle竞赛和实际生产的差异:

ML系统技术债

D. Sculley等人在2015年的经典论文中指出,ML系统中只有很小一部分是实际的ML代码,其余都是胶水代码、配置、数据管道、监控等。隐藏的技术债包括:

项目复盘与进阶路线

5个项目的核心收获

  1. 房价预测:回归全流程——EDA→特征工程(对数变换+交叉特征)→多模型比较→融合。关键教训:特征工程比模型选择更重要,对数变换处理右偏目标是标准操作。
  2. 欺诈检测:极度不平衡——SMOTE/类别权重/异常检测框架。关键教训:AUC-PR比AUC-ROC更有意义,监督方法远优于无监督方法。
  3. 客户分群:无监督业务应用——RFM+聚类+画像解读。关键教训:业务可解释性比聚类指标重要,K值选择要考虑运营成本。
  4. 推荐基础:推荐系统经典算法——协同过滤+矩阵分解。关键教训:冷启动是最难的问题,简单方法(SVD)常常足够好。
  5. 文本分类:NLP传统方法——TF-IDF+NB/SVM。关键教训:预处理影响巨大,线性SVM在文本上通常最好。

从竞赛到生产的差距

维度竞赛生产
数据已清洗CSV多源异构、实时流
目标单一指标多目标(精度+延迟+成本)
模型复杂集成简单高效、可维护
评估离线CV在线A/B测试
部署不涉及Docker/K8s/服务化
监控不涉及漂移检测+重训练

继续学习路线

推荐学习资源

类别资源特点
教材ISLR (Python版)统计学习入门经典
教材ESL统计学习圣经(进阶)
课程Andrew Ng ML最佳入门课
课程Stanford CS229更数学化
实践Kaggle Learn动手学ML
文档Scikit-learn最优秀的ML库文档

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

补充:关键概念与面试要点

核心直觉

常见面试问题

  1. L1正则化为什么产生稀疏解?(几何:菱形与等高线在角上相交)
  2. 逻辑回归为什么用交叉熵而不用MSE?(MSE导致梯度消失)
  3. 随机森林为什么不容易过拟合?(Bagging降方差,特征随机降相关性)
  4. K-Means为什么收敛到局部最优?(目标函数非凸)
  5. PCA为什么需要中心化?(否则第一主成分指向均值方向)

📝 课后练习

  1. 计算A/B测试样本量
  2. 实现比例差异Z检验
  3. 比较多重比较校正方法
  4. 实现连续指标A/B测试
  5. 设计完整A/B测试方案
🧪
实验设计师
完成A/B测试项目