网页点击率AB测试

目录

简介

本项目是一家电子商务网站运行 A/B 测试。分析和决定是否应该使用新的页面,保留旧的页面,或者应该将测试时间延长,之后再做出决定。

I - 概率

先导入数据。

import pandas as pd
import numpy as np
import random
import matplotlib.pyplot as plt
%matplotlib inline
#We are setting the seed to assure you get the same answers on quizzes as we set up
random.seed(42)

1. 导入 ab_data.csv 数据,并将其存储在 df 中。

a. 导入数据集,查看前几行数据:

df = pd.read_csv('ab_data.csv')
df.head()
user_idtimestampgrouplanding_pageconverted
08511042017-01-21 22:11:48.556739controlold_page0
18042282017-01-12 08:01:45.159739controlold_page0
26615902017-01-11 16:55:06.154213treatmentnew_page0
38535412017-01-08 18:28:03.143765treatmentnew_page0
48649752017-01-21 01:52:26.210827controlold_page1

b. 查看数据集的行数。

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 294478 entries, 0 to 294477
Data columns (total 5 columns):
user_id         294478 non-null int64
timestamp       294478 non-null object
group           294478 non-null object
landing_page    294478 non-null object
converted       294478 non-null int64
dtypes: int64(2), object(3)
memory usage: 11.2+ MB

c. 查看数据集中的用户数量(不同的user_id数)。

df['user_id'].nunique()
290584

d. 转化用户的占比。

df.query('converted == 1').user_id.nunique()/df['user_id'].nunique()
0.12104245244060237

e. 请计算数据中 new_pagetreatment 不匹配的次数。控制组(control) 应该对应旧页面(old_page),实验组(treatment) 对应新页面(new_page)。

df.groupby(['group', 'landing_page']).count()
user_idtimestampconverted
grouplanding_page
controlnew_page192819281928
old_page145274145274145274
treatmentnew_page145311145311145311
old_page196519651965
df[((df.group == 'treatment') == (df.landing_page == 'new_page')) == False].shape[0]
3893

f. 是否有任何行空缺数值?

df.isnull().any()
user_id         False
timestamp       False
group           False
landing_page    False
converted       False
dtype: bool

2. 对于 treatmentnew_page 不匹配的行或 controlold_page 不匹配的行,不能确定该行是否接收到了新页面还是旧页面。如何处理这些行?

a. 删除treatmentnew_page 不匹配的行或 controlold_page 不匹配的行。

#删除treatment 和 new_page 不匹配的行
df1 = df.drop(df[(df.group == 'treatment') & (df.landing_page!= 'new_page')].index)
#删除control 与 old_page 不匹配的行
df2 = df1.drop(df1[(df1.group == 'control') & (df1.landing_page != 'old_page')].index)
df2.groupby(['group', 'landing_page']).count()
user_idtimestampconverted
grouplanding_page
controlold_page145274145274145274
treatmentnew_page145311145311145311
# Double Check all of the correct rows were removed - this should be 0
df2[((df2['group'] == 'treatment') == (df2['landing_page'] == 'new_page')) == False].shape[0]
0

3. 去重

a. df2 中的用户数量(不同的 user_id) ?

df2['user_id'].nunique()
290584

b. df2 中有一个重复的 user_id 。它是什么?

df_dup = df2.user_id.duplicated()
df2[df_dup]
user_idtimestampgrouplanding_pageconverted
28937731922017-01-14 02:55:59.590927treatmentnew_page0

c. 这个重复 user_id 的行信息是什么?

df2[df2['user_id'] == 773192]
user_idtimestampgrouplanding_pageconverted
18997731922017-01-09 05:37:58.781806treatmentnew_page0
28937731922017-01-14 02:55:59.590927treatmentnew_page0

d. 删除一行重复行,但仍然存储 dataframe 为 df2

df2 = df2.drop(1899, axis = 0)
#检查是否删除
df2[df2['user_id'] == 773192]
user_idtimestampgrouplanding_pageconverted
28937731922017-01-14 02:55:59.590927treatmentnew_page0

