把“扔硬币”搬到互联网:一文看懂 AB 测试的底层逻辑 - 指南

news/2025/10/20 13:28:21/文章来源:https://www.cnblogs.com/lxjshuju/p/19152435

“新版按钮到底是红色好还是绿色好?”——这个问题在会议室里出现的频率,远高于“今晚吃什么”。产品经理拍桌子说红色吸睛,设计师翻白眼说绿色高级,老板最后拍板:“那就各一半流量,跑一周看数据。” 这句看似和稀泥的决策,其实正是 AB 测试(AB Test)最朴素的原型。本文用 3000 字把“扔硬币”这一古老统计学动作,还原成一套可在互联网规模落地的实验框架。读完以后,你可以亲手设计一场最小可运行的 AB 测试,也能一眼识别“P 值造假”或“辛普森悖论”这类常见深坑。


目录

一、从“农田裂区”到“云端分流”:AB 测试简史

二、核心概念:随机单元、指标、假设、检验

三、样本量计算:为什么“跑一周”不一定够

四、分流机制:哈希、时间片与多层正交

五、P 值陷阱:0.05 不是魔法门限

六、多重检验与序贯检验:跑得多、看得早也会错

七、常见深坑清单:辛普森、选择偏倚、网络效应

八、工具与代码:用 Python 完成一次最小可行实验

十、结语:把实验文化种进 DNA


一、从“农田裂区”到“云端分流”:AB 测试简史

现代 AB 测试的源头是 20 世纪 20 年代英国农学家 Ronald Fisher 的“裂区实验”。Fisher 为了验证不同肥料对马铃薯产量的影响,把一块大田划成若干小区,随机施加肥料,再用 t 检验判断差异是否显著。这一方法在 90 年代被直销公司搬进邮寄广告:一半用户收到红色信封,一半收到蓝色信封,哪一版回信率高就用哪一版。2000 年 Google 工程师将同样的思想写进代码,把搜索结果页的标题颜色从#0000FF 改成#0044CC,首次在云端完成“毫秒级分流+天级回收”,互联网 AB 测试由此诞生。由此可见,AB 测试的本质从未改变:通过随机化排除混杂因子,用统计量度量因果效应。


二、核心概念:随机单元、指标、假设、检验

一场合规的 AB 测试必须同时定义四个要素,否则后续所有结论都站不住脚。

  1. 订单?多数 C 端产品以用户 ID 为随机单元,保证同一用户始终看到同一版本;搜索广告常以“关键词”为随机单元,避免同一关键词被重复拍卖。就是随机单元(Randomization Unit)。它回答“谁被随机”:用户、设备、会话、还

  2. 7 日留存?指标必须分“决策指标”与“护栏指标”两类,前者决定“上不上新功能”,后者保证“不踩红线”。例如,视频 App 可以把“人均播放时长”设为决策指标,把“ crash 率”设为护栏指标,一旦 crash 率提升 50% 立即停实验。就是指标(Metric)。它回答“看什么数”:点击率、转化率、人均营收、还

  3. 假设(Hypothesis)。它回答“怎么算赢”。通常写成:
    H0:μA − μB ≥ 0(新版不比旧版差)
    H1:μA − μB < 0(新版显著优于旧版)
    注意,H0 必须涵盖“等号”,否则无法计算 P 值。

  4. 检验(Test)。它回答“差异是否超出随机波动”。互联网场景多用“两样本 Z 检验”或“两样本 t 检验”,前者要求样本量足够大(中心极限定理成立),后者对小样本更友好。

为便于查阅,我把四要素浓缩成一张速查表:

要素关键问题常见选择踩坑提示
随机单元谁被随机?用户 ID、设备号、会话 ID用 Cookie 随机会导致“用户换浏览器就 crossover”
指标看什么数?点击率、转化率、营收决策指标只能选一个,多个指标需做多重校验校正
假设怎么算赢?单侧检验:μA − μB < 0把“提升 5% ”写进 H1 属于典型错误,假设只能写“≠”“<”“>”
检验差异显著吗?Z 检验、t 检验、Mann-Whitney样本量>10 万时,t 检验与 Z 检验结果几乎一致

