本文是对《关键迭代:可信赖的线上对照实验》的摘抄和总结。或者说一位 Airbnb 的读者,对一本作者与译者均来自 Airbnb 的技术书做的小结 😁。如有错误恳请指出,欢迎各种评论。
如果你只有一个锤子,那你看什么都像钉子。——亚伯拉罕·马斯洛
- 准备测试
- 想成功就多失败
- 测试是战术,决策是战略
- 什么是显著结果
- 搭建测试
- 变体分配
- 指标分类
- 指标选择
- 代理指标
- 指标归一化
- 对偶性
- 预防子指标冲突
- 陷阱
- 警惕极端结果
- 辛普森悖论
- 用户群改变
- 不确定的混淆因素
- Others
- 长期实验
- 伦理
- 一个例子:设计一个减速实验
- 替代方案
- 数学推导
- 方差相关问题
- 增量%,以及比率指标的方差计算
- 离群值
- 提高灵敏度
- p-value 的取值问题
- 样本量n要多大
- TBD 为什么选择t 分布?
准备测试
想成功就多失败
实验的带来的认知改变也和预期于现实的差距有关。
如果你认为一件事情会发生,然后它真的发生了,那么你不会学到什么。如果你认为一件事情会发生,但没有发生,那么你会学到一些重要的东西。如果你原本认为一件事情不值一提,但它带来了惊人的或突破性的结果,那么你会学到一些非常有价值的东西。
团队认为一个产品功能有用才会去开发它,然而,很多领域的大部分想法都无法提升关键指标。在微软,被测试过的想法仅有三分之一能改善目标指标。在已经高度优化的产品领域,如必应和谷歌,想要成功就更难了,测试的成功率仅在10%~20%之间。 必应几百人的关联算法团队每年的任务就是将单个OEC指标提高2%。
测试是战术,决策是战略
测试大胆的想法时,运行和评估实验的方式也有所变化。
- 实验的运行时长,房间里温度的小幅提升不会引起变化,而一旦达到熔点,冰块就会开始融化。
- 被测试的创意数量。每个实验只测试一个具体的战术,该战术是总体战略的一个组成部分。个别实验的失败不代表总体战略有问题。但如果经对照实验评估后的很多战术都以失败告终,那大概率就是战略的问题。用实验来验证战略是极其消耗成本的,制定战略所需的数据应该从已收集的可用数据中得出。
OKR 的一种解释就是确定战略 O,其后的 KR 衍生出一系列战术来满足 KR 并回馈到 O。
什么是显著结果
不是所有用户显著的结果都有实际意义。以人均营收为例,多大的差异从业务角度来说是紧要的?换句话说,什么演的变化是实际显著的(practically significant)?构建这一实质性的边界很重要,它可以帮助理解一个差异是否值得话费相应改动所需的成本。如果你的网站像谷歌和必应那样有数十亿美金的营收,那么 0.2% 的变化是实际显著的。作为对比,一个初创公司可能认为 2% 的增长都太小了,因为他们追求的是 10% 或更大的增长。
2012年 bing 每 10 毫秒的性能提升(眨眼速度的 1/30)足以支付雇佣一个全职工程师一年的成本。到了 2015 年这个数字变成了 4 毫秒。
搭建测试
变体分配
如何把实验分配给用户
- 单层方法。把用户分桶,比如1000 个桶,每次拿两个用户桶做实验。
- 并行实验。
- 把代码架构分层,每层只有一个实验。
- 不关心实验互相影响,默认实验都是正交的,如果有不正交的实验,依赖执行团队发现并解决矛盾。
指标分类
- 目标指标,也被称为成功指标或北极星指标,它体现了机构终极关心的是什么。能用语言把你的目标清楚表达出来是重要的,因为从目标到指标的转化通常都不完美,你的目标指标也许只是你真正关心事物的一个近似,并且需要随着时间推移而迭代改进。让人们能理解这个局限性,以及指标与目标陈述之间的区别,对于把握公司的正确方向是至关重要的。
- 驱动指标,也被称为路标指标、代理指标、间接或预测指标,一般比目标指标更短期,变化更快也更灵敏。驱动指标反映了一个思维上的因果模型,它是关于如何做可以让机构更成功,也就是对成功的驱动力的假设,而非关于成功本身是什么样的。
- 护栏指标,保证我们在通往成功的道路上有正确的权衡取舍,不会违背重要的限制。
指标选择
指标选择在不能违反数理常识的前提下,还取决于设计者的价值选择(“人是目的,不是手段”)。指标代表着你想要系统怎么去理解数据,你的关心是什么。例如关注极端值就要用P95 P99,关注整体情况就用平均值和中位数。
代理指标
一些订阅服务以年为单位续订。除非你愿意运行一个长达一年的实验,否则很难测量对续订量的影响。对于这种情况,我们不能用续订率作为实验指标,而是需要寻找代理指标,比如服务的使用量,这类指标往往可以提早显示用户对服务的满意度,并最终影响续订率。
指标归一化
即便想要提高的是营收总和,也不建议将营收总和作为指标,因为它依赖于变体对应的用户数量。即便各变体被等量分配,实际用户数也可能因为偶然性而有所不同。我们推荐按实际样本量归一化的关键指标,因此人均营收才是一个好的综合评估标准。
对偶性
有时候精确测量你不想要的事物反而比测量你想要的更简单,如用户的不满意度和不幸福度。 从观测数据中建立因果关系是很难的,但一个仔细进行的观测研究有助于否定错误的假设。
预防子指标冲突
要仔细检查大指标下面的各个子指标,很有可能子指标之间是互相冲突的,例如搜索引擎的人均搜索量 = 人均会话数 * 会话平均的去重查询个数。
一个会话的开始被定义为用户开始第一次查询,结束则是用户30分钟内在搜索引擎上没有活动。
- 人均会话数大概率是一个正向的指标,用户对搜索引擎越喜欢,其使用频次就会上升,那么人均会话数也会上升。
- 会话的平均去重查询却应该减少,这个与总目标相违背。因为单次会话的平均去重查询减少代表用户解决问题的步骤变少了,但是也有可能代表用户放弃了查询。我们最好伴随这个指标在建立一个查询中途放弃的指标。
陷阱
警惕极端结果
当看到令人惊讶的正面结果(例如对关键指标的重大改进)时,我们倾向于围绕它构思一个故事,分享并庆祝。当结果出人意料地是负面的时候,我们倾向于找出这项研究的某些局限性或较小的缺陷,并将其忽略掉。 经验告诉我们,许多极端结果更有可能是由工具化记录(例如,日志记录)的错误、数据丢失(或数据重复)或计算错误导致的。
辛普森悖论
在某个条件下的两组数据,分别讨论时都会满足某种性质,可是一旦合并考虑,却可能导致相反的结论。
当实验feature 导致了两个互为穷尽且互斥的细分群中的个体发生迁移,也会导致类似的情况(虽然书中强调这不是辛普森悖论)。
例如某个feature 让等级2 的用户回到了等级1,可能两个等级的数据都变好了,因为等级2 的用户群剔除了表现差的用户,而等级1 的用户群增加了表现好的用户,但可能两个等级的总用户表现不会有变化甚至会变差。
在理想情况下,只应该通过在实验之前就确定的值来进行细分,这样实验不会导致用户对应细分群的更改,但实际上在某些案例下我们很难限制这种细分。
用户群改变
当计算指标或运行实验时,所有的数据都来自现有的用户群。尤其是对早期产品和初创企业来说,早期用户可能无法代表业务长期发展所希望获取的用户群。
不确定的混淆因素
共享这些因素可能会导致实验失败:
- 市场资源。民宿、网约车有这样的问题,一旦进入supply constraint,一个组抢占过多的资源会让另一个组失去原有的资源。
- 广告活动的预算。
- 关联模型训练。一旦两个模型都是用全量用户的数据计算的,那么几天后很可能两个模型的知识会发生共享。
- CPU或其他计算资源。
Others
Goodhart 法则:当一个测量变成目标时,它就不再是一个好的测量。
Lucas 批判观察到在历史观测数据中的关系是无法被考虑为结构性的或者因果关系的。政策上的决定会改变经济模型的结构,这样以来历史上的关联性就不再成立了。随着时间的变化,可能我们之前倚赖的因果关系都会变化。
长期实验
短期实验和长期实验结果可能不同的原因:
- 用户的习得效应。
- 网络效应。
- 延迟的体验和评估。
- 生态系统的变化
- 启动其他新功能。
- 季节性。
- 竞争格局。
- 政府政策。
- 概念漂移。
- 软件性能下降。
长期运行实验的改善方法:
- 群组分析。长期跟踪一个稳定群组的用户数据。
- 后期分析。运行一段时间后关闭实验/或者把实验开放给所有用户,然后继续测量对照组和实验组的差异。
- 时间交错时实验。把实验开始时间t 作为变量创建多个实验组,比较不同t 之间用户的差异表现。
- 留出和反转实验。
- 留出:留下10%的用户在对照组;
- 反转:几个月后吧10%的用户重新放到对照组。去测量用户的表现。
伦理
- 尊重人:尊重实验参与者是有自主行为能力的个体,并在他们丧失这种能力时保护他们。这一原则的重点是透明、真实和自愿(选择和同意)。
- 有益性:保护人们免受伤害。正确评估风险和收益,并在审查拟议研究时适当平衡风险和收益。
- 正义性:确保不剥削参与者,并公平分配风险和收益。
一个例子:设计一个减速实验
为什么减速实验可以测出加速对产品的影响?
假设相关指标(如营收)对性能(如速度)的变化图线,在当前值附近可以很好的被线性拟合。这就是一阶泰勒展开的近似,或者说是线性近似。
即如果我们改进性能,得到的指标变化是可以用降低性能得到的指标变化来近似的。
还有两个原因可以支持这个假设
- 从我们自己作为用户的经验来看,网站速度是越快越好的。即大家都喜欢性能好的产品。
- 我们还可以去验证线性假设,比如测试一下延迟100ms 和延迟250ms 的指标,看一看在这两个情况下得到的指标是否符合线性关系。
替代方案
如何去测量虚拟事实呢?考虑要计算一个测试对象为人群的实验,想要知道此实验的虚拟事实和现实的偏差,我们有:
受影响人群的结果 - 未受影响人群的结果
=(受影响人群的结果 - 受影响人群如果未受影响的结果) +
(受影响人群如果未受影响的结果 - 未受影响人群的结果)
= 变动对于受影响人群的作用 + 选择性偏差
我们能观测到的是是否收到影响人群的表现,但我们想知道的是变动对于受影响人群的作用,所以我们期望系统中的选择性偏差为0。
A/B 测试就是选择性偏差为0 的系统,但是很多实际情况我们无法把A/B 测试施加到一个现实问题中,比如没有随机化单元,比如实验会带来巨大的(机会)成本浪费,比如实验会有违伦理道德。
一般有这些方法来替代A/B 测试,但这一类方案总是会比A/B 测试带来更大的误差和夸张的结果:
- 中断时间序列,把实验时间分割成许多小段,每段时间均匀(且随机、或者就是轮询)地分配给各个事实,然后对此进行测量和分析(一些时序模型可以派上用场,比如贝叶斯结构时间序列分析)。
- 交错式实验,经常用于排名算法,奇数位置展示算法A,偶数位置展示算法B,以此来比较差异。
- 断点回归设计,当受实验影响的人群是由一个明确阈值识别的情况下时考虑该方法,把刚好低于阈值的人群作为对照组,将刚好高于阈值的人群作为实验组,通过比较这两组人群来减少选择性偏差。比如研究奖学金对学生的影响,80分以上的考生可以有奖学金,那我们就研究84-80 和79-75 这两个考生群体。
- 工具变量和自然实验,如果能在被研究流程中找到可以帮助我们实现随机分组的工具,那么利用这个工具来分析实验,比如采取抽签制的征兵和入学分配,若可以判定抽签过程是随机的,那么就可以用抽签作为随机化单元。
- 倾向评分匹配,虽然我们无法随机化,但是如果我们可以分清楚不同组别之间可能会影响我们对变量判断的混淆因素(协变量),又或者可以确定无法辨别的混淆因素不会影响分析,那我们就可以去分析变量和结果之间的因果关系,通常很难做到。
- 双重差分法,识别出与实验组尽可能相似的对照组,假设两组在趋势上是相同的。比如选择两个各类特征都相近的两个城市作为对照城市,一个开启新feature,一个不是,然后比较两个城市之间的差异。
这一类分析需要小心使用,可能会因为如下原因失效:
- 共同原因,手掌越小寿命越长,其实是女性的寿命越长。
- 伪相关性或欺骗性的相关性,全美拼写比赛的单词长度和当年被毒蜘蛛咬死的人数正相关,但这显然是伪相关性。
数学推导
我们用双样本t检验来计算p-value,这符合实际的实验设置。
其中 是实验组均值和对照组均值之差, 和 因为中心极限定理符合正态分布。
考虑独立变量的方差公式 :
其中
p-value 在事实上就是一个条件概率,这个条件概率是:“当零假设为真时,观测到当前差异甚至更大差异的条件概率”,即 。这里的 其实是经过归一化后的 ,这个条件概率是可以无视具体实验提前计算出来的,所以我们认为p-value具有普适性。
有人会误以为p-value 代表“当观测到当前差异甚至更大差异时,零假设为真的概率是多少”,其实这里面隐含的条件“观测到当前差异甚至更大差异”的概率是针对每个实验不同的, 没有普适性。可以用贝叶斯定理推导两者的关系:
\begin{align*} P(H_0 为真|观测到\mathit{\Delta}) &= \frac {P(观测到\mathit{\Delta}|H_0 为真)P(H_0 为真)} {P(观测到\mathit{\Delta})} \\ &= \frac {P(H_0 为真)}{P(观测到\mathit{\Delta})} * P(观测到\mathit{\Delta}|H_0 为真) \\ &= \frac {P(H_0 为真)}{P(观测到\mathit{\Delta})} * p值 \end{align*}
方差相关问题
p-value 的计算依赖方差,方差估计常见问题:
增量%,以及比率指标的方差计算
此时注意,如果指标的含义和分析单元是不同的,很可能会导致一些取值不是独立同分布的。比如算页面转化率,而实验单位是用户,那么用户多次访问页面,让页面数据变成非独立同分布的数据。这时候方差需要从比率计算公式的分子分母各自对应的方差计算得来,不能根据比率公式算出比率再算方差。
下面是正确的计算方法 我们把比率指标写成两个用户指标平均指标的比率
通过delta 方法,跳过推导,最后的方差公式是:
离群值
离群值会干扰试验,可以对观测指标添加一个合理的阈值,其他方法自己搜索。
提高灵敏度
方差越小显著性越高,这些方法可以减小方差:
- 通过添加阈值、二元化和对数转化来改变指标。购买量比是否购买有更大的方差,人均观看时长比观看超过x小时有更大的方差。
- 通过触发分析移除噪音。
- 通过分层采样,控制变量法或者CUPED在采样范围内进行分层。最后把每层的结果合并得到总值,这样计算出的方差更小。
- 选择颗粒度更精细的随机化单元。
- 共享对照组。合理计算出一个对照组的大小,和多个实验组做比较,这样的方差更小,可以提高所有实验组的功效,但也会带来一些问题。
p-value 的取值问题
警惕这样一个事实:当p-value 为0.05时,测试一个不显著的feature(比如没有任何改动的feature,此时零假设为真)100次,那么在统计上有5次测试我们会错误地认为这个feature 是显著的(测量到了极端值)。这里我们引入两个概念:
- 第一型错误,测量结果是显著差异的,但是真实情况是没有差异的。
- 第二型错误,测量结果是非显著差异的,但是真实情况是有差异的。
不难发现,p-value 越小,第一型错误越少,但第二型错误会增多;反之第一型错误变大,第二型错误变小。
为了防止前述“在统计上有5次测试我们会错误地认为这个feature 是显著的”,这样的第一型错误产生,我们可以对一些确认与实验无关(或间接相关)的指标施加更小的p-value,防止第一型错误发生。信心越坚定,所需的显著性水平越低。
同时,对比较敏感,我们不希望没有发现差异的guardrail metrics,应该放大p-value。特别是一些指标我们明确其不变化幅度不能超过x%,那我们应该遵循工业界,检验应有80%统计功效的原则(统计功效 = 1 - 第二型错误,一些具体的近似公式请自行查询),根据x 的数值去计算更具体的p-value。
样本量n要多大
这一段和提高灵敏度那一段重复了一些内容。
样本量n越大越好的理论基础是什么呢?这是因为t分布的前提假设之一就是其测算分布是正态分布,而根据中心极限定理,在适当的条件下,大量相互独立随机变量的均值经适当标准化后依分布收敛于标准正态分布。所以我们需要n足够大。
前面叙述的统计功效近似公式可以在给定条件下帮我们测算n的大小,但这个公式需要我们去指定变化幅度x%,只适用在一些guardrail metrics上。
那为了让均值服从正态分布,我们还有基于偏态系数的经验公式来计算n,一些差异较大的指标偏态系数也会很大,我们可以通过限制差异(比如超过10的数值都为10)来降低偏态系数和n,只要限制差异的条件不违反我们的假设就可以。
当然还可以通过构建零分布来验证,但是涉及的概念就更复杂了,此处略过。
TBD 为什么选择t 分布?
需要比较几个抽样分布的特点,可以参考一下大学教材中的总结。