4. 查看数据集中的转化率。

a. 用户成功转化的整体概率是多少?(不分旧页面或者新页面)

toltal_p = df2.converted.mean()
toltal_p
0.11959708724499628

b. control 组用户的转化率是多少?

df_con = df2.query('group == "control"')
con_p = df_con.converted.mean()
con_p
0.1203863045004612

c. treatment 组用户的转化率是多少?

df_tre = df2.query('group == "treatment"')
tre_p = df_tre.converted.mean()
tre_p
0.11880806551510564
obs_diff = tre_p - con_p
obs_diff
-0.0015782389853555567

d. 一个用户收到新页面的概率是多少?

new_page = df2.query('landing_page == "new_page"').user_id.nunique()/df2['user_id'].nunique()
new_page
0.5000619442226688

e. 目前否有足够的数据支持来证明旧页面或者新页面可以带来更高的转化率?

新页面与旧页面的转化率差距太小,因此并没有显著性证据证明哪一种页面可以带来更多转化。

II - A/B 测试

因为每个事件都对应有一个时间记录(time stamp 时间戳),所以技术上可以实现每次观察都连续运行假设检验。

问题的难点在于,什么时候停止试验:是在发现其中一组的试验效果足够好时立即停止?还是在这样的观察结果又持续发生了一段时间再停止?需要运行多长时间才能确认两个页面没有带来用户转化率的显著差异?

1. 根据数据做出决策:你假设旧页面效果更佳,除非在一类错误在5%以内,新页面被证明更好。

零假设: p n e w p_{new} pnew - p o l d p_{old} pold <= 0
备择假设: p n e w p_{new} pnew - p o l d p_{old} pold > 0

2. 假定在零假设中, p n e w p_{new} pnew p o l d p_{old} pold 是相等的。假设它们都等于ab_data.csv 中的 转化率(converted)

在新旧页面上执行抽样分布,并计算 转化(converted) 差异,每个页面的样本大小要与 ab_data.csv 相同。计算零假设中10000次迭代计算的估计值。

a. 在零假设中, p n e w p_{new} pnew 的 convert rate(转化率) 是多少?

p_new = df2.converted.mean()
p_new
0.11959708724499628

b. 在零假设中, p o l d p_{old} pold 的 convert rate(转化率) 是多少?

p_old = df2.converted.mean()
p_old
0.11959708724499628

c. n n e w n_{new} nnew 是多少?

n_new = df2.query('landing_page=="new_page"').shape[0]
n_new
145310

d. n o l d n_{old} nold 是多少?

n_old = df2.query('landing_page=="old_page"').shape[0]
n_old
145274

e. 在零假设中,使用 p n e w p_{new} pnew (新页面的转化率)模拟 n n e w n_{new} nnew 个新页面的转化,并将这些 n n e w n_{new} nnew 个 1 和 0 存储在 new_page_converted 中。

new_page_converted = np.random.choice(2, size = n_new, p=[1-p_new,p_new])
new_page_converted 
array([0, 0, 0, ..., 0, 0, 0])

f. 在零假设中,使用 p o l d p_{old} pold (旧页面的转化率)模拟 n o l d n_{old} nold 个旧页面的转化,并将这些 n o l d n_{old} nold 个 1 和 0 存储在 old_page_converted 中。

old_page_converted=np.random.choice(2,size=n_old,p=[1-p_old,p_old])
old_page_converted
array([0, 1, 0, ..., 0, 0, 0])

g. 根据 e 和 f,计算 p n e w p_{new} pnew p o l d p_{old} pold 的差异值( p n e w p_{new} pnew - p o l d p_{old} pold)。

diff = new_page_converted.mean() - old_page_converted.mean()
diff
-0.00028411903292373253

h. 由于单个数值不能形成分布图形,请参考以上a-g的过程,模拟 10,000 个 p n e w p_{new} pnew p o l d p_{old} pold 差异值( p n e w p_{new} pnew - p o l d p_{old} pold),将这 10,000 个值存储在 p_diffs 中。

p_diffs = []

