最完整版的AB测试理论和实践

框架

框架

为什么要做AB测试

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

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

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

AB测试的原理和作用

什么是AB测试

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

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

作用

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

AB测试适用的场景

如何开展AB测试?

原始假设

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

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

产品运营方案交流

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

确定分流人群

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

确定观察指标

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

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

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

计算用户量以及实验周期

理论支撑

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

均值:

比率:

计算用户量的网站

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

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

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

注意点-影响用户量

注意点-周期

  1. 安全性,影响放量策略。比如一些重大的改动可能对于用户的影响很大,那么,我们一般会切小流量,这样就会需要给长的时间周期

  2. 流量的大小。

  3. 多个实验,如果有多个实验的话,为了避免有相互影响,我们就需要在不同的层进行实验,这时候流量就会变小,也会影响,就需要更长的周期

  4. 本身分流人群比较少,也会需要更长的时间,比如只对新用户进行实验,对于成熟的APP,新用户的量比老用户少很多。

  5. 周内效应和季节效应。一般周内的用户和周末的用户行为表现不一样,所以建议至少实验一周。还有一些有周期性的或是节假日的影响。比如七夕节对于中国和其他国家的用户表现的就不一样。

  6. 初始和新奇效应。有些实验在初始阶有或大或小的影响,并在一段时间后趋向稳定,所以需要更长时间。

确定分流方式

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

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

进行实验

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

一定要埋点!!!

一定要埋点!!!

一定要埋点!!!

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

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

分析结果

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

一定要看基础指标!!!

一定要看基础指标!!!

一定要看基础指标!!!

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

利用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")

结果检验

  • 实验上线后达到了观察周期后的数据,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'])
image.png

比率的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)

AB测试过程中的问题

  1. 什么样的变化是实际显著的,对于业务的提升效果明显
  2. 既要考虑本实验的结果,也要考虑其他的指标影响,比如点击率降低了,人数少了,但是进入之后的用户转化率升高了。
  3. 发布的成本问题,包含上线和维护成本。需要考虑发布的成本和带来的收益问题。

其他

  1. kaggle上的实验数据https://www.kaggle.com/datasets/thetrueboolean/ab-data?select=ab_data.csv
  2. 同事的血泪史:对于注册流程的改动,业务同学没有做AB,但是最后转化率降低了,同事评估说是由于这次改动带来的,被业务方狂怼了一次。
  3. 个人建议:对于不AB的改动,不要轻易下结论,业务方要什么数据给什么就好了。不然最后吃亏的是自己
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容