三、样本量计算:为什么“跑一周”不一定够

很多团队把“跑一周”当口头禅,却忽略样本量公式背后的统计原理。样本量由四元组决定:

  • 基准值(p):旧版转化率

  • 最小可检测效应(MDE):想发现多小的差异

  • 显著性水平(α):通常取 5%

  • 统计功效(1−β):通常取 80%

对转化率这类服从二项分布的指标,样本量计算公式为:
n = 2 × [Z_(1−α) + Z_(1−β)]² × p(1−p) / MDE²

举例:旧版转化率 p=10%,希望检测到 MDE=2%(相对提升 20%),α=5%,功效 80%,则每组需要 15 400 个用户。若日均活跃用户仅 1 万,就需要至少 3 天才能攒够样本。此时“跑一周”只是经验值,真正科学的做法是“先算后跑”,并在实验平台配置“样本量门槛”:未达标自动延长,达标后自动计算 P 值。


四、分流机制:哈希、时间片与多层正交

样本量够了,还得保证分流均匀。主流方案有三类:

  1. 哈希分流:把用户 ID 哈希成 0−999 的整数,0−499 进对照组,500−999 进实验组。优点是实现轻松,可复现;缺点是无法动态调比例。

  2. 时间片分流:把一天切成 96 个 15 分钟片,奇数片走旧版,偶数片走新版。优点是能 100% 释放流量,适合 B 端 SaaS 这类无法按用户分流的场景;缺点是易受时间趋势干扰,比如晚高峰用户更挑剔。

  3. 多层正交分流:利用正交表让同一名用户同时处于 10 个实验,彼此不冲突。Google 的“Overlapping Experiment Infrastructure”首次提出此思路,国内字节、美团均已落地。核心是把“用户 ID + 层编号”再次哈希,确保层与层之间独立。

为直观比较,我把三种分流机制放进同一表格:

机制是否支持动态调比是否易受时间趋势干扰实现复杂度适用场景
哈希分流C 端产品常规实验
时间片分流B 端、无法按用户分流
多层正交多实验并行,流量稀缺

五、P 值陷阱:0.05 不是魔法门限

P 值小于 0.05 就上线,大于 0.05 就下线——这种二元判断最容易踩坑。P 值只告诉“内容与原假设的兼容程度”,并不告诉“新能力提升多少”。因此,我习惯把“点估计 + 区间估计”与 P 值同时输出:

  • 点估计:新版转化率 12%,相对提升 20%

  • 95% 置信区间:[+5%, +35%]

  • P 值:0.008

只有当置信区间下限高于业务关心的“最小可接受提升”(例如 3%)时,才建议全量发布。否则可能出现“统计显著但业务微不足道”的尴尬:新版就算显著提升了 0.2%,却要多花 200 台机器,ROI 为负。


六、多重检验与序贯检验:跑得多、看得早也会错

当团队同时跑 20 个实验,假阳性概率从 5% 飙升到 64%,此时必须用 Bonferroni 或 FDR 做校正。Bonferroni 方便粗暴:把 α 除以实验次数,缺点是过度保守。FDR(Benjamini-Hochberg 法)允许少量假阳性,更适合高频实验场景。

序贯检验(Sequential Test):在实验开始前就设定最多偷看 K 次,并用 α spending 函数分配每次的显著性阈值。就是另一个陷阱是“每天看一眼 P 值,显著就停”。此种做法叫“偷看数据”(peeking),会把假阳性再抬高 3 倍。正确姿势


