本次项目主要围绕一家电商网站新旧页面的用户体验数据展开数据分析。
环境
win10,python 3,jupyter notebook
目录
正文
一、项目背景
1.项目概述
本项目分析的数据集来源于一家电商网站,希望通过对新旧页面A/B测试的数据进行显著性检验分析,判断新旧两版页面在用户转化率上是否有显著区别,帮助公司决定是否应当采用新的页面,或是保留旧页面。
2.A/B测试解读
A/B 测试是为Web或App界面或流程制作两个(A/B)或多个(A/B/n)版本,在同一时间维度,分别让组成成分相同(相似)的访客群组(目标人群)随机地使用一个方案,收集各群组的用户体验数据和业务数据,最后根据显著性检验分析、评估出最好版本予以正式采用。
本项目将新旧版本以随机的方式同时推送给测试用户,随后可以把用户分成两组,对照组和实验组,对照组(control)体验旧页面,实验组(treatment)体验新页面,接下来再分别统计两组用户的总用户数、转化数指标等数据,根据这些样本数据进行假设检验分析。
二、数据分析
1.数据概览
import pandas as pd #结构化数据分析工具包
import numpy as np #科学计算基础软件包
import matplotlib.pyplot as plt #图表绘制工具包
import seaborn as sns #基于 matplotlib, 导入 seaborn 会修改默认的 matplotlib 配色方案和绘图样式,提高图表的可读性和美观性
%matplotlib inline # 在 jupyter notebook 里面显示图表
ABtest.head() #查看前五行数据
ABtest.tail()
通过以上数据以及题目资料, 可以了解到数据集总共有294478行, 有以下字段:
user_ id——用户ID,具有唯一标识的作用,即一个人员对应一个id
timestamp——用户行为时间戳,记录实验时的日期和时间
group——分组标签: treatment= 实验组,control= 对照组
landing_ page——展示的页面版本,分为old_page和new_page converted——是否转化(0代表没有转化,1代表已经转化)
ABtest.info()
数据维度:294478 行 X 5 列
缺失字段: 无
数据类型: 2个64位整型, 3个python对象
ABtest.describe() #描述性统计
除了python对象以外的两列数据类型, 均参与了计算:
12.17%的人转化, 转化率不是很高
#其他列的描述性统计
ABtest[['timestamp','group','landing_page']].describe()
timestamp共有891种, 总数也891个, timestamp是唯一的
group 只有2种,对照组和实验组,unique=2 说明group列没有出现别的组名;treatment组的人更多,一共有147276个
landing_ page 列也没有出现除了old_page和new_page之外别的页面名字;但是old_page的人更多,old_page对应的是control组,说明某些记录可能出错
2.数据清洗
2.1 缺失值查看及处理
ABtest.isnull().sum()
本数据集完整程度较好,每一列都没有缺失值
2.2 检查逻辑错误并处理
之前查看到treatment组和old_page组的人更多,我们看一下是否有分组group和展示页面版本landing_page不符情况
old_error = len(ABtest[(ABtest['group'] == 'treatment') & (ABtest['landing_page'] == 'old_page')])
new_error = len(ABtest[(ABtest['group'] == 'control') & (ABtest['landing_page'] == 'new_page')])
print(
'实验组看到旧页面的人数:{}, 对照组看到新页面的人数:{}'.format(
old_error,
new_error))
实验组看到旧页面的人数:1965, 对照组看到新页面的人数:1928
把这些错误对应的数据删除
ABtest = ABtest[((ABtest['group'] == 'treatment') & (ABtest['landing_page'] == 'new_page'))
| ((ABtest['group'] == 'control') & (ABtest['landing_page'] == 'old_page'))]
再验证一下是否还有对应错误的数据
old_error = len(ABtest[(ABtest['group'] == 'treatment') & (ABtest['landing_page'] == 'old_page')])
new_error = len(ABtest[(ABtest['group'] == 'control') & (ABtest['landing_page'] == 'new_page')])
print(
'实验组看到旧页面的人数:{}, 对照组看到新页面的人数:{}'.format(
old_error,
new_error))
实验组看到旧页面的人数:0, 对照组看到新页面的人数:0
逻辑错误处理完毕
2.3 去除重复值
ABtest.drop_duplicates(inplace=True,keep="first") #仅保留第一条
ABtest.reset_index()
ABtest.info()
最后只剩下290585行数据
再看一下两组的用户占比
percent1=len(ABtest[ABtest.landing_page=="old_page"])/len(ABtest)
percent2=len(ABtest[ABtest.landing_page=="new_page"])/len(ABtest)
print('看到旧页面的用户占比:','%.2f%%'%(percent1*100))
print('看到新页面的用户占比:','%.2f%%'%(percent2*100))
看到旧页面的用户占比: 49.99%
看到新页面的用户占比: 50.01%
两组用户各占50%左右,流量分配相对均衡
三、假设检验
1.提出假设
在本项目中验证的是实验组和控制组的转化率哪一个更大,那么可以提出假设:
虚无假设 H0: p_old ≥ p_new
备择假设 H1: p_old < p_new
2.为下结论设立标准
本项目为一个显著水平为0.05的单侧检验
(1)拒绝域由绝对值大于1.64的z分数决定;
(2)若p值大于0.05,无法拒绝虚无假设,新页面转化率小于或等于旧页面转化率;p值小于0.05则拒绝虚无假设,新页面转化率大于旧页面转化率。
3.选择数据,计算样本统计量
先计算一下样本中的转化率
convert_old = ABtest.query('landing_page=="old_page"').query('converted==1').shape[0]
convert_new = ABtest.query('landing_page=="new_page"').query('converted==1').shape[0]
n_old = ABtest.query('landing_page=="old_page"').shape[0]
n_new = ABtest.query('landing_page=="new_page"').shape[0]
p_old = convert_old / n_old
p_new = convert_new / n_new
print('旧页面的转化率是',p_old)
print('新页面的转化率是',p_new)
旧页面的转化率是 0.1203863045004612
新页面的转化率是 0.12299137711529065
import statsmodels.api as sm
from scipy.stats import norm
z_score, p_value = sm.stats.proportions_ztest([convert_old, convert_new], [n_old, n_new],alternative='smaller')
print('z分数是:{} p值是{}'.format(z_score,p_value))
print('显著性水平为0.05对应的z分数是',norm.ppf(0.05))
z分数是:-2.147714741889884 p值是0.015868211766816118
显著性水平为0.05对应的z分数是 -1.6448536269514729
4.得出结论
本例中的z分数绝对值(2.15)大于显著性水平为0.05对应的z分数绝对值(1.64),并且p值(0.016)小于0.05,所以拒绝虚无假设,新页面转化率大于旧页面转化率,公司应该选择新页面。