Kaggle A/B Test 项目:A/B Test on An E-commerce Landing Page(某电商网页的A/B测试)

1. 背景

   某电商公司希望通过改进设计来提高转化率。以往该公司全年转化率平均在13%左右,现在希望新页面的转化率能有2%的提升,达到15%。在推出新页面之前,该公司通过AB测试在小范围的用户中进行测试,以确保新页面的效果能够达到预期目标。

2. 设计A/B test实验

在A/B测试实验设计这一步,通常需要完成以下6个步骤:

  • 1、提出假设
  • 2、确定实验分组
  • 3、计算实验样本量及试验周期
  • 4、上线AB测试并收集数据
  • 5、数据分析及假设检验
  • 6、得出结论及建议

Step1:提出假设

  设计AB test实验的第一步通常是提出假设。假设是对于某个特定变化我们所期望的结果,也是后续实验的基础,我们需要在后续实验中通过数据验证这个假设是否成立。如果验证成立,我们可以将这个变化推广到全部用户。如果验证不成立,则需要继续优化这个假设或者放弃这个修改方案,以寻找更好的变化。

  在这个实验中,我们希望新页面可以提升2%的转化率,原则上我们应选择单尾检验,准确的说,应该选择右侧单尾检验,因为我们的假设是新页面的转化率要大于旧页面的转化率。但是,在本案例中,我们并不能确定新页面的性能一定比当前的页面更好。所以,这里选择双尾检验。

Step2:确定实验分组

  在此次AB测试中,我们分为实验组和对照组两组:

对照组(control组):这一组用户将看到旧版落地页
实验组(treatment组):这一组用户将看到新版落地页

  为了后续计算每一组的转化效率,需要记录每一位参与实验的用户的购买行为,也就是说无论用户看到的是新版落地页还是旧版落地页,都需要记录这位用户最终是否购买了产品。这可以通过在网站上添加相应的追踪代码来实现:

  • 0 0 0:代表用户在测试期间没有购买产品
  • 1 1 1:代表用户在测试期间购买了产品

这样,后续就可以很容易地计算出每个组的均值,从而得到新旧两版落地页的转化率。

==================================================================

Step3:计算实验样本量、试验周期

  • 实验样本量的确定
    每一个实验组所需样本量计算公式如下:
    N = σ 2 δ 2 ( Z 1 − α 2 + Z 1 − β ) 2 N = \frac{\sigma^2}{\delta^2}(Z_{1-\frac{\alpha}{2}}+Z_{1-\beta})^2 N=δ2σ2(Z12α+Z1β)2

在这个公式当中, α \alpha α为犯第一类错误的概率, β \beta β为犯第二类错误的概率,σ代表的是样本数据的标准差,δ代表的是预期实验组和对照组两组数据的差值。一般情况下,我们会设置:

  • 显著性水平: α = 0.05 \alpha=0.05 α=0.05,即在拒绝原假设之前,我们有95%的把握新版落地页的转化率比旧版落地页要高
  • 统计功效( 1 − β 1-\beta 1β): β = 0.2 \beta=0.2 β=0.2,即表示测试检测特定效果的能力,如果该特定效果存在的话。在此案例中就是,如果新版落地页真的比旧版转换率要高,该测试有80%的概率能检测出这个状况。
    当衡量指标为比率类指标时,标准差计算公式为:
    σ 2 = P A ( 1 − P A ) + P B ( 1 − P B ) \sigma^2 = P_A(1-P_A)+P_B(1-P_B) σ2=PA(1PA)+PB(1PB)
    其中,𝑃𝐴和𝑃𝐵分别是对照组和实验组的观测值。在此案例中𝑃𝐴=13%,𝑃𝐵=15%
    每个组所需的最小样本量为:
    N = σ 2 δ 2 ( Z 1 − α 2 + Z 1 − β ) 2 = ( 0.13 ∗ ( 1 − 0.13 ) + 0.15 ∗ ( 1 − 0.15 ) ) / ( 0.15 − 0.13 ) 2 ∗ ( 1.96 + 0.84 ) 2 = 4716 N = \frac{\sigma^2}{\delta^2}(Z_{1-\frac{\alpha}{2}}+Z_{1-\beta})^2 \\ = (0.13*(1-0.13)+0.15*(1-0.15))/(0.15-0.13)^2*(1.96+0.84)^2 \\ = 4716 N=δ2σ2(Z12α+Z1β)2=(0.13(10.13)+0.15(10.15))/(0.150.13)2(1.96+0.84)2=4716
