【科普贴】运用贝叶斯推断进行A/B测试

探究Ptengine中的Experience A/B 测试框架原理

内容提要:

1、什么是贝叶斯推断?

2、Ptengine 的A/B测试为何选择贝叶斯推断?

3、胜率如何计算?如何确定胜者?

前言:

每一棵参天大树都会经历诸如从种子萌芽、逐渐生长发育、历经四季轮回、繁盛与衰退,不断扩大其根系和枝叶的过程。产品或品牌的成长亦是如此,在内容创新上持续推陈出新,稳固老客户关系的同时吸引新的用户。因此我们可以将内容看作是产品的活力所在。

在数据驱动的运营策略中,A/B测试为内容创作、发布、效果反馈以及最终决策(正式上线)这一流程提供了科学且客观的支撑。在Ptengine的Experience功能中,我们提供了一套非常便利的A/B测试框架,并结合无代码页面编辑功能,以加速您的内容创新业务闭环。

【科普贴】运用贝叶斯推断进行A/B测试

本文并不会详述应用层面的内容,而是专注于阐述Ptengine中A/B测试框架的基础原理。在解释计算原理时,我们会以简单易懂的例子辅助说明,使您在不深入理解数学性质的前提下,也能把握其主要逻辑。

文章最后也会利用Python语言搭建出一个简易的A/B测试程序,以满足对编程有好奇心的读者。

什么是贝叶斯推断?

贝叶斯推断(Bayesian inference)是一种用于统计推断的方法。根据贝叶斯定理,当获取到更多的证据和信息时,我们可以更新特定假设的概率。

看到这里或许会让你想起大学课堂,教授声音深沉浑厚,念着课本上的定义,生僻的用词,专业的术语,深奥的原理开始充斥你的大脑,你的眼神开始迷离,思绪开始游荡,直到下课铃声拯救你于太虚。

让我们通过一个例子来解释贝叶斯推断的基本逻辑:

假设情境:在第一节大学课堂上,Clyde对同学Bonnie一见倾心。他希望能追求到Bonnie,但却不知道该如何行动,何时表白最合适。作为他的朋友,我们能否通过数学的方式,计算出他表白的成功率,并给出一些建议呢?

首先,我们需要设定一个目标,比如当表白成功率“达到”95%时,Clyde就可以向Bonnie表白,因为95%的成功率看起来几乎是稳操胜券。那么,问题就变成了如何计算这个成功率。

注意,我们说的是成功率“达到”95%,这是因为在贝叶斯推断的过程中,我们要推断的目标概率是会随着新证据的出现不断更新的。因此,我们需要给出一个初始的假设概率,即先验概率(Prior probability),然后根据得到的证据调整这个概率,得到后验概率(Posterior probability)。之后,将得到的后验概率作为新的先验概率,循环进行这个过程。这就是贝叶斯公式的基本逻辑:

【科普贴】运用贝叶斯推断进行A/B测试

其中,P(H) 代表我们根据经验设定的先验概率,P(E|H)/P(E)是调整因子,

P(H∣E)是后验概率。只有当调整因子大于1时,后验概率才会大于先验概率。

回到我们的例子,我们可以假设先验概率为0.5,表示Clyde成功和失败的概率各占一半。然后,我们开始收集证据。

我们注意到Bonnie是个高冷的女神,但她似乎经常对Clyde微笑。根据这个证据,我们计算出调整因子为1.2(考虑到篇幅,请忽略调整因子的计算过程)。根据贝叶斯公式,我们更新成功率为0.6。Clyde也因此更有信心了。在Bonnie的生日时,Clyde送给她一个漂亮的发饰,Bonnie非常喜欢并每天都带着它来上课。这个新的证据为我们提供了调整因子1.6,于是我们计算出:

【科普贴】运用贝叶斯推断进行A/B测试

现在,表白的成功率已经达到了96%,作为朋友和“军师”,我们可以告诉Clyde大胆去表白。结果,他们两人都收获了甜蜜的爱情。

通过以上例子,相信你已经理解了贝叶斯推断的基本逻辑:设定前提假设,然后根据收集到的证据调整先验概率,如此循环往复,最终推断出目标概率。这也是贝叶斯A/B测试的主要逻辑。

为什么选择贝叶斯推断?