for i in range(10000):
    p_new_diff = np.random.choice(2,size=n_new,p=[1-p_new,p_new]).mean()
    p_old_diff = np.random.choice(2,size=n_old,p=[1-p_old,p_old]).mean()
    p_diffs.append(p_new_diff - p_old_diff)

i. 绘制一个 p_diffs 分布图形。

plt.hist(p_diffs)
plt.axvline(x = obs_diff, color = 'r')

在这里插入图片描述

j. p_diffs列表的数值中,有多少比例的数值会大于 ab_data.csv 中观察到的实际转化率差异

p_diffs = np.array(p_diffs)
(p_diffs > obs_diff).mean()
0.90290000000000004

k. 用文字解释一下你刚才在 j. 中计算出来的结果。在数据研究中,这个值是什么? 根据这个数值,请判断新旧页面的转化率是否有显著差异。

p值是零假设的抽样分布下,新旧页面转化率的差值中,能够取到obs_diff的可能性,即零假设为真时,观察到统计量的概率。

p值为91%,远大于一类错误阈值5%,因此不能拒绝零假设,即新页面的转化率小于或等于旧页面。

l. 也可以使用一个内置程序 (built-in)来实现类似的结果。使用内置程序可能很容易就能取得结果,但上面的内容仍然很重要,它可以训练你具有正确的数据统计思维。

import statsmodels.api as sm
#旧页面转化人数
convert_old = df2[(df2.landing_page=='old_page') & (df2.converted == 1)].shape[0]
#新页面转化人数
convert_new = df2[(df2.landing_page=='new_page') & (df2.converted == 1)].shape[0]
n_old = df2.query('landing_page=="old_page"').shape[0]#旧页面用户数
n_new = df2.query('landing_page=="new_page"').shape[0]#新页面用户数
convert_old,convert_new,n_old ,n_new 
(17489, 17264, 145274, 145310)

m. 用 stats.proportions_ztest 来计算你的 z-score 与 p-value。

z_score, p_value = sm.stats.proportions_ztest([convert_new, convert_old], [n_new, n_old], alternative='larger')
z_score, p_value
(-1.3109241984234394, 0.90505831275902449)

n. p值为91%,大于5%,所以不能拒绝零假设,即新页面的转化率小于或等于旧页面。这个结果与j、k问题中的结果一致。

III - 回归分析法之一

1. A / B测试中获得的结果也可以通过执行回归来获取。

a. 既然每行的值是转化或不转化,还可用逻辑回归

b. 目标是使用 statsmodels 来拟合你a. 中指定的回归模型,以查看用户收到的不同页面是否存在显著的转化差异。
首先为这个截距创建一个列( 原文:column) ,并为每个用户收到的页面创建一个虚拟变量列。添加一个 截距 列,一个 ab_page 列,当用户接收 treatment 时为1, control 时为0。

#添加一个 截距 列,一个 ab_page 列
df2['intercept'] = 1
df2[['control', 'ab_page']] = pd.get_dummies(df['group'])
df2 = df2.drop('control', axis = 1)
df2.head()
user_idtimestampgrouplanding_pageconvertedinterceptab_page
08511042017-01-21 22:11:48.556739controlold_page010
18042282017-01-12 08:01:45.159739controlold_page010
26615902017-01-11 16:55:06.154213treatmentnew_page011
38535412017-01-08 18:28:03.143765treatmentnew_page011
48649752017-01-21 01:52:26.210827controlold_page110

c. 使用 statsmodels 导入回归模型。 实例化该模型,并使用你在 b. 中创建的2个列来拟合该模型,用来预测一个用户是否会发生转化。

logit_mod = sm.Logit(df2['converted'], df2[['intercept', 'ab_page']])
result = logit_mod.fit()
Optimization terminated successfully.
         Current function value: 0.366118
         Iterations 6

d. 请在下方提供你的模型摘要,并根据需要使用它来回答下面的问题。