#计算每一组的样本量
(0.13*(1-0.13)+0.15*(1-0.15))/(0.15-0.13)**2*(1.96+0.84)**2
# 引入需要的包
import numpy as np 
import pandas as pd 
import scipy.stats as stats 
import statsmodels.stats.api as sms 
import matplotlib as mpl 
import matplotlib.pyplot as plt 
import seaborn as sns 
# 计算效果量
effect_size = sms.proportion_effectsize(0.13, 0.15) 
effect_size
# 计算所需的样本量
required_n = sms.NormalIndPower().solve_power( 
    effect_size, 
    power=0.8, 
    alpha=0.05, 
    ratio=1 ,
    ) 
    required_n
#向上取整
np.ceil(required_n) 
  • 实验周期的确定
      根据上面最小样本量的计算,我们知道此次AB测试至少需要9440个用户参与测试,假如该落地页以往每天的平均浏览量为1000,则实验周期至少需要的天数为:

试验周期 = 9440 / 1000 = 9.4 ≈ 10 (天) 试验周期 = 9440/1000 = 9.4 ≈10(天) 试验周期=9440/1000=9.410(天)

===================================================================

Step4:上线AB测试并收集数据

  上线AB测试,同时收集数据。(我们这里采用的是kaggle上的数据)

===================================================================

Step5:数据分析及假设检验

  这里使用的是Kaggle上的A/B测试数据集来模拟练习。

  • 导入数据集
# 导入数据集
df = pd.read_csv("ab_data.csv")
df.head()
df.info()
df["group"].value_counts()
df["landing_page"].value_counts()
  • 数据清洗
# 检查缺失值并处理
df.isnull().sum()
# 检查重复值并处理
df.duplicated().sum() #对于整体数据集没有重复值
# 检查用户是否有重复值
df["user_id"].duplicated().sum()
#查看重复值对应的用户Id
df[df["user_id"].duplicated()]["user_id"]
# 储存所有的重复用户ID
del_id = df[df["user_id"].duplicated()]["user_id"].values
len(del_id)
del_id
#查看重复用户的所有数据
df["user_id"].isin(del_id).sum()
#非重复用户对应的布尔值结果
~df["user_id"].isin(del_id)
#非重复用户对应的所有数据
df_new = df[~df["user_id"].isin(del_id)]
df_new
#提取时间年月日形式
pd.to_datetime(df_new['timestamp'],format='%Y-%m-%d')
# 处理时间,并检查时间天数
date_days = pd.to_datetime(df_new['timestamp'],format='%Y-%m-%d').dt.strftime('%Y-%m-%d')
date_days
 #查看数据共有多少天
len(date_days.unique()) 
# 确保数据一一匹配
df_new.info()
# control组对应old_page,treatment组对应new_page
(((df_new['group']=='treatment')&(df_new['landing_page']=='new_page'))|((df_new['group']=='control')&(df_new['landing_page']=='old_page'))).sum()
# 确保contorl组每个用户看到的是旧页面,treatment组看到的是新页面
pd.crosstab(df_new['group'], df_new['landing_page'])

至此,所有的数据清洗工作已完成。

  • 抽样
    由于提供的数据量太大,所以每组4720个样本,这里我们选择每组抽样5000个
#随机提取5000个样本
df_new[df_new['group'] == 'control'].sample(n=required_n, random_state=22)
#每组各取5000个数据
required_n = 5000
control_sample = df_new[df_new['group'] == 'control'].sample(n=required_n, random_state=22) 
treatment_sample = df_new[df_new['group'] == 'treatment'].sample(n=required_n, random_state=22) 

