AB Testing基础与Python实战(二)支付宝营销策略效果分析

1. 数据来源

本文所用数据集来自阿里云天池:

阿里云天池 - Audience Expansion Datasethttps://tianchi.aliyun.com/dataset/50893

该数据集包含三张表,分别记录了支付宝两组营销策略的活动情况:

effect_tb.csv: 广告点击情况数据集

emb_tb_2.csv: 用户特征数据集

seed_cand_tb.csv: 用户类型数据集

本篇文章中主要使用广告点击情况数据集effect_tb.csv。原始数据有四列,用到的是第二列到第四列的数据,涉及字段如下:

user_id:支付宝用户ID

label:用户当天是否点击活动广告(0:未点击,1:点击)

dmp_id:营销策略编号(源数据文档未作说明,这里根据数据情况设定为1:对照组,2:营销策略一,3:营销策略二)

2.数据处理

首先导入所需要的数据与Python 库

py 复制代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline


# 导入数据
data = pd.read_csv(r"audience_expansion\effect_tb.csv",header = None)
data.columns = ["dt","user_id","label","dmp_id"]

# 日志天数属性用不上,删除该列
data = data.drop(columns = "dt")
data.head(3)

查看数据行数与独立用户数检查是否存在重复行:

py 复制代码
#数据行数
data.shape

# 去重后行数
data.nunique()

数据行数2645958与独立用户数2410683不统一,检查一下重复行并删除:

py 复制代码
#筛选出重复的user_id
data[data.duplicated(keep = False)].sort_values(by = ["user_id"])

# 删除重复的行
data = data.drop_duplicates()

# 再次检查是否有重复的行
data[data.duplicated(keep = False)]

结果为空,已删除所有的重复的user_id

接着看看有没有空白值。

py 复制代码
#检查是否有空值
data.info(null_counts = True)

通过结果得到数据集无空值,无需进行处理。

拉一个透视表,生成label和dmp_id两列对应的值的计数情况,看看有没有异常值

py 复制代码
data.pivot_table(index = "dmp_id", columns = "label", values = "user_id",
                aggfunc = "count", margins = True)

从结果看也没有异常值,无需处理

3.样本量检验

在进行A/B测试前,需检查样本容量是否满足试验所需最小值。当然在实际的AB test中在确定实验方案时就定好了所需要的样本量,这里由于我们拿到的是已有的数据,所以简单做个验证

这里借助之前说到的样本量计算工具:
https://www.evanmiller.org/ab-testing/sample-size.html

首先需要设定点击率基准线以及最小提升比例,我们将对照组的点击率设为基准线,在工具中计算可以得到最小样本量

查看每个每个营销活动的样本数

py 复制代码
#按照dmp_id分类计数
data["dmp_id"].value_counts()

两组营销活动的样本量分别为41.11万和31.62万,满足最小样本量需求。

3.假设检验

先计算几组试验的点击率情况

py 复制代码
# 计算每组的点击率情况
print("对  照  组: " ,data[data["dmp_id"] == 1]["label"].mean())
print("营销策略一: " ,data[data["dmp_id"] == 2]["label"].mean())
print("营销策略二: " ,data[data["dmp_id"] == 3]["label"].mean())

#输出结果为:
#对  照  组:  0.012551012429794775
#营销策略一:  0.015314747742072015
#营销策略二:  0.026191869198779274

可以看到策略一和策略二相较对照组在点击率上都有不同程度提升。

其中策略一提升0.2个百分点,策略二提升1.3个百分点,只有策略二满足了前面我们对点击率提升最小值的要求。

接下来需要进行假设检验,看策略二点击率的提升是否显著。

a. 原假设和备择假设

记对照组点击率为\(p_1\),策略二点击率为\(p_2\),则:

原假设 H0: \(p_1 ≥ p_2\)

备择假设 H1: \(p_1< p_2\)

b. 分布类型、检验类型和显著性水平

数据结果只有点击和不点击,样本服从二点分布,独立双样本,样本大小n>30,总体均值和标准差未知,所以采用Z检验。显著性水平α取0.05。

c. Z检验的统计量

1.单样本的比例Z检验

用于检验样本比例与总体比例是否有显著差异。其公式为:

\[Z = \dfrac{\hat{p} - p}{\sqrt{\dfrac{p(1-p)}{n}}} \]

其中:
\(\hat{p}\) 是样本比例
\(p\) 是假设的总体比例
\(n\) 是样本量

2.独立双样本的比例Z检验

用于检验两个独立样本的比例是否有显著差异。其公式为:

\[Z = \frac{(\hat{p}_1 - \hat{p}_2) - (p_1 - p_2)}{\sqrt{\dfrac{\hat{p}_1(1-\hat{p}_1)}{n_1} + \dfrac{\hat{p}_2(1-\hat{p}_2)}{n_2}}} \]

其中:
\(\hat{p}_1 , \hat{p}_2\)分别是两个样本的比例
\(p_1,p_2\)分别是两个总体的比例
\(n_1,n_2\)分别是两个样本的样本量

当原假设为\(H_0: p_1 = p_2\)也就是总体比例相同时,我们可以使用公式:

\[Z = \frac{\hat{p}_1 - \hat{p}_2}{\sqrt{\hat{p}(1-\hat{p})(\frac{1}{n_1} + \frac{1}{n_2})}} \]

其中\(\hat{p} = \frac{x_1 + x_2}{n_1 + n_2}\)是总体的比例

https://www.stats.gov.cn/zs/tjll/csgj/202311/t20231127_1944929.html

首先根据公式手动计算一下检验统计量z:

py 复制代码
# 样本数
n_old = len(data[data.dmp_id == 1])  # 对照组
n_new = len(data[data.dmp_id == 3])  # 策略二

# 点击数
c_old = len(data[data.dmp_id ==1][data.label == 1])
c_new = len(data[data.dmp_id ==3][data.label == 1])

# 计算点击率
r_old = c_old / n_old
r_new = c_new / n_new

# 总体点击率
r = (c_old + c_new) / (n_old + n_new)

print("总体点击率:", r)
py 复制代码
# 计算检验统计量z
z = (r_old - r_new) / np.sqrt(r * (1 - r)*(1/n_old + 1/n_new))

print("检验统计量z:", z)

计算得出检验统计量z为 -59.44168632985996

py 复制代码
# 查α=0.05对应的z分位数
from scipy.stats import norm
z_alpha = norm.ppf(0.05)
z_alpha

当α=0.05是z检验统计量为-1.64, 检验统计量z = -59.44,该检验为左侧单尾检验,拒绝域为{z<z_alpha}。

所以我们可以得出结论:原假设不成立,策略二点击率的提升在统计上是显著的

当然也可以直接根据已有的Python公式计算:

py 复制代码
import statsmodels.stats.proportion as sp
z_score, p = sp.proportions_ztest([c_old, c_new],[n_old, n_new], alternative = "smaller")
print("检验统计量z:",z_score,",p值:", p)

检验统计量z: -59.44168632985996 ,p值: 0.0

p值约等于0,p < α,与方法一结论相同,拒绝原假设。

参考文章:
https://zhuanlan.zhihu.com/p/68019926
https://www.heywhale.com/mw/project/5efee4a563975d002c98adba/content