AB Test

AB testing 简介

AB testing 本质上是基于假设性检验的统计过程,它首先对对照组和实验组提出了某种基本假设,比如改变产品的颜色用户的购买转化率会提升等,然后计算两组数据的差异性并判断差异是否具有统计学意义,来给出结论。本文会step by step 讲解下AB testing 样本量如何确定以及结果如何分析。

在进入hands on coding之前,我们先了解下统计学的几个基本概念

置信区间和抽样误差

样本中得到的观测值和总体中的真值间存在差异,由抽样样本分布和总体分布不一致造成的这种差异为抽样差异。比如说经过两周的统计,对照组转化率为52%,实验组转化率为53%,由于抽样误差的存在。正确的描述是实验组比对照组转化率高0.8%~1.2% ,抽样误差为0.2%,置信度为95%。

置信度95%说的是我们有95%的自信能说出“实验组转化率相比对照组转化率高0.8-1.2%”这句话。从概率论的角度解释,就是在其他参数不变的情况下,如果我们重复做同样的实验100次,那么有95次得出的实验组和对照组的转化率差异都在0.8%-1.2%这个区间内。

置信区间的公式为:AB Test

假设性检验

  • 原假设AB Test: 需要反对的假设(对照组和实验组的差异是由抽样误差引起的,本质上无差异)
  • 备择假设AB Test: 实际想接收的假设(对照组和实验组是由差异的)

与假设性检验对应的是两类error。Type 1 error: 假阳,对照组和实验组无差异,但是错误拒绝了原假设。置信水平一般取AB Test。Type 2 error: 假阴,对照组和实验组有差异,但是错误的接收了原假设。1-AB Test一般取80%

设计实验

假设一个场景,是产品团队对UX进行优化,当前版本用户转化率为13%,在全面上线新版本前,PM想做个ab test,看下新版本是否能将用户转化率提升到15%

设计ab test实验,最为重要的是计算样本量,样本量小了,样本不足以代表总体。实验结果不准确。样本量大了,花的费用也高。样本量大小通过power ananysis 估计得出,依赖下列参数。

  • Power of the test (AB Test) – 统计功效是正确的拒绝原假设的概率,对应1-type2 error。也就是说当对照组和实验组真实存在差异时,可以正确识别到。一般取0.8。
  • Alpha value (AB Test) – 显著性水平,一般设 0.05
  • Effect size – 对照组和实验组之间的差异

上code~

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
# Some plot styling preferences
plt.style.use('seaborn-whitegrid')
font = {'family' : 'Helvetica',
        'weight' : 'bold',
        'size'   : 14}

mpl.rc('font', **font)
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 = ceil(required_n)                          # 圆整                          

print(required_n)
4720

说明对照组和实验组都需要4720个用户的数据,由于统计功效取得是0.8,意味着我们有80%的信心说如果对照组和实验组检测出显著性差异,总体也是有差异的。

实验后分析

因为是假设一个场景,因此我们从网上download了一份数据,从中sample出需要的样本量,然后进而进行分析

variabledescription
user_idThe user ID of each session
timestampTimestamp for the session
groupWhich group the user was assigned to for that session {control, treatment}
landing_page新版设计还是旧版设计{old_page, new_page}
converted是否转化 (binary, 0=not converted, 1=converted)
df_1 = pd.read_csv('data.txt')
df_2 = pd.read_csv('data1.txt')
df = df_1.append(df_2)
df.head()
user_idtimestampgrouplanding_pageconverted
08511042017-01-21 22:11:48.556739controlold_page0
18042282017-01-12 08:01:45.159739controlold_page0
26615902017-01-11 16:55:06.154213treatmentnew_page0
38535412017-01-08 18:28:03.143765treatmentnew_page0
48649752017-01-21 01:52:26.210827controlold_page1
pd.crosstab(df['group'], df['landing_page'])
landing_pagenew_pageold_page
group
control1928145274
treatment1453111965
# 判断下是否有重复登录的客户,去重
session_counts = df['user_id'].value_counts(ascending=False)
multi_users = session_counts[session_counts > 1].count()

print(f'There are {multi_users} users that appear multiple times in the dataset')
There are 3894 users that appear multiple times in the dataset
# 客户数较少,直接remove
users_to_drop = session_counts[session_counts > 1].index

df = df[~df['user_id'].isin(users_to_drop)]
print(f'The updated dataset now has {df.shape[0]} entries')
The updated dataset now has 286690 entries
# sample出4720个用户
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)

ab_test = pd.concat([control_sample, treatment_sample], axis=0)
ab_test.reset_index(drop=True, inplace=True)

在进行post experiment分析前,我们看下对照组和实验组的数据分布

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

std_p = lambda x: np.std(x, ddof=0)              # Std. deviation of the proportion
se_p = lambda x: stats.sem(x, ddof=0)            # Std. error of the proportion (std / sqrt(n))

conversion_rates = conversion_rates.agg([np.mean, std_p, se_p])
conversion_rates.columns = ['conversion_rate', 'std_deviation', 'std_error']


conversion_rates.style.format('{:.3f}')
            <tr>
                    <th id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572level0_row0" class="row_heading level0 row0" >control</th>
                    <td id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572row0_col0" class="data row0 col0" >0.123</td>
                    <td id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572row0_col1" class="data row0 col1" >0.329</td>
                    <td id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572row0_col2" class="data row0 col2" >0.005</td>
        </tr>
        <tr>
                    <th id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572level0_row1" class="row_heading level0 row1" >treatment</th>
                    <td id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572row1_col0" class="data row1 col0" >0.126</td>
                    <td id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572row1_col1" class="data row1 col1" >0.331</td>
                    <td id="T_5bf3e656_d131_11ec_a497_62e4bb4c1572row1_col2" class="data row1 col2" >0.005</td>
        </tr>
</tbody></table>
conversion_ratestd_deviationstd_error
group

简单看的化,对照组转化率12.3%,实验组转换率12.6%。实验组略有提升,我们看下这个数据统计学上是否有意义。另外对照组的转化率也低于13%,我们也需要看下是否是由抽样误差导致的对照组和实验组的差异

用Z检验,检验下两组数据的差异统计学上是否显著

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)
(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}]')
z statistic: -0.34
p-value: 0.732
ci 95% for control group: [0.114, 0.133]
ci 95% for treatment group: [0.116, 0.135]

结论:Pvalue 本身也是大于0.05的,不能拒绝原假设,也就是说对照组和实验组没有本质的差异。虽然结果上看实验组还是提升了0.3%,但是是由于抽样误差引起的。另外从置信区间也能看的,对照组的区间是[0.114, 0.133],13%在这个区间里。同时实验组的区间是[0.116, 0.135],13%也在这个区间里,也说明本身对照组和实验组也是没有差异的。

————————-我是分割线————————

其实呢,ABtest能用到很多地方,像CRM会员管理中,给消费者发满减的券转化高还是买赠活动转化高,这种场景用ABtest做下实验就好了。这比很多其他方式的分析都直接,因为可以去除掉seasonality,竞品等的影响。如果后面项目中用到,我再做个序章~~~~

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
乘风的头像乘风管理团队
上一篇 2022年5月12日
下一篇 2022年5月12日

相关推荐