AB测试实战(二)

简介: AB测试是一种数据驱动的产品优化方法,用于比较不同版本的网页、应用界面或营销策略的效果。

AB测试实战(一)+https://developer.aliyun.com/article/1544766?spm=a2c6h.13148508.setting.14.22454f0eHFZZj3


3、AB测试代码实战

3.1 项目背景


UI设计师设计了最新的产品页面想通过页面更新提高转化率


  • 目前的转化率全年平均在13%左右


  • 目标转化率达到 15%。


  • 在新的页面上线之前,我们要通过一小部分用户上测试页面的效果, 所以需要进行A/B测试

3.2 设计实验


  • 提出假设


首先,我们要确保在项目开始时就制定了一个假设


鉴于我们不知道新设计的性能是否会比我们当前的设计更好或更差(或相同?),我们将选择双尾测试:


H 0 原假设 老的设计比较好, 新版设计没有用


H 1 备选假设 新的设计比较好


  • 选择变量


对照组: 看到旧的设计

实验组: 看到新的设计


虽然我们已经知道了旧的设计的转化率(13%左右), 但是我们依然要需要设计两组, 原因是为了避免其他因素带来的误差, 比如季节因素, 促销因素。这两组人在其它条件都相同的只是页面设计不同的情况下进行实验, 这样能保证两组间的差异是由于设计导致的


我们的设计的目标KPI是转化率, 所以,我们会添加一个字段来记录用户的购买情况


购买了产品的用户 值为1

未购买产品的用户值为0


  • 确定实验人数


AB测试只会选择一小部分用户来参与实验, 用小部分的实验结果来估计整体的结果,每组的人数越多,我们得到的结果就越精准,但同时我们付出的成本就越大,通过功效分析我们可以计算出满足实验条件的最小人群


检验功效 (1 — β) :一般设置为0.8


α :在设计实验的时候我们设置为0.05


效果大小:旧的页面转化率为13%,新页面我们希望转化率能提升2%,所以我们可以用13%和15%来计算预期效果大小


确定实验人数的计算过程可以通过Python代码实现


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
from math import ceil

%matplotlib inline


effect_size = sms.proportion_effectsize(0.13, 0.15)   

required_n = sms.NormalIndPower().solve_power(
    effect_size,
    power=0.8, 
    alpha=0.05, 
    ratio=1  
    )                                                  
#对结果向上取整
required_n = ceil(required_n)                         

print(required_n)


4720


  • 计算结果说明每组至少需要4720人
  • 在实践中将功率参数设置为 0.8 意味着如果我们的设计之间存在转化率的实际差异,假设差异是我们估计的差异(13% 对 15%),我们有大约 80% 的机会检测到它 与我们计算的样本量在我们的测试中具有统计显着性。


3.3 收集准备数据


  • 在企业场景下,我们需要与工程团队配合,收集满足要求的数据, 这里我们使用准备好的数据集, 对数据进行处理
  • 加载数据到DataFrame
  • 检查和清理数据
  • 从DataFrame中采样数据每组4720行


df = pd.read_csv('data/ab_data.csv')
df.head()



user_id
timestamp group landing_page converted
0 851104 2017-01-21 22:11:48.556739 control old_page 0
1 804228 2017-01-12 08:01:45.159739 control old_page 0
2 661590 2017-01-11 16:55:06.154213 treatment new_page 0
3 853541 2017-01-08 18:28:03.143765 treatment new_page 0
4 864975 2017-01-21 01:52:26.210827 control old_page 1


  • 查看数据基本情况


df.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 294478 entries, 0 to 294477
Data columns (total 5 columns):
 #   Column        Non-Null Count   Dtype 
---  ------        --------------   ----- 
 0   user_id       294478 non-null  int64 
 1   timestamp     294478 non-null  object
 2   group         294478 non-null  object
 3   landing_page  294478 non-null  object
 4   converted     294478 non-null  int64 
dtypes: int64(2), object(3)
memory usage: 11.2+ MB


数据一共294478行,每一条数据代表一次用户访问,共五列:


  • user_id - 访问的用户ID
  • timestamp - 访问的时间
  • group - 该用户被放到那一组 {control对照, treatment实验}
  • landing_page -该用户看到的是哪一种落地页 {old_page老页面, new_page新页面}
  • converted - 改次访问是否有转化 (binary, 0=无转化, 1=转化)


在后续的分析中,我们实际上主要用到的是 group 和converted 这两个字段


创建透视表, 查询是否对照组看到的都是老页面


df.pivot_table(index = 'group',columns='landing_page',values = 'user_id',aggfunc='count')


anding_page new_page old_page
group
control 1928 145274
treatment 145311 1965


  • 在我们进行后续处理之前, 还要查看是否有用户进行了多次操作


session_counts = df['user_id'].value_counts(ascending=False)
multi_users = session_counts[session_counts>1].count()
multi_users


3894


  • 说明一共有3894个用户访问了不止一次, 整体数据有20多万条, 所以我们直接把这部分数据删除


users = session_counts[session_counts < 2].index
df = df[df['user_id'].isin(users)]


数据采样


  • 接下来我们从处理后的数据中,每组采样4720条数据, 我们这里使用DataFrame的sample()方法进行简单随机采样


control_sample = df[df['group'] == 'control'].sample(n=required_n, random_state=22)
treatment_sample = df[df['group'] == 'treatment'].sample(n=required_n, random_state=22)
# 这里random_state 为随机数种子, 如果也传入22, 那么后续结果会与讲义中一样
ab_test = pd.concat([control_sample, treatment_sample], axis=0)
ab_test.reset_index(drop=True, inplace=True)
ab_test