在A/B测试刚被提出的时代,它利用的是基于条件假设检验的频率派统计方法。然而,贝叶斯方法的兴起为我们提供了新的机会。

首先,贝叶斯推断的计算逻辑更加简洁直观,并且相较于频率派方法,在小样本量上表现更好。

更为重要的是,贝叶斯A/B测试框架引入了更具解释性的概念,如胜率。这一概念定量化了不同版本间的对比,并以更直观、更易于理解的方式解释了哪个版本更优秀。

【科普贴】运用贝叶斯推断进行A/B测试

以上为Ptengine 中直观的A/B 测试报告

因此,Ptengine选择贝叶斯推断作为A/B测试框架的底层原理,并结合Experience的无代码页面编辑功能。遵循我们的设计理念,我们提供了简洁、直观的产品操作逻辑和用户界面。在数据驱动的运营策略中,A/B测试为内容创作、发布、效果反馈以及最终决策(正式上线)等环节提供了科学且客观的依据。

胜率

胜率是贝叶斯A/B测试框架的一个独特概念,它以量化的方式呈现了“哪个版本更优”的结论,使用户能更直观地了解每个版本“有多好”。许多用户对Ptengine中胜率的计算逻辑很感兴趣。其实,其计算逻辑并不复杂,接下来我们将通过解释两个统计学概念来阐述胜率的计算逻辑:

1. Beta 分布

Beta分布是一种定义在[0,1]区间内的连续概率分布,通常用于对事件成功率进行建模。在Ptengine中,我们使用它来模拟版本的目标完成率。在可视化展示中,它就是你在产品中看到的曲线。

【科普贴】运用贝叶斯推断进行A/B测试

从上图可以看出,我们对目标完成率的估计并不是简单的估计成一个数值,而是通过概率分布进行建模并采取置信区间估计法。借助Beta分布,我们可以轻松更新目标完成率的分布状态,也即前文提到的利用先验分布更新后验分布。接下来,我们将结合产品案例(测试样例)和代码进行说明:

下图展示了一个产品中的A/B测试报告界面。我们看到该Experience在11月20日有少量流量访问,并且控制组产生了转化。在Ptengine的计算引擎中,这时会发生什么呢?

【科普贴】运用贝叶斯推断进行A/B测试

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import beta

# 预先设定的先验分布, alpha代表转化数,beta代表未转化数, 都为1时为均匀分布
alpha_prior = 1
beta_prior = 1

# 观测到11月20日的数据,计算后验分布, alpha增加转化的数量, beta增加未转化的数量
ctrl_alpha_post = alpha_prior + 4
ctrl_beta_post = beta_prior + 129 - 4

var1_alpha_post = alpha_prior + 0
var1_beta_post = beta_prior + 113

var2_alpha_post = alpha_prior + 0
var2_beta_post = beta_prior + 106

# 生成后验分布曲线
x = np.linspace(0, 1, 1000)
y_ctrl = beta.pdf(x, ctrl_alpha_post, ctrl_beta_post)
y_var1 = beta.pdf(x, var1_alpha_post, var1_beta_post)
y_var2 = beta.pdf(x, var2_alpha_post, var2_beta_post)

# 绘图
plt.figure(figsize=(8, 6))
plt.plot(x, y_ctrl, label='Control')
plt.plot(x, y_var1, label='Variant 1')
plt.plot(x, y_var2, label='Variant 2')
plt.title('后验分布')
plt.xlabel('概率')
plt.ylabel('密度')
plt.legend()plt.show()

运行以上代码你将会看到:

【科普贴】运用贝叶斯推断进行A/B测试

通过以上过程,我们完成了一次贝叶斯推断的迭代模拟。之后,将这次得到的后验alpha和beta作为下次迭代的先验,就可以持续更新各个版本的Beta分布了。

【科普贴】运用贝叶斯推断进行A/B测试

Beta 分布迭代示例

2. 蒙特卡罗模拟

蒙特卡罗方法(Monte Carlo method),也称统计模拟方法,是由冯·诺伊曼等人于1940年代提出的一种基于概率统计理论的数值计算方法。它使用随机数来解决许多计算问题。