七、常见深坑清单:辛普森、选择偏倚、网络效应

  1. 辛普森悖论:分组看实验组都更好,合并后却更差。根源是分流变量与混杂变量相关。解决办法:在实验设计阶段就把“用户活跃度”等关键因素作为分层变量,并在分析阶段使用分层检验或加权检验。

  2. 否被触达”作为协变量进行回归调整。就是选择偏倚:实验组用户更容易被运营触达,导致转化率虚高。解决办法:实验前关闭所有 Push、短信,或把“

  3. 网络效应:社交产品里,A 用户被分到新版,B 用户被分到旧版,两人互动导致结果互相污染。解决办法:按“集群”随机,例如微信实验按“群”随机,抖音按“同城”随机,并在分析时使用集群标准误(Cluster Robust Standard Error)。


八、工具与代码:用 Python 完成一次最小可行实验

为了让读者“开箱即跑”,我给出基于 Python 的完整脚本,依赖只有 pandas、scipy、statsmodels。内容用随机种子生成,保证可复现。

import pandas as pd
from scipy import stats
import statsmodels.stats.api as sms
# 1. 生成虚拟数据
n = 21000
df = pd.DataFrame({'user_id': range(n*2),'group': ['A']*n + ['B']*n,'converted': stats.bernoulli.rvs(0.081, size=n*2)
})
# 让 B 组提升 1.1 个百分点
df.loc[df.group=='B', 'converted'] = stats.bernoulli.rvs(0.092, size=n)
# 2. 计算转化率与标准误
rate = df.groupby('group')['converted'].agg(['mean', 'count', 'std'])
se = np.sqrt((rate['std']**2 / rate['count']).sum())
# 3. Z 检验
diff = rate.loc['B', 'mean'] - rate.loc['A', 'mean']
z = diff / se
p_value = stats.norm.sf(z)  # 单侧
# 4. 置信区间
ci = sms.CompareMeans(sms.DescrStatsW(df[df.group=='B'].converted),sms.DescrStatsW(df[df.group=='A'].converted))
lower, upper = ci.tconfint_diff(usevar='unequal')
print(f'转化率差异: {diff:.3%}, P 值: {p_value:.3f}, 95% CI: [{lower:.3%}, {upper:.3%}]')

运行结果示例:
转化率差异: +1.06%, P 值: 0.002, 95% CI: [+0.42%, +1.70%]


十、结语:把实验文化种进 DNA

AB 测试不是花哨的“灰度开关”,而是一种“用随机化对抗主观”的科学习惯。它把“我觉得”变成“数据证明”,把“老板拍脑袋”变成“置信区间”。当你下次再听到“红色按钮好还是绿色按钮好”时,不妨微笑着反问:“样本量够吗?P 值校正了吗?置信区间下限过 3% 了吗?” 如果对方能接住这三个问题,说明你们已经把实验文化种进了团队 DNA。祝实验顺利,愿所有上线都经得起显著性检验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/941147.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实用指南:IEC 60364-7-722-2018低压电气装置中电动车供电安全要求标准介绍

实用指南:IEC 60364-7-722-2018低压电气装置中电动车供电安全要求标准介绍pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-famil…

记录下,cadence17.4 PCB封装更新方法

在PCB板上 然后在元件选择栏内看到元件置于待放入元件nets列表中 在随后出现的设置对话框中,选择update 焊盘from lib,fixed 属性,然后update,再选元件进入PCB,封装已经更新了。

c#设计模式—访问者模式 - 教程

c#设计模式—访问者模式 - 教程2025-10-20 13:20 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !importa…

springboot使用aop切面,记录日志

技术说明: springboot:2.1.4.RELEASE jQuery Ajax mysql:8.0.32 业务背景: 当我们在操作网页的时候,我们后台需要记录每个用户,什么时候操作了哪些记录。比如注册了,还是登录了,还是查询了,我们把这些记录全部…

【整活】OI的那些奇妙小操作(Part 1)

卡时 在C++里,有(double)clock()/CLOCKS_PER_SEC这一行代码可以获得当前已经运行的时间。 初见端倪,也就是说,当你使用一些暴力算法(暴搜)的时候,你可以通过计算当前已经运行的时间并判断是否将要超时,如果要超…

想学习的数学

