对网页点击率分析A/B测试结果
项目概述
数据分析师和数据学家经常使用 A/B 测试。如何分析A/B测试结果非常重要。
在这个项目中,设定了一个电子商务网站运营 A/B 测试的情境。该公司设计了新网站页面,想提高用户转化率,即购买公司产品的用户数量。我的目标是通过分析来帮助公司决定他们是否应该使用新页面,还是保留原有网页或延长测试时间来进一步观测。
该项目中,共有5个测试,可以综合来评价电子商务网站的页面变更情况。
数据集
是一个名为“ab_data.csv”的数据集,里面包含“用户ID”、“时间戳”、“组别”(实验组、对照组)、“访问页面的类型”、“转化情况”(0-否,1-是)。
项目重点
通过概率、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_id | timestamp | group | landing_page | converted | |
---|---|---|---|---|---|
0 | 851104 | 2017-01-21 22:11:48.556739 | control | old_page | 0 |
1 | 804228 | 2017-01-12 08:01:45.159739 | control | old_page | 0 |
2 | 661590 | 2017-01-11 16:55:06.154213 | treatment | new_page | 0 |
3 | 853541 | 2017-01-08 18:28:03.143765 | treatment | new_page | 0 |
4 | 864975 | 2017-01-21 01:52:26.210827 | control | old_page | 1 |
b. 使用下面的单元格来查找数据集中的行数。
lines_number = df.shape[0]
lines_number
294478
c. 数据集中独立用户的数量。
df.user_id.nunique()
290584
d. 用户转化的比例。
df.converted.mean()
0.11965919355605512
e. new_page
与 treatment
不一致的次数。
#new_page 与 treatment 不一致的次数
first_diff = df[(df['group'] == 'treatment') & (df['landing_page'] == 'old_page')].shape[0]
#old_page 与 control 不一致的次数
second_diff = df[(df['group'] == 'control') & (df['landing_page'] == 'new_page')].shape[0]
first_diff + second_diff
3893
df[((df['group'] == 'treatment') == (df['landing_page'] == 'new_page')) == False].shape[0]
3893
f. 是否有任何行存在缺失值?
df.isnull().sum()
user_id 0
timestamp 0
group 0
landing_page 0
converted 0
dtype: int64
2.
对于 treatment 不与 new_page 一致的行或 control 不与 old_page 一致的行,我们不能确定该行是否真正接收到了新的或旧的页面。
a. 现在,使用测试题的答案创建一个符合测试规格要求的新数据集。将新 dataframe 存储在 df2 中。
#得到不一致的行的索引
index_diff = df[((df['group'] == 'treatment') == (df['landing_page'] == 'new_page')) == False].index
#根据索引删除不一致的行
df2 = df.drop(index=(index_diff)).reset_index()
# 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.
使用 df2 与下面的单元格来回答课堂中的 测试3 。
a. df2 中有多少唯一的 user_id?
df2.user_id.nunique()
290584
b. df2 中有一个重复的 user_id 。它是什么?
df_dup = df2.user_id.duplicated()
df2[df_dup].user_id
2862 773192
Name: user_id, dtype: int64
c. 这个重复的 user_id 的行信息是什么?
df2[df_dup]
index | user_id | timestamp | group | landing_page | converted | |
---|---|---|---|---|---|---|
2862 | 2893 | 773192 | 2017-01-14 02:55:59.590927 | treatment | new_page | 0 |
d. 删除 一个 含有重复的 user_id 的行, 但需要确保你的 dataframe 为 df2。
df2 = df2.drop(index=df2[df_dup].index).copy()
df2.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 290584 entries, 0 to 290584
Data columns (total 6 columns):
index 290584 non-null int64
user_id 290584 non-null int64
timestamp 290584 non-null object
group 290584 non-null object
landing_page 290584 non-null object
converted 290584 non-null int64
dtypes: int64(3), object(3)
memory usage: 15.5+ MB
4.
在下面的单元格中,使用 df2 来回答与课堂中的 测试 4 相关的测试题目。
a. 不管它们收到什么页面,单个用户的转化率是多少?
converted_total = df2.converted.mean()
converted_total
0.11959708724499628
b. 假定一个用户处于 control
组中,他的转化率是多少?
converted_control = df2[df2['group'] == 'control'].converted.mean()
converted_control
0.1203863045004612
c. 假定一个用户处于 treatment
组中,他的转化率是多少?
converted_treatment = df2[df2['group'] == 'treatment'].converted.mean()
converted_treatment
0.11880806551510564
d. 一个用户收到新页面的概率是多少?
get_new = (df2['landing_page'] == 'new_page').mean()
get_new
0.5000619442226688
e. 使用这个问题的前两部分的结果,给出你的建议:你是否认为有证据表明一个页面可以带来更多的转化?在下面写出你的答案。
在用户收到新旧页面概率几乎相等的情况下,实际转化率相差不大(对照组转化率稍高于实验组),但目前并没有显著性证据证明哪一种页面可以带来更多转化。
II - A/B 测试
请注意,由于与每个事件相关的时间戳,你可以在进行每次观察时连续运行假设检验。
然而,问题的难点在于,一个页面被认为比另一页页面的效果好得多的时候你就要停止检验吗?还是需要在一定时间内持续发生?你需要将检验运行多长时间来决定哪个页面比另一个页面更好?
一般情况下,这些问题是A / B测试中最难的部分。如果你对下面提到的一些知识点比较生疏,请先回顾课程中的“描述统计学”部分的内容。
1.
现在,要考虑的是,需要根据提供的所有数据做出决定。如果假定旧的页面效果更好,除非新的页面在类型I错误率为5%的情况下才能证明效果更好,那么,你的零假设和备择假设是什么? 你可以根据单词或旧页面与新页面的转化率 p o l d p_{old} p