作者:数据星爷,CDA特约作者  上市公司高级分析师/微软认证Excel专家

我们来看看以下几个场景:

  1. 产品:现在我们有一个想法,比如说对于产品的某个按钮由方形改成了圆形或是两个按钮的位置做了调整,我们猜想其会增加用户的点击转化率,但是,实际上我们并不知道是不是真的跟我们想的一样,毕竟用户真正的决策行为很难预料到,如果强行修改全量上线,在转化率降低的情况下影响很大。
  2. 运营:现在我们有一个想法,要做一个活动,需要给目标用户进行触达,但是呢,我们怎么知道触达之后效果如何呢?如果不做活动是不是也能带来相同的效果呢?
  3. 产品&运营:我们有ABCD...个想法,但是呢,我们不确定哪个方案比较好,怎么办呢?

上面这些问题,我们都可以使用AB测试来完成,能够在成本最低的情况下做最好的决策。

01AB测试的原理和作用

什么是AB测试

AB测试是为Web或App界面或流程制作两个(A/B)或多个(A/B/n)版本,在同一时间维度,分别让组成成分相同(相似)的访客群组(目标人群)随机的访问这些版本,收集各群组的用户体验数据和业务数据,最后分析、评估出最好版本,正式采用。

简单来说,就是同时进行多个方案的测试,在这些方案中选出最好的版本。(其实就是局部最优解)

作用

  1. 目标:搜集数据以驱动决策
  2. 评估多个方案的最优方案
  3. 评估活动的效果


02AB测试适用的场景

适合的场景

例子

不适合场景

例子

更优问题

ABC三种营销页哪个更好?

最优问题

如何设计最好的落地页?

估计短期影响

发送优惠券对于销量的提升

长期影响

新功能能否带来长期的收益?

因果分析

优化营销页能否提升转化率?

结果分析

转化率提升的原因?

战术性迭代

聊天按钮放在左边还是右边?

战略性迭代

要不要增加开聊按钮?

03如何开展AB测试

原始假设

我们可以看到AB测试是对多个版本进行评估,或是优化现有的方案。这些都是有一定的假设,那么假设的来源有哪些呢?

  1. 产品或是运营根据自己多年经验提出假设。
  2. 数据分析师通过数据分析给到的建议,这里就体现了我们数据分析师的价值了,如果能够写出分析报告让业务方采纳是很不容易,如果采纳并上线后有效果是更不容易。(如果感兴趣可以看看我的其他文章,有关于如何写可落地的分析报告)

数据分析-使用OSQSM模型+逆推法写出可落地的分析报告

产品运营方案交流

假设建立完成之后,就需要出具体的产品和运营方案,讨论方案的可行性。这个时候需要研发,所以在这之前,如果你的假设是基于自己经验的时候,最好有一些辅助的数据支撑,不然很容易被质疑,因为资源是有限的,给你做了就不能给其他人做。

确定分流人群

一旦方案确定之后,我们需要考虑我们的分流人群,是对于新用户还是老用户,是需要进入特定场景的用户还是其他。

确定观察指标

人群确定之后,就需要考虑观测指标了。指标分两种:

  1. 核心指标:也称为目标指标,就是我们想要提升的指标,一般就是一个,最多不超过3个。另外,一般是均值或是比率,而不是规模。
  2. 基础指标:跟基础体验相关的指标,比如我们要优化营销也到商品选择页的转化率,那么,在优化营销页的时候,至少保证新老版本的加载是一样。

有个亲身经历的营销页AB测试时,研发为了方便,新版本默认加载一下老页面然后再加载新页面,这样用户在能感知到老页面闪了一下,然后再出新页面,这样的结果就是新版本PV会是原来的两倍。

计算用户量以及实验周期

理论支撑

在计算样本量时有两种情况,一种是均值比如人均搜索次数,一种是比率比如用户的购买率或是点击转化率等,两种情况计算方式有所差异:

均值:

比率:

计算用户量的网站

如果觉得手算比较麻烦,并且实际工作中提高效率,可以直接使用下面的网站:

均值:

http://powerandsamplesize.com/Calculators/Compare-2-Means/2-Sample-Equality。

其他网站,我自己用的少,大家感兴趣可以自己去看看

https://abtestguide.com/abtestsize/。

比率:

https://www.evanmiller.org/ab-testing/sample-size.html

  • 1处:原始比率,这里原始转化率是20.911798%
  • 2处:想提升的百分数,这个地方是根据3处的选项来填写具体的值
  • 3处:提升的是绝对量还是涨幅,有两个选项Absolute是绝对量,Relative相对量(涨幅)。比如我想从20.911798%提升5%到达21.9638%。那么这里的2处填写5,3处选择Relative
  • 4处:默认80%
  • 5处:默认5%