蒙特卡罗方法是一种非确定性算法,其特点是随着模拟次数的增加,得到的数值结果会趋向于收敛,即逼近真实值。利用蒙特卡罗方法,我们可以计算很多难以进行确定性计算的数值,例如复杂函数的积分等。

接下来,我们通过一个经典例子来解释蒙特卡罗方法的应用 —— 利用蒙特卡罗方法模拟计算圆周率π。

import random

def estimate_pi(iterations):
    points_inside_circle = 0
    points_inside_square = 0

    for _ in range(iterations):
        x = random.uniform(0, 1)
        y = random.uniform(0, 1)

        distance = x ** 2 + y ** 2
        
        if distance <= 1:
            points_inside_circle += 1
        
        points_inside_square += 1

    # 由于正方形边长为圆的半径,所以四分之一圆的面积与正方形面积比为pi/4
    pi_estimate = 4 * points_inside_circle / points_inside_square
    return pi_estimate

从代码中我们可以推断,随着迭代参数iterations的增加,四分之一圆内的点数与正方形内点数的比值将逐渐趋近π/4. 通过增加迭代参数,我们可以得到满足精度要求的π估值。

【科普贴】运用贝叶斯推断进行A/B测试

利用蒙特卡洛方法计算圆周率

现在,我们理解了蒙特卡罗方法,可以结合前面介绍的Beta分布来计算胜率和胜者。具体步骤如下:

  • 首先设定模拟次数n。
  • 根据观测数据计算出后验Beta分布。
  • 在每次模拟中,根据每个版本的概率分布进行抽样,转化率最高的版本在此次模拟中获胜。
  • 重复上述模拟,直到模拟次数达到n,然后将每个版本的获胜次数除以n,得到各版本的胜率。
  • 如果某版本的胜率不低于设定的阈值,则宣布该版本获胜。

通过这种方法,我们可以更直观地评估各版本的表现,并确定哪一个版本最有可能带来最高的转化率。

接下来,让我们通过代码来模拟实践一下简易的A/B测试中胜率的计算过程。

from scipy.stats import beta
from numpy import random

# 控制组信息, alpha代表转化数, beta代表未转化数
control_group_alpha = 300
control_group_beta = 100

# 变体信息
variant_alpha = 400
variant_beta = 150

# 模拟次数, 次数越多结果越精确
simulation_number = 10000

# 建立beta分布并进行随机抽样
beta_ctrl = beta(control_group_alpha, control_group_beta)
beta_var = beta(variant_alpha, variant_beta)
ctrl_samples = beta_ctrl.rvs(size=simulation_number)
var_samples = beta_var.rvs(size=simulation_number)

# count各版本获胜次数
ctrl_win, var_win = 0, 0
for ctrl_sample, var_sample in zip(ctrl_samples, var_samples):
    if ctrl_sample > var_sample:
        ctrl_win += 1
    elif ctrl_sample < var_sample:
        var_win += 1
    else:
        # 二者相等时随机选择一个进行加1
        winner = random.choice(['ctrl', 'var'])
        if winner == 'ctrl':
            ctrl_win += 1
        else:
            var_win += 1

# 胜率计算
ctrl_wr, var_wr = (ctrl_win / simulation_number)*100, (var_win / simulation_number)*100
print(f'控制组胜率:{ctrl_wr}%, 新版本胜率:{var_wr}%')

以上代码会生成类似以下的输出结果:

【科普贴】运用贝叶斯推断进行A/B测试

至此,相信您已对Ptengine A/B测试胜率的计算逻辑有了基本的理解。

总结

本文详细介绍了贝叶斯推断的概念,并解释了Ptengine为何选择贝叶斯推断作为其A/B测试底层实现的原因。我们可以看到,加入胜率等概念使得A/B测试具有更高的可解释性,并能够为您在分析新内容的效果时提供更易于理解的客观依据。对于复杂的胜率计算部分,我们通过提供可运行的Python代码帮助您进行理解。

来源公众号:Ptengine(ID:ptmind_bj)从实现到发现,高效提升独立站转化率与业务ROI。

本文由奇赞合作媒体 @Ptengine 发布,未经许可,禁止转载、采集。

该文观点仅代表作者本人,奇赞平台仅提供信息存储空间服务。

(1)

为你推荐

发表回复

登录后才能评论
李坤锦
公众号
视频号
小程序