from scipy import stats
stats.chisqprob = lambda chisq, df: stats.chi2.sf(chisq, df)
result.summary()
Logit Regression Results
Dep. Variable:converted No. Observations: 290584
Model:Logit Df Residuals: 290582
Method:MLE Df Model: 1
Date:Fri, 15 May 2020 Pseudo R-squ.: 8.077e-06
Time:14:08:58 Log-Likelihood: -1.0639e+05
converged:True LL-Null: -1.0639e+05
LLR p-value: 0.1899
coefstd errzP>|z|[0.0250.975]
intercept -1.9888 0.008 -246.669 0.000 -2.005 -1.973
ab_page -0.0150 0.011 -1.311 0.190 -0.037 0.007
1/np.exp(-0.015)
1.0151130646157189

旧页面的点击量是新页面的点击量1.0151倍。

e. 与 ab_page 关联的 p-值是多少? 为什么它与你在 II 中发现的结果不同?

提示: 与你的回归模型相关的零假设与备择假设分别是什么?它们如何与 Part II 中的零假设和备择假设做比较?

与 ab_page关联的 p-值是0.19。p值较大,表明ab_page这个因素不适合用来预测转化率。

回归模型零假设: p n e w p_{new} pnew - p o l d p_{old} pold = 0
回归模型备择假设: p n e w p_{new} pnew - p o l d p_{old} pold != 0

前后两个p值的含义不同。该回归模型的p值表示ab_page因素与转化率是否有相关性,同时也表示 p n e w p_{new} pnew = p o l d p_{old} pold的概率。
假设检验的p值表示 p n e w p_{new} pnew - p o l d p_{old} pold <= 0时,观察到统计量的概率。

f. 将其他更多因素添加到回归模型中有什么好处和弊端?

在实际应用中,影响反应变量的因素可能是多个,添加更多因素可以更好地分析和预测反应变量。
添加多个变量的弊端:1.反应变量与预测变量间未必有线性关系;2.可能有相关性误差;3.可能产生非恒定方差;4.可能破坏模型的离群值或杠杆点;5.可能产生多重共线性。这些潜在因素都会影响预测的准确性

g. 现在,除了测试不同页面的转化率是否会发生变化之外,还要根据用户居住的国家或地区添加一个 effect 项。导入 countries.csv 数据集,并将数据集合并在适当的行上。

为这些国家的列创建虚拟变量—— 为这三个虚拟变量增加两列。

country_df = pd.read_csv('countries.csv') 
country_df.head()
user_idcountry
0834778UK
1928468US
2822059UK
3711597UK
4710616UK
#连接df2与country_df
df3 = pd.merge(df2, country_df, on = 'user_id')
df3.head()
user_idtimestampgrouplanding_pageconvertedinterceptab_pagecountry
08511042017-01-21 22:11:48.556739controlold_page010US
18042282017-01-12 08:01:45.159739controlold_page010US
26615902017-01-11 16:55:06.154213treatmentnew_page011US
38535412017-01-08 18:28:03.143765treatmentnew_page011US
48649752017-01-21 01:52:26.210827controlold_page110US
#创建虚拟变量
df3[['CA', 'UK', 'US']] = pd.get_dummies(df3['country'])
df3 = df3.drop('US', axis = 1)       
df3.head(10)                                             
user_idtimestampgrouplanding_pageconvertedinterceptab_pagecountryCAUK
08511042017-01-21 22:11:48.556739controlold_page010US00
18042282017-01-12 08:01:45.159739controlold_page010US00
26615902017-01-11 16:55:06.154213treatmentnew_page011US00
38535412017-01-08 18:28:03.143765treatmentnew_page011US00
48649752017-01-21 01:52:26.210827controlold_page110US00
59369232017-01-10 15:20:49.083499controlold_page010US00
66796872017-01-19 03:26:46.940749treatmentnew_page111CA10
77190142017-01-17 01:48:29.539573controlold_page010US00
88173552017-01-04 17:58:08.979471treatmentnew_page111UK01
98397852017-01-15 18:11:06.610965treatmentnew_page111CA10
#拟合模型
logit_mod1=sm.Logit(df3.converted,df3[['intercept','ab_page','CA','UK']])
result1=logit_mod1.fit()
result1.summary()
Optimization terminated successfully.
         Current function value: 0.366113
         Iterations 6