注意点-影响用户量

  • 从样本量计算公式中,我们可以看出对于均值来说标准差α越大,也就是样本的波动越大,需要的样本也是越大的。
  • 两外还有一个影响样本量的就是提升量 Δ,我们可以看出想要提升的幅度越大,我们需要的样本量就越小,其实也可以理解,越大的差异越容易观察到。
  • 还有两个默认给到的值是α、β

注意点-周期

  1. 安全性,影响放量策略。比如一些重大的改动可能对于用户的影响很大,那么,我们一般会切小流量,这样就会需要给长的时间周期
  2. 流量的大小。
    1. 多个实验,如果有多个实验的话,为了避免有相互影响,我们就需要在不同的层进行实验,这时候流量就会变小,也会影响,就需要更长的周期
    2. 本身分流人群比较少,也会需要更长的时间,比如只对新用户进行实验,对于成熟的APP,新用户的量比老用户少很多。
  3. 周内效应和季节效应。一般周内的用户和周末的用户行为表现不一样,所以建议至少实验一周。还有一些有周期性的或是节假日的影响。比如七夕节对于中国和其他国家的用户表现的就不一样。
  4. 初始和新奇效应。有些实验在初始阶有或大或小的影响,并在一段时间后趋向稳定,所以需要更长时间。

确定分流方式

分流方式也有很多中,一般公司做的比较完善的都会把流量分成不同的域,不同的层进行试验,试验抽取的用户都是随机抽取的。

但是根据经验来说,很多研发为了省事直接指定用户尾号进行测试,这是非常常见的错误。

进行实验

一切准备好了就开始试验了,在这里再次强调一个问题:

一定要埋点!!!

一定要埋点!!!

一定要埋点!!!

重要的事情说三遍,很多产品运营最后想看数据发现没有数,因为根本没有提埋点。最后可能什么都评估不了。我遇到的情况:

  1. 没有数,前期没有沟通想看的数据,没提埋点,这种情况好解决就是一定提前跟相应的分析师聊需要看的基数指标和核心指标是什么,然后提埋点,基本问题不大。
  2. 有数,但是数不对,研发功能到是实现了,但是会带一堆的逻辑,比如前面提到的默认加载老页面。这种情况就是不太好解决,很难想到研发会这么去做。。。这就看研发的能力了。

分析结果

按照前面计算需要的样本量,达到之后,我们就需要开始分析了。这里看的就是前面提到的基础指标和核心指标了。

一定要看基础指标!!!

一定要看基础指标!!!

一定要看基础指标!!!

稳定是一切事情的前提,这里的稳定就是指基础指标了

04利用Python 实践AB试验

均值的AB测试

背景

想提高人均搜索次数,基于这个目标,有一些假设,然后进行试验

原始数据

导入需要用到的包

import pandas as pd
import numpy as np
from scipy import stats
from statsmodels.stats.power import tt_ind_solve_power
from statsmodels.stats.proportion import proportion_effectsize as es 
from scipy.stats import ttest_ind,norm,f

构建监测数据

data = {'avg_cnt':[11.077378,8.398665,8.571959,8.283145,5.93106,7.453807,9.184988,7.755004,8.438116,9.159712,6.773043,8.315689,7.682243,7.343689,8.982294,7.653003,7.419295,8.419876,6.440056,7.040037,9.724157,8.956077,8.760673,9.226514,6.82048,5.025931,6.90876,8.110434,6.430384,8.037746]}
df = pd.DataFrame(data)

正态性检验

'''输出结果中第一个为统计量,第二个为P值(统计量越接近1越表明数据和正态分布拟合的好,P值大于指定的显著性水平,接受原假设,认为样本来自服从正态分布的总体)'''
print(stats.shapiro(df))

'''输出结果中第一个为统计量,第二个为P值(注:p值大于显著性水平0.05,认为样本数据符合正态分布)'''
print(stats.normaltest(df))

样本量计算

  • 计算
tt_ind_solve_power(effect_size=(|μA-μB|)/σ, alpha=0.05, power=0.8, ratio=1.0, alternative="two-sided")
# effect_size,|μA-μB|是原始均值和希望提升到的均值之差,也就是提升的绝对值,σ是标准差,直接取一段时间内的样本均值的标准差。
# alpha,默认取0.05
# power,默认取0.8
# ratio,
  • 在计算样本量之前,计算样本均值和标准差
print("标准差:",np.std(df))
print("均值:",np.mean(df))
print("提升量:",np.mean(df)*0.02)

计算样本量 : 923

tt_ind_solve_power(effect_size=(0.158883)/1.217752, alpha=0.05, power=0.8, ratio=1.0, alternative="two-sided")

也可以使用前面提到的网站,有详细的操作步骤:

http://powerandsamplesize.com/Calculators/Compare-2-Means/2-Sample-Equality。

结果检验

实验上线后达到了观察周期后的数据,data1为新版本数据,data2为老版本数据。

