A/Btest (A/B测试)的营销策略效果分析
目录
前言
本文分析以支付宝营销活动为例,通过广告点击率指标比较两组营销策略的广告投放效果。
一、数据介绍
来自阿里天池:数据
用到的是:effect_tb.csv: Click/Non-click dataset.
这个csv文件主要用来记录用户是否对广告进行点击。
二、观察数据
1.引入库
# import libraries
import pandas as pd
import numpy as np
pd.set_option('float_format', lambda x: '%.4f' % x)
2.读入数据
# load data
data = pd.read_csv('effect_tb.csv',header = None)
data.columns = ["试验后天数","用户编号","是否点击","试验组别"]
3.观察数据
data.info()
# table summary
data.describe()
# distinct count of columns
data.nunique()
#把重复用户的用户编号变成一个list去观察
dup_userid=data["用户编号"].value_counts()[data["用户编号"].value_counts()>1].index.tolist()
#查看是否都全部字段都重复的记录
data[data.duplicated()]
虽然有重复的用户id,但是可能在不用的时间(试验后几天)去做这个测试,也可能被放在不同的组别(实验组别)、有不同的结果(是否点击),我们都去验证一下。
print("有重复用户编号的记录条数:",data[data["用户编号"].isin(dup_userid)].shape[0])
print("用户编号和【在第几天试验】重复的记录条数:",data[data["用户编号"].isin(dup_userid)].duplicated(["用户编号","试验后天数"]).sum())
print("用户编号和【是否点击】重复的记录条数:",data[data["用户编号"].isin(dup_userid)].duplicated(["用户编号","是否点击"]).sum())
print("用户编号和【试验组别】重复的记录条数:",data[data["用户编号"].isin(dup_userid)].duplicated(["用户编号","试验组别"]).sum())
print("用户编号和【试验后天数】、【是否点击】重复的记录条数:",data[data["用户编号"].isin(dup_userid)].duplicated(["用户编号","试验后天数","是否点击"]).sum())
print("用户编号和【试验后天数】、【试验组别】重复的记录条数:",data[data["用户编号"].isin(dup_userid)].duplicated(["用户编号","试验后天数","试验组别"]).sum())
用户ID和【试验后天数】、【试验组别】重复的记录条数: 0
意味着一个用户在不同天用了不同版本,简而言之,没有一个用户在同一天用一个版本。
可以不删除数据,因为如果按照用户编号去重了,会对整个对比有影响。(之后讨论)
data.pivot_table(index = "试验组别", columns = "是否点击", values = "用户编号",aggfunc = "count",margins = True)
三、计算效果
1.简单比对不同策略点击率
#各组的点击率:
print("对照组点击率:",data[data["试验组别"]==1]["是否点击"].mean())
print("一组试验点击率:",data[data["试验组别"]==2]["是否点击"].mean())
print("二组试验点击率:",data[data["试验组别"]==3]["是否点击"].mean())
策略一组和策略二组都相对于对照组有提升,看起来策略二组提升得更多。
查看策略一组二组相对于参照组来说提升了多少
print("对照组点击率:",data[data['试验组别']==1]['是否点击'].mean())
print("策略一相对对照组提升:",round((data[data['试验组别']==2]['是否点击'].mean()-data[data['试验组别']==1]['是否点击'].mean())*100,3))
print("策略二相对对照组提升:",round((data[data['试验组别']==3]['是否点击'].mean()-data[data['试验组别']==1]['是否点击'].mean())*100,3))
策略一提升了0.279%,策略二提升了1.364。
假定我们希望新的营销策略能让广告点击率至少提升1个百分点才算提升。那么这里策略一不算是提升。我们研究策略二组的点击率是否在置信区间内有显著提升。
2.观察样本容量
在进行A/B测试前,需检查样本容量是否满足试验所需最小值。
这里借助Evan Miller的样本量计算工具:
已知对照组点击率为1.26%,假定我们希望新的营销策略能让广告点击率至少提升1个百分点才算提升,显著性水平α取5%,则算得所需最小样本量为:2167。
data["试验组别"].value_counts()
两组营销活动的样本量都满足最小样本量需求。
3.计算(以策略二组和对照组为例)
3.1 设定假设
接下来需要进行假设检验,这里先查看一组点击率的提升是否显著。
-
零假设和备择假设。记对照组点击率为p0,策略二组点击率为p2,则:
零假设 H0: p0 ≥ p2 (对照组的点击率大于等于策略一组)
备择假设 H1: p0 < p2 (对照组的点击率小于策略一组) -
分布类型、检验类型和显著性水平样本服从二点分布,独立双样本,样本大小n>30,总体均值和标准差未知,所以采用Z检验。显著性水平α取0.05。显著性水平α取0.05的单尾检测(左侧)对应的z值 = -1.64。
z值可以用python得出或者查看z-score表:
from scipy.stats import norm
z_alpha = norm.ppf(0.05)
# 若为双侧,则norm.ppf(0.05/2)
结果为z_alpha=-1.6448536269514729,统计上一般取-1.645,拒绝域为{z <z_alpha }
3.2 计算方法
独立双样本,样本大小n>30,总体的均值和标准差未知的Z检验的检验统计量公式如下:
3.2.1 方法一:公式计算
# 用户数
n_old = len(data[data["试验组别"] == 1]) # 对照组
n_two = len(data[data["试验组别"] == 3]) # 策略二组
# 点击数
c_old = len(data[data["试验组别"] == 1][data["是否点击"] == 1])
c_two = len(data[data["试验组别"] == 3][data["是否点击"] == 1])
# 计算点击率
r_old = c_old / n_old
r_two = c_two / n_two
#点击率标准差
std_old=np.std(data[data["试验组别"] == 1]["是否点击"])
std_two=np.std(data[data["试验组别"] == 3]["是否点击"])
# 总和点击率
r = (c_old + c_two) / (n_old + n_two)
print("转化率的联合率::", r)
'''
结果:
转化率的联合率: 0.014429896833357214
'''
按照公式计算:
z_two = (r_old - r_two) / np.sqrt(r * (1 - r)*(1/n_old + 1/n_two))
print("检验统计量z:", z_two)
'''
结果:
检验统计量z: -59.66600946268368
'''
z_one = -59.66600946268368 < -1.64,符合拒绝域为{z<z_alpha}。
所以我们可以得出结论:原假设(对照组的点击率大于策略一组)不成立,策略二点击率的提升在统计上是显著的。
3.2.2 方法二:Python函数计算
直接用python statsmodels包计算z值和p值。
难点:
alternativestr The alternative hypothesis, H1, has to be one of the
following
- ‘two-sided’: H1: difference in means not equal to value (default)
- ‘larger’ : H1: difference in means larger than value
- ‘smaller’ : H1: difference in means smaller than value
import statsmodels.stats.proportion as sp
z_two_score, p = sp.proportions_ztest([ c_two,c_old],[ n_two,n_old], alternative = "la")
print("检验统计量z_two:",z_two_score,",p值:", p)
#alternative 默认 ='two-sided'
#alternative='smaller'代表左尾
#用p值判断与用检验统计量z判断是等效的
'''
结果:
检验统计量z_two: -59.66600946268368 ,p值: 0.0
'''
p值约等于0,p < α,与方法一结论相同,拒绝原假设。
4.扩展
4.1 扩展一:策略一组和对照组对比
策略二组点击率的提升是否显著。
p1为策略一组,p0为对照组
- 零假设 H0: p1 < p0 (策略二组相比于对照组无提升)
- 备择假设 H1: p1 ≥ p0 (策略二组相比于对照组有提升)
# 用户数
n_old = len(data[data["试验组别"] == 1]) # 对照组
n_one = len(data[data["试验组别"] == 2]) # 一组
# 点击数
c_old = len(data[data["试验组别"] == 1][data["是否点击"] == 1])
c_one = len(data[data["试验组别"] == 2][data["是否点击"] == 1])
# 计算点击率
r_old = c_old / n_old
r_one = c_one / n_one
# 总和点击率
r = (c_old + c_one) / (n_old + n_one)
print("转化率的联合率:", r)
z_one_score, p = sp.proportions_ztest([c_old, c_one],[n_old, n_one], alternative = "smaller")
print("检验统计量z_one:",z_one_score,",p值:", p)
'''
结果:
转化率的联合率:0.01298700183320143
检验统计量z_one: -14.362726203811503 ,p值: 4.433468512724253e-47
(P值约等于0)
'''
z_one < -1.64,,p < 0.05,拒绝原假设,即策略一组相比于对照组有提升。
4.2 扩展二:策略二组和策略一组对比
那么策略一和策略二相比呢?
p1为策略一组,p2为策略二组
因为从之前的结果看起来策略二组比策略一组提升更多,那么我们先假设是这样。
- 零假设 H0: p2 <≥ p1 (策略二组相比于策略一组有提升)
- 备择假设 H1: p2 ≥ p1 (策略二组相比于策略一组无提升)
看一下样本容量,算出这两组对比所需最小样本量为:2580。
这两组样本的容量符合要求。
z_one_two_score, p = sp.proportions_ztest([ c_two,c_one],[ n_two,n_one], alternative = "smaller")
print("检验统计量z:",round(z_one_two_score,4),",p值:", round(p,4))
'''
结果:
检验统计量z: 32.818 ,p值: 1.0
'''
p值约等于1,p > α(0.05),符合原假设,即策略二组相比于策略一组有提升。
总结
- 策略一和策略二都相对于对照组对广告点击率有显著提升效果。
- 策略二相对于策略一对广告点击率有显著提升效果。