Logit Regression Results
Dep. Variable:converted No. Observations: 290584
Model:Logit Df Residuals: 290580
Method:MLE Df Model: 3
Date:Fri, 15 May 2020 Pseudo R-squ.: 2.323e-05
Time:14:55:38 Log-Likelihood: -1.0639e+05
converged:True LL-Null: -1.0639e+05
LLR p-value: 0.1760
coefstd errzP>|z|[0.0250.975]
intercept -1.9893 0.009 -223.763 0.000 -2.007 -1.972
ab_page -0.0149 0.011 -1.307 0.191 -0.037 0.007
CA -0.0408 0.027 -1.516 0.130 -0.093 0.012
UK 0.0099 0.013 0.743 0.457 -0.016 0.036
1/np.exp(-0.0408),np.exp(0.0099)
(1.0416437559600236, 1.0099491671175422)

从p值判断,国家项不具有统计显著性,对转化率影响不大。

h. 虽然已经查看了国家与页面在转化率上的个体性因素,但还要查看页面与国家/地区之间的相互作用,测试其是否会对转化产生重大影响。创建必要的附加列,并拟合一个新的模型。

提示:页面与国家/地区的相互作用

df3['new_CA'] = df3['new_page'] * df3['CA']
df3['new_UK'] = df3['new_page'] * df3['UK']
#添加交叉项
df3['new_page'] = df3['ab_page']
df3['new_CA'] = df3['new_page'] * df3['CA']
df3['new_UK'] = df3['new_page'] * df3['UK']
df3.head()
user_idtimestampgrouplanding_pageconvertedinterceptab_pagecountryCAUKnew_pagenew_CAnew_UK
08511042017-01-21 22:11:48.556739controlold_page010US00000
18042282017-01-12 08:01:45.159739controlold_page010US00000
26615902017-01-11 16:55:06.154213treatmentnew_page011US00100
38535412017-01-08 18:28:03.143765treatmentnew_page011US00100
48649752017-01-21 01:52:26.210827controlold_page110US00000
#拟合模型
logit_mod2=sm.Logit(df3.converted,df3[['intercept','ab_page','CA','UK', 'new_CA', 'new_UK']])
result2=logit_mod2.fit()
result2.summary()
Optimization terminated successfully.
         Current function value: 0.366109
         Iterations 6
Logit Regression Results
Dep. Variable:converted No. Observations: 290584
Model:Logit Df Residuals: 290578
Method:MLE Df Model: 5
Date:Fri, 15 May 2020 Pseudo R-squ.: 3.482e-05
Time:15:05:30 Log-Likelihood: -1.0639e+05
converged:True LL-Null: -1.0639e+05
LLR p-value: 0.1920
coefstd errzP>|z|[0.0250.975]
intercept -1.9865 0.010 -206.344 0.000 -2.005 -1.968
ab_page -0.0206 0.014 -1.505 0.132 -0.047 0.006
CA -0.0175 0.038 -0.465 0.642 -0.091 0.056
UK -0.0057 0.019 -0.306 0.760 -0.043 0.031
new_CA -0.0469 0.054 -0.872 0.383 -0.152 0.059
new_UK 0.0314 0.027 1.181 0.238 -0.021 0.084
1/np.exp(-0.0057),np.exp(0.0314)
(1.0057162759095335, 1.0318981806179213)

通过比较包括 US 地区在内的p值,远远大于0.05,所以这种影响均没有显著性,即页面与国家/地区之间的相互作用,不会对转化产生重大影响

总结

通过A/B测试,新页面的转化率并不高于旧页面。

使用逻辑回归分析,新页面的转化率同样没有显著性变化。

进一步分析国家项对转化的影响,国家项不具有统计显著性,对转化率影响不大。

根据“页面”和“国家/地区”的相互作用建立回归模型,页面与国家/地区之间的相互作用,不会对转化产生重大影响。

因此综合来看,此“新页面”对转化率影响不大,甚至低于旧页面的转化率,需继续对新页面进行优化改进。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值