本文目录导读:

- 方案一:针对连续型指标(如用户平均消费、留存天数)
- 方案二:针对二分类指标(如点击率、转化率)
- 方案三:计算效应量(Cohen‘s d)和置信区间
- 方案四:一次性完成完整A/B测试报告
- 什么时候不能用t检验或Z检验?
- 判断显著性的完整检查清单
在Python中进行A/B测试的显著性计算,通常涉及假设检验,最常用的方法是双样本t检验(针对均值,如转化率、平均订单金额)或Z检验(针对比例,如点击率)。
以下是完整的实战指南,包含代码示例。
针对连续型指标(如用户平均消费、留存天数)
使用 scipy.stats.ttest_ind。
import numpy as np
from scipy import stats
# 模拟数据:A组(对照组)和B组(实验组)
np.random.seed(42)
group_a = np.random.normal(loc=100, scale=20, size=1000) # 均值100
group_b = np.random.normal(loc=105, scale=20, size=1000) # 均值105
# 执行独立样本t检验
t_stat, p_value = stats.ttest_ind(group_a, group_b)
print(f"T统计量: {t_stat:.4f}")
print(f"P值: {p_value:.4f}")
# 判断是否显著(通常alpha=0.05)
alpha = 0.05
if p_value < alpha:
print(" 存在显著差异 (拒绝原假设)")
else:
print(" 无显著差异 (无法拒绝原假设)")
针对二分类指标(如点击率、转化率)
使用 proportions_ztest 进行双比例Z检验。
from statsmodels.stats.proportion import proportions_ztest
# 数据示例:A组1000人中120人点击,B组1000人中150人点击
successes = [120, 150] # 成功事件数
trials = [1000, 1000] # 总样本量
z_stat, p_value = proportions_ztest(count=successes, nobs=trials)
print(f"Z统计量: {z_stat:.4f}")
print(f"P值: {p_value:.4f}")
alpha = 0.05
if p_value < alpha:
print(" B组转化率显著高于A组")
else:
print(" 两组无显著差异")
计算效应量(Cohen‘s d)和置信区间
除了P值,业务上更常关注效应大小和置信区间。
from scipy.stats import norm
# 使用方案一的数据
mean_a, mean_b = np.mean(group_a), np.mean(group_b)
std_a, std_b = np.std(group_a, ddof=1), np.std(group_b, ddof=1)
n_a, n_b = len(group_a), len(group_b)
# Cohen’s d (效应量)
pooled_std = np.sqrt(((n_a-1)*std_a**2 + (n_b-1)*std_b**2) / (n_a+n_b-2))
cohens_d = (mean_b - mean_a) / pooled_std
print(f"Cohen‘s d: {cohens_d:.3f}") # 0.2小, 0.5中, 0.8大
# 均值差的95%置信区间
diff = mean_b - mean_a
se = np.sqrt(std_a**2/n_a + std_b**2/n_b)
z_critical = norm.ppf(0.975) # 1.96
ci_lower = diff - z_critical * se
ci_upper = diff + z_critical * se
print(f"均值差 95% CI: [{ci_lower:.2f}, {ci_upper:.2f}]")
一次性完成完整A/B测试报告
封装成一个函数,自动输出统计量、P值、效应量和结论。
def ab_test_report(control, treatment, metric_type=“continuous”, alpha=0.05):
"""
完整的A/B测试显著性报告
:param control: 对照组数据 (list or array)
:param treatment: 实验组数据
:param metric_type: “continuous” (连续) 或 “binary” (二分类, 输入为[成功数, 总样本])
:param alpha: 显著性水平
:return: 打印报告
"""
if metric_type == “continuous”:
t_stat, p_value = stats.ttest_ind(control, treatment)
mean_c, mean_t = np.mean(control), np.mean(treatment)
diff = mean_t - mean_c
# 效应量
n_c, n_t = len(control), len(treatment)
var_c, var_t = np.var(control, ddof=1), np.var(treatment, ddof=1)
pooled_std = np.sqrt(((n_c-1)*var_c + (n_t-1)*var_t) / (n_c+n_t-2))
effect_size = diff / pooled_std
# 置信区间
se = np.sqrt(var_c/n_c + var_t/n_t)
ci = (diff - 1.96*se, diff + 1.96*se)
print(f”均值差: {diff:.3f}“)
print(f”95% CI: [{ci[0]:.3f}, {ci[1]:.3f}]“)
elif metric_type == “binary”:
successes = [control[0], treatment[0]]
trials = [control[1], treatment[1]]
z_stat, p_value = proportions_ztest(count=successes, nobs=trials)
p_c = control[0] / control[1]
p_t = treatment[0] / treatment[1]
diff = p_t - p_c
effect_size = diff / np.sqrt(p_c * (1-p_c) / control[1])
ci = (diff - 1.96*np.sqrt(p_c*(1-p_c)/control[1] + p_t*(1-p_t)/treatment[1]),
diff + 1.96*np.sqrt(p_c*(1-p_c)/control[1] + p_t*(1-p_t)/treatment[1]))
print(f”对照组转化率: {p_c:.3f}“)
print(f”实验组转化率: {p_t:.3f}“)
print(f”转化率差: {diff:.3f}“)
print(f”95% CI: [{ci[0]:.3f}, {ci[1]:.3f}]“)
print(f”P值: {p_value:.4f}“)
print(f”效应量(Cohen‘s d): {effect_size:.3f}“)
if p_value < alpha:
print(“ ✅ 存在显著差异”)
else:
print(“ ❌ 无显著差异”)
# 使用示例
ab_test_report(group_a, group_b, metric_type=“continuous”)
ab_test_report([120, 1000], [150, 1000], metric_type=“binary”)
什么时候不能用t检验或Z检验?
如果数据不符合正态分布,或样本量很小(<30),建议使用非参数检验:
# Mann-Whitney U检验(独立样本的非参数版本)
u_stat, p_value = stats.mannwhitneyu(group_a, group_b, alternative=‘two-sided’)
print(f”U统计量: {u_stat}, P值: {p_value}“)
# 或 Bootstrap 法(推荐,不依赖分布假设)
def bootstrap_ab_test(a, b, n_bootstrap=10000):
diff = np.mean(b) - np.mean(a)
combined = np.concatenate([a, b])
diffs = []
for _ in range(n_bootstrap):
sample_a = np.random.choice(combined, size=len(a), replace=True)
sample_b = np.random.choice(combined, size=len(b), replace=True)
diffs.append(np.mean(sample_b) - np.mean(sample_a))
p_value = (np.sum(np.abs(diffs) >= np.abs(diff)) + 1) / (n_bootstrap + 1)
return p_value
print(f”Bootstrap P值: {bootstrap_ab_test(group_a, group_b):.4f}“)
判断显著性的完整检查清单
- 样本量:每组至少几百(比例指标至少每组1000个样本)。
- 随机化:确保用户被完全随机分配。
- 多重比较:如果跑了很多个指标,需要做 Bonferroni 或 FDR 校正。
- 实战业务:统计显著 ≠ 业务显著,即使P值很小,也要看效应量是否值得投入开发资源(比如转化率提升0.1%,但成本很高,可能不值得上线)。
如果你有具体的数据结构(比如是DataFrame列),可以告诉我,我可以帮你写对应的代码。