ab_test = pd.concat([control_sample, treatment_sample], axis=0) 
ab_test.reset_index(drop=True, inplace=True)
ab_test
#查看数据是不是一一对应,有无交叉重复
pd.crosstab(ab_test['group'], ab_test['landing_page'])
  • 可视化结果【选做】
#查看均值和标准差
conversion_rates = ab_test.groupby('group')['converted'].agg([np.mean,np.std])
conversion_rates
from statsmodels.stats.proportion import proportions_ztest, proportion_confint
control_results = ab_test[ab_test['group'] == 'control']['converted']
treatment_results = ab_test[ab_test['group'] == 'treatment']['converted']
#查看数据
control_results
treatment_results
#计算控制组的转换数
control_results.sum()
#计算Z_test参数
n_con = control_results.count()
n_treat = treatment_results.count()
#控制组和实验组的转换下单数量
successes = [control_results.sum(), treatment_results.sum()]
#控制组和实验组的样本量
nobs = [n_con, n_treat]
#z-test
z_stat, pval = proportions_ztest(successes, nobs=nobs)
#z统计量计算结果
z_stat
#p值
pval
#各组置信区间
(lower_con, lower_treat), (upper_con, upper_treat) = proportion_confint(successes, nobs=nobs, alpha=0.05)
#显示检验结果
print(f'z statistic: {z_stat:.2f}')
print(f'p-value: {pval:.3f}')
print(f'ci 95% for control group: [{lower_con:.3f}, {upper_con:.3f}]')
print(f'ci 95% for treatment group: [{lower_treat:.3f}, {upper_treat:.3f}]')

==================================================================

Step6:分析结果及建议

  由于我们计算出来的P值=0.607远高于显著水平 α = 0.05 \alpha=0.05 α=0.05,所以我们不能拒绝原假设H0.这意味着新版落地页与旧版落地页没有明显不同(更不用说更好了……)
  此外,我们继续看置信区间,treatment组的置信区间为 [ 0.117 , 0.136 ] [0.117,0.136] [0.117,0.136],可以看出:

  • 它包括我们的转化率基准线13%
  • 它不包括我们的转化率目标值15%

  也可以说明,新版落地页的真实转化率更有可能与我们的基线相似,而没有办法达到我们期望的15%。进一步证明了,新版设计并不是一个很好的改进。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 Nginx 的反向代理功能来实现这个需求。具体配置如下: ``` server { listen 80; server_name www.test.com; location /projectA { proxy_pass http://127.0.0.1:8080/projectA; # springboot 项目的地址 proxy_set_header Host $host; # 设置请求头中的 Host 字段,用于支持虚拟主机 proxy_set_header X-Real-IP $remote_addr; # 将客户端真实 IP 地址传递给后端服务器 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 将客户端 IP 地址传递给后端服务器 } location /projectB { proxy_pass http://127.0.0.1:8081/projectB; # springboot 项目的地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /projectA/ { alias /path/to/vue/projectA/dist/; # vue 项目的地址 try_files $uri $uri/ /index.html; } location /projectB/ { alias /path/to/vue/projectB/dist/; # vue 项目的地址 try_files $uri $uri/ /index.html; } } ``` 这里假设两个 Spring Boot 项目的地址分别为 `http://127.0.0.1:8080/projectA` 和 `http://127.0.0.1:8081/projectB`,两个 Vue 项目的地址为 `/path/to/vue/projectA/dist/` 和 `/path/to/vue/projectB/dist/`。 其中,`location /projectA/` 和 `location /projectB/` 的作用是将 URL 中以 `/projectA` 或 `/projectB` 开头的请求映射到对应的 Vue 项目中。`try_files $uri $uri/ /index.html;` 是为了支持 Vue 的路由模式,将所有的 URL 都重定向到 Vue 的 `index.html` 页面中。 注意,在配置 Nginx 反向代理时,需要根据实际情况修改端口号、路径等参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值