空闲时间想多学习一些基础数学课,虽然以前也学过,但是没有写一些笔记 比如: 泛函分析 范畴论 测度论 暑期班的优化笔记也可以整理一下,还一些可逆遇见的矩阵的性质,以为比较散乱,所以遇到了再整理。本文来自博客园…

详细介绍:Streamlit:CSS——从基础到实战美化应用

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

SqlServer 事务复制的两个参数immediate_sync,allow_anonymous

SqlServer 事务复制的两个参数immediate_sync,allow_anonymousSqlServer的事务复制中,immediate_sync和allow_anonymous两个参数会影响到复制的后台行为和分发库(distribution)的数据保留方式,这两个参数单从名字…

OO之接口-DAO模式代码阅读及应用

1. StudenDaoListImpl.java 与 StudentDaoArrayImpl.java 有何不同?StudenDaoListImpl 使用 ArrayList 存储学生对象,可以动态扩容,无需指定初始大小。StudentDaoArrayImpl 使用固定长度的 Student[] 数组存储学生对…

个微协议,微信号二次开发/ipad协议

优势 我们是一家专业服务企业数字化微信管理服务的技术团队,服务于需求SCRM、机器人、营销系统、社群小助手等具有研发能力的企业,同时我们也接收因使用Xp方案、ipad方案、PC方案导致被批量封号的企业,我们合作伙伴目…

Win11设置默认打开全部右键菜单

前言Win11 的右键菜单默认是折叠起来,很多功能需要点击“显示更多选项”才能显示,非常不方便。 方法打开 CMD 运行下面命令,然后重启电脑即可。reg add HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c…

屏幕显示发白难题的硬件工程深度排查:架构兼容性边界分析

屏幕显示发白难题的硬件工程深度排查:架构兼容性边界分析pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consola…

发现概率

5.1.3 发现概率模型的求解 发现概率的核心特征是累积性与不可逆性: 单雷达需连续3个扫描周期(窗口大小 $w = 3$)探测成功才判定"发现",且一旦某时刻满足"发现"条件,后续所有时刻的发现状态需…

MySQL索引查看语句show index详解

一、概述 SHOW INDEX语句是MySQL中用于查看表索引信息的语句。它提供了有关表中索引的详细信息,包括索引名称、索引类型、关联的列等。 二、语法与概要描述 SHOW INDEX语句的语法如下: SHOW INDEX FROM table_name […

qzmoot 生活合集

qzmoot 生活合集欣赏穿蛋侠; 摸彭云; 跳缩小版《我是奶龙》。

yocto工程升级要点

需求 原有的工程是多年前基于yocto sumo开发,对应的linux kernel版本是4.14。 需求是要求linux kernel升级到5.10。 背景 工程由以下几部分组成,yocto sumo构建部分的代码,包括poky,bitbake等 目标平台支持多款第三…

微信机器人开发API!3步搞定微信聊天机器人

微信机器人开发API!3步搞定微信聊天机器人 WTAPI框架是一个能将个人微信各项功能提取成可供开发人员调用的一套私有API接口,比如微信的收发消息,发朋友圈,群聊,建群等等都是可以用API接口来做的。你可以用 微信机…

详细介绍:【Linux】Linux管道与进程池深度解析:从原理到实战

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

windows2019的域控服务器更新时间.251020

1 先找到合适的源 w32tm /stripchart /computer:ntp.aliyun.com #若是可以使用会显示如下图2 注册表配置确****保NTP客户端已启用:确认以下注册表路径的 E nabled 值为 1: HKEY_LOCAL_MACHINE\SYSTEM\CurrentCo…

国内DOH解析速度测试(阿里 腾讯 360 Doh测速)

阿里 腾讯 360 Doh测速以前一直用阿里DOH,上个月开始明显感觉网页打开速度异常慢,怀疑是阿里DOH限速,验证过程如下: 测试工具:Python3.14 aiohttp matplotlib numpy dnspython 库 地理位置:阳江(距离省会偏远的落后城市…