user_id
timestamp group landing_page converted
user_id
group landing_page converted
0 763854 2017-01-21 03:43:17.188315 control old_page 0 0




1 690555 2017-01-18 06:38:13.079449 control old_page 0 1




2 861520 2017-01-06 21:13:40.044766 control old_page 0 2




3 630778 2017-01-05 16:42:36.995204 control old_page 0 3




4 656634 2017-01-04 15:31:21.676130 control old_page 0 4







9435 908512 2017-01-14 22:02:29.922674 treatment new_page 0 9435




9436 873211 2017-01-05 00:57:16.167151 treatment new_page 0 9436




9437 631276 2017-01-20 18:56:58.167809 treatment new_page 0 9437




9438 662301 2017-01-03 08:10:57.768806 treatment new_page 0 9438




9439 944623 2017-01-19 10:56:01.648653 treatment new_page 1 9439





  • 查看两组数据情况


ab_test.groupby('group')['landing_page'].value_counts()
# landing_page 落地页类型  old_page老页面 new_page 新页面
# control 控制组  treatment 对照组


group landing_page

control old_page 4720

treatment new_page 4720

Name: landing_page, dtype: int64


3.4 分析实验结果


  • 首先我们来计算一下两组的转化率和标准差


conversion_rates = ab_test.groupby('group')['converted'].mean().to_frame()
conversion_rates 

conversion_rates.style.format('{:.3f}')


group conversion_rate
control 0.123
treatment 0.126


  • 从上面的统计数据来看,旧的和新的落地页表现非常相似,新设计表现略好, 12.3% 与 12.6%


  • 从对照组的数据看, 转换率为12.3% 比之前我们的整体表现要差一些, 可能与采样人群的差异有关
  • 测试组的数据比对照组要好一些, 但是这个结果是否具有统计意义?


3.5 假设检验


  • 最后一步是假设检验, 我们的样本量比较大,可以应用Z检验来计算P值, 如果P值<0.05, 说明
  • 我们可以使用statsmodels.stats.proportion 模块来计算P值和置信区间


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'] #获取实验组是否转化的数据
n_con = control_results.count() # 获取对照组人数
n_treat = treatment_results.count()  # 获取实验组人数
successes = [control_results.sum(), treatment_results.sum()] # 获取实验组和对照组成功转化的人数
nobs = [n_con, n_treat]

z_stat, pval = proportions_ztest(successes, nobs=nobs)  #计算P值
(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}]')


🥂小结


AB测试的应用场景


  • 互联网行业应用广泛:页面结构调整, 换新图标,添加新功能等等
  • 实体行业应用相对复杂一些:不同优惠券效果测试


AB测试还是ABC测试


  • AB测试:一次测试一个方案
  • ABC…… 测试: 一次测试多个方案,但需要流量足够大,否则难以满足实验要求的最少人数


AB测试需要注意如下几点


  • 流量分配


  • 确定有效的最小参与人数
  • 确定基准指标和提升目标
  • 设置显著性水平α (一般是5%)和 统计功效 1-β (一般是80%)
  • 出结果之后计算P值 如果P<5% 则可以拒绝原假设算P值 如果P<5% 则可以拒绝原假设
  • 我们可以通过AB测试工具网站帮助确定人数,也可以使用statsmodels 模块来通过代码实现


  • import statsmodels.stats.api 计算需要人数
  • statsmodels.stats.proportion 计算P值和置信区间


相关文章
|
15天前
|
SQL 搜索推荐 Android开发
AB测试实战(一)
AB测试是一种数据驱动的产品优化方法,用于比较不同版本的网页、应用界面或营销策略的效果。
|
25天前
|
设计模式 Java 测试技术
Java8实战-重构、测试和调试(二)
Java8实战-重构、测试和调试(二)
46 2
|
3天前
|
JavaScript 测试技术
vue 官方测试工具 unit-jest 实用教程(含实战范例:登录组件的测试)
vue 官方测试工具 unit-jest 实用教程(含实战范例:登录组件的测试)
5 0
|
8天前
|
消息中间件 缓存 中间件
【赠书活动 - 第1期】- 测试工程师Python开发实战(异步图书出品)| 文末送书
【赠书活动 - 第1期】- 测试工程师Python开发实战(异步图书出品)| 文末送书
|
2月前
|
测试技术 Apache Windows
如何使用apache的ab压力测试小工具传参数
该内容是关于在Windows环境下使用PHPStudy中的Apache集成的ab工具进行性能测试的简要教程。
39 9
|
24天前
|
前端开发 Java 测试技术
【SpringBoot】单元测试实战演示及心得分享
【SpringBoot】单元测试实战演示及心得分享
35 0
|
25天前
|
设计模式 算法 Java
Java8实战-重构、测试和调试(一)
Java8实战-重构、测试和调试(一)
16 0
|
2月前
|
开发框架 监控 Java
深入探索Spring Boot的监控、管理和测试功能及实战应用
【5月更文挑战第14天】Spring Boot是一个快速开发框架,提供了一系列的功能模块,包括监控、管理和测试等。本文将深入探讨Spring Boot中监控、管理和测试功能的原理与应用,并提供实际应用场景的示例。
36 2
|
2月前
|
存储 人工智能 测试技术
python自动化测试实战 —— CSDN的Web页面自动化测试
python自动化测试实战 —— CSDN的Web页面自动化测试
213 0
|
6天前
|
JSON JavaScript 测试技术
Postman接口测试工具详解
Postman接口测试工具详解
14 1