data_af = pd.DataFrame(
    {
    'data1':[5.679312,5.596886,6.044847,5.994368,7.532478,5.922314,4.296232,4.188054,3.777318,8.253483,7.114997,6.82596,7.213144,4.213463],
    'data2':[6.150766,4.026921,8.072727,8.764057,6.079969,5.504954,7.113292,6.33763,4.940921,6.367048,7.244069,6.365149,7.964037,3.840968]
    }
    )

T检验,定义函数:

from scipy.stats import ttest_ind,norm,f
import numpy as np
import pandas as pd
def ftest(s1,s2):
    #'''F检验样本总体方差是否相等'''
    print("Null Hypothesis:var(s1)=var(s2),α=0.05")
    F = np.var(s1)/np.var(s2)
    v1 = len(s1) - 1
    v2 = len(s2) - 1
    p_val = 1 - 2*abs(0.5-f.cdf(F,v1,v2))
    print(p_val)
    if p_val < 0.05:
        print("Reject the Null Hypothesis.")
        equal_var=False
    else:
        print("Accept the Null Hypothesis.")
        equal_var=True
    return equal_var


def ttest_ind_fun(s1,s2):
    #'''t检验独立样本所代表的两个总体均值是否存在差异'''
    equal_var = ftest(s1,s2)
    print("Null Hypothesis:mean(s1)=mean(s2),α=0.05")
    ttest,pval = ttest_ind(s1,s2,equal_var=equal_var) #如果equal_var为True(默认),则执行一个标准的独立2样本检验,该检验假设总体方差相等[1]。如果为False,则执行Welch的t检验,该检验不假定总体方差相等
    if pval < 0.05:
        print("Reject the Null Hypothesis.")
    else:
        print("Accept the Null Hypothesis.")
    return pval


# np.random.seed(42)
#s1 = norm.rvs(loc=1,scale=1.0,size=20)
#s2 = norm.rvs(loc=1.5,scale=0.5,size=20)
# s3 = norm.rvs(loc=1.5,scale=0.5,size=25)
#print(s1)
#print(s2)

结果:无差异

ttest_ind_fun(data_af['data1'],data_af['data2'])


比率的AB测试

背景

对于营销页进行AB测试,以提升营销页到商品选择页的转化率。

原始数据

导入需要的包

import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
from statsmodels.stats.power import tt_ind_solve_power
from statsmodels.stats.proportion import proportion_effectsize as es 
from scipy.stats import ttest_ind,norm,f
import statsmodels.stats.weightstats as sw

实验前数据:

data = {
    "ratio":[0.211249,0.217914,0.22124,0.20922,0.214652,0.207703,0.187119,0.204098,0.20032,0.203912,0.211707,0.205356,0.222301,0.206412,0.214494]
}
df =pd.DataFrame(data)

样本量计算

历史数据

print("平均转化率:",df['ratio'].mean())
print("转化率提升5%:",df['ratio'].mean()*0.05)
print("转化率提升5%后:",df['ratio'].mean()*1.05)

计算样本量

结果:24168

####样本量
tt_ind_solve_power(effect_size=es(prop1=0.2091798, prop2=0.21963879), alpha=0.05, power=0.8, ratio=1.0, alternative="two-sided")

也可以使用前面提到的网站,有详细的操作步骤:
https://www.evanmiller.org/ab-testing/sample-size.html

结果检验

实验上线后数据

data_df={
    'ratio_new':[0.20324,0.19301,0.21427,0.20777,0.20836,0.20266,0.207759,0.200588,0.198808,0.189438,0.207227,0.20823,0.207167],
    'ratio_old':[0.198468,0.212332,0.211364,0.219309,0.207997,0.201348,0.21549,0.209222,0.187228,0.198169,0.217129,0.211271,0.21982]
}
df_af = pd.DataFrame(data_df)

画图预览

plt.plot(df_af['ratio_new'],marker = 'o',label = 'new')
plt.plot(df_af['ratio_old'],marker = '*',label = 'old')
plt.legend()

结果检验:无差异

z_value, p_value = sw.ztest(df_af['ratio_new'],df_af['ratio_old'],alternative='two-sided')
print('统计量:',z_value)
print('P值:',p_value)

05AB测试过程中的问题

什么样的变化是实际显著的,对于业务的提升效果明显

既要考虑本实验的结果,也要考虑其他的指标影响,比如点击率降低了,人数少了,但是进入之后的用户转化率升高了。

发布的成本问题,包含上线和维护成本。需要考虑发布的成本和带来的收益问题。

06其他

kaggle上的实验数据:

https://www.kaggle.com/datasets/thetrueboolean/ab-data?select=ab_data.csv

同事的血泪史:对于注册流程的改动,业务同学没有做AB,但是最后转化率降低了,同事评估说是由于这次改动带来的,被业务方狂怼了一次。

个人建议:对于不AB的改动,不要轻易下结论,业务方要什么数据给什么就好了。不然最后吃亏的是自己