漏斗分析 - AARRR模型案例分析

   漏斗分析是一套流程式的数据分析方法,能够科学地反映各阶段用户转化情况。漏斗分析模型已经广泛应用于用户行为分析类产品,且功能十分强大:它可以评估总体或各个环节的转化情况、促销活动效果;也可以与其他数据分析模型结合进行深度用户行为分析,从而找到用户流失的原因,以提升用户量、活跃度、留存率。


   漏斗分析最常用的两个互补型指标是转化率和流失率。例如如有100人访问某电商网站,有27人支付成功。这个过程共有5步,第一步到第二步的转化率为88%,流失率为12%,第二步到第三步转化率为32%,流失率68%……以此类推。整个过程的转化率为27%,流失率为73%。该模型就是经典的漏斗分析模型。每一层漏斗,就是一个漏斗事件。其中,最核心的指标就是转化率。


漏斗的三个要素:


时间:特指漏斗的转化周期,即为完成每一层漏斗所需时间的集合。
节点:每一层漏斗,就是一个节点。
流量:就是人群(人数)。


对于时间来说:通常来讲,一个漏斗的转化周期越短越好。


对于节点来说:最核心的指标就是转化率,计算公式为:转化率 = 本层事件转化人数/上层事件转化人数


对于流量来说:不同特定人群在同一个漏斗下的表现情况一定是不一样的,例如同一类的高端电子产品漏斗里,年轻人和老人的转化率肯定不一样的。


   AARRR模型是漏斗分析的其中一种,可以指导我们主要检测和分析哪些指标,是生命周期中的 5 个重要环节的缩写,包括:用户获取(Acquisition)、用户激活(Activation)、用户留存(Retention)、收入(Revenue)、自传播(Refer)



在这里插入图片描述



   以在线电子书为例,新用户从打开 APP 到购买,总共会经过这样一条包括以下四个主要环节的路径:


1.打开 APP 进入首页
2.进入书籍页面
3.开始试读
4.购书


   每一个环节都只会有部分用户会走到下一个环节,走到的我们称为转化,没有走到的我们称为流失,这一系列环节就像一层层漏斗一样。对应的,我们将一层一层分析转化的方法称为漏斗(Funnel)分析法。通过漏斗分析法,我们就可以发现究竟在哪几层转化特别低值得优先改善。


   从电子书平台后台抽取了用户数据,把数据存放在对应的变量名之中,具体如下:



在这里插入图片描述



   首先把前10个最活跃用户ID找出来:



在这里插入图片描述



import numpy as np

active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
print(active_uids[:10])


   获取4种 ID 类型的数量:



在这里插入图片描述



import numpy as np

active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')
trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

num_active_uids = len(active_uids)
num_enterbook_uids = len(enterbook_uids)
num_trial_uids = len(trial_uids)
num_paid_uids = len(paid_uids)

print("活跃用户数:%d" % num_active_uids)
print("打开书籍页面用户数:%d" % num_enterbook_uids)
print("试读用户数:%d" % num_trial_uids)
print("购书用户数:%d" % num_paid_uids)


   根据获取的 ID数,可以绘制一个直观的柱形图:



在这里插入图片描述



import numpy as np
import matplotlib.pyplot as plt

active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')
trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

num_active_uids = len(active_uids)
num_enterbook_uids = len(enterbook_uids)
num_trial_uids = len(trial_uids)
num_paid_uids = len(paid_uids)

x = ['Active','Enter Book','Trial','Paid']
data = [num_active_uids,num_enterbook_uids,num_trial_uids,num_paid_uids]
plt.bar(x,data)
plt.show()


   在图中可以明显看到,从试读到购买的转化率不高。其实存在两条不同的购买转化路径,我们需要分别分析。


   首先,我们分析那些进入书籍页,没有试读而直接购买的用户。这时候我们不能简单的看数字,而是要根据原始的用户 ID 来进行操作。经过试读再购买的用户 ID,一定同时属于试读用户的 ID,也属于购买用户的 ID,也就是 trial_uids 和 paid_uids 这两个列表间重合的部分 ID,就是经过试读再购买的用户 ID 了。


   如何可以快速找到两个列表重合的部分呢? Python 有一个集合的方法可以快速去重。可以使用 intersection() 方法,执行 s.intersection(t) 。因为 s 和 t 的交集与 t 和 s 的交集是完全一致的,顺序并不重要。因此 t.intersection(s) 的效果也一样。最简单的写法是 s & t 或 t & s。



在这里插入图片描述



import numpy as np
# import matplotlib.pyplot as plt
# active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
# enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')

trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

trial_uids_set = set(trial_uids)
paid_uids_set = set(paid_uids)
paid_with_trial_uids = trial_uids_set & paid_uids_set
num_paid_with_trial_uids = len(paid_with_trial_uids)


print("有%d位用户先试读后再购书" % num_paid_with_trial_uids)


   通过输出结果,得知有22位用户先试读后再购书。而没有试读就直接购买的用户 ID,一定存在于 paid_uids 中,且一定不存在于 trial_uids。只要对集合求差集,就可以得出结果。



在这里插入图片描述



import numpy as np
#import matplotlib.pyplot as plt

# active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
# enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')

trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

trial_uids_set = set(trial_uids)
paid_uids_set = set(paid_uids)
paid_with_trial_uids = trial_uids_set & paid_uids_set

paid_without_trial_uids = paid_uids_set - paid_with_trial_uids
num_paid_without_trial_uids = len(paid_without_trial_uids)

print("有%d位用户没有试读就购书" % num_paid_without_trial_uids)


   通过输出结果,得知有114位用户没有试读就购书。


   我们就按照两个不同的路径,分别绘出两个漏斗,因为我们主要注意力放在用户进入书籍页后,所以可以暂时不管活跃用户那一层。



漏斗一:用户经过 进入书籍页面-试读书籍-试读后购买 三步。



在这里插入图片描述



import numpy as np
import matplotlib.pyplot as plt

active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')
trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

num_active_uids = len(active_uids)
num_enterbook_uids = len(enterbook_uids)
num_trial_uids = len(trial_uids)
num_paid_uids = len(paid_uids)

trial_uids_set = set(trial_uids)
paid_uids_set = set(paid_uids)
paid_with_trial_uids = trial_uids_set & paid_uids_set

paid_without_trial_uids = paid_uids_set - paid_with_trial_uids
num_paid_without_trial_uids = len(paid_without_trial_uids)
num_paid_with_trial_uids = len(paid_with_trial_uids)

x = ['Enter Book', 'Trial', 'Trial Then Paid']
nums = [num_enterbook_uids, num_trial_uids, num_paid_with_trial_uids]
plt.bar(x, nums)
plt.show()


漏斗二:用户经过 进入书籍页面-直接购买 两步。



在这里插入图片描述



import numpy as np
import matplotlib.pyplot as plt

active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')
trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

num_active_uids = len(active_uids)
num_enterbook_uids = len(enterbook_uids)
num_trial_uids = len(trial_uids)
num_paid_uids = len(paid_uids)

trial_uids_set = set(trial_uids)
paid_uids_set = set(paid_uids)
paid_with_trial_uids = trial_uids_set & paid_uids_set

paid_without_trial_uids = paid_uids_set - paid_with_trial_uids
num_paid_without_trial_uids = len(paid_without_trial_uids)
num_paid_with_trial_uids = len(paid_with_trial_uids)

x = ['Enter Book', 'Paid Without Trial']
nums = [num_enterbook_uids, num_paid_without_trial_uids]
plt.bar(x, nums)
plt.show()


   直接把这两个漏斗图画在一起 :



在这里插入图片描述



import numpy as np
import matplotlib.pyplot as plt

active_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\active_uids.csv')
enterbook_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\enterbook_uids.csv')
trial_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\trial_uids.csv')
paid_uids = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\paid_uids.csv')

num_active_uids = len(active_uids)
num_enterbook_uids = len(enterbook_uids)
num_trial_uids = len(trial_uids)
num_paid_uids = len(paid_uids)

trial_uids_set = set(trial_uids)
paid_uids_set = set(paid_uids)
paid_with_trial_uids = trial_uids_set & paid_uids_set

paid_without_trial_uids = paid_uids_set - paid_with_trial_uids
num_paid_without_trial_uids = len(paid_without_trial_uids)
num_paid_with_trial_uids = len(paid_with_trial_uids)

x = ['Enter Book', 'Trial Or Pay', 'Trial Then Pay']
nums_enter_book = [num_enterbook_uids, 0, 0]
plt.bar(x, nums_enter_book)

nums_trial = [0, num_trial_uids, num_paid_with_trial_uids]
plt.bar(x, nums_trial, label='Trial')

nums_without_trial = [0, num_paid_without_trial_uids, 0]
plt.bar(x, nums_without_trial, label='Pay Without Trial')

plt.legend()
plt.show()


   从图可见,在漏斗的第二层,也就是对应用户进入书籍页的第二步,绝大部分(973)用户选择了试读,少部分(114)用户选择了直接购买;但是试读用户后续只有 22 位购书,也就是说,经过试读的用户再购书的数量和转换,远远小于那些一进书籍页直接买书的用户。于是,我们就产生一个大胆的想法——试读究竟有没有用?如果取消会怎样,是否会增加?如果我们决定先取消试读功能,然后观察和比较购买转化率,这个结果很可能不客观。因为外部环境是随时间不断发生变化的,如果在不同的日期做实验,即便结果上有差别,那么我们很难解释这个差别是因为我们在 APP 上的更改导致,还是因为日期本身导致,因为不同的日期(例如周末、节假日、双十一)对用户消费行为是会产生影响的。


   我们可以引入A/B 测试,就是如果一个产品有多个版本想要进行比较和取舍,就在同一段时间内,将目标人群随机的分成相等数量的多组,每组使用不同版本的产品,然后比较结果。



在这里插入图片描述



在这里插入图片描述



   经过 AB测试后, 从电子书后台获取 A、B 两组的实验数据,并定义2组 的变量名。



在这里插入图片描述



在这里插入图片描述



在这里插入图片描述



import numpy as np

active_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\active_uids_A.csv')
enterbook_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\enterbook_uids_A.csv')
trial_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\trial_uids_A.csv')
paid_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\paid_uids_A.csv')

active_uids_B = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\active_uids_B.csv')
enterbook_uids_B = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\enterbook_uids_B.csv')
paid_uids_B = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\paid_uids_B.csv')

num_active_uids_A = len(active_uids_A)
num_enterbook_uids_A = len(enterbook_uids_A)
num_trial_uids_A = len(trial_uids_A)
num_paid_uids_A = len(paid_uids_A)

num_active_uids_B = len(active_uids_A)
num_enterbook_uids_B = len(enterbook_uids_A)
num_paid_uids_B = len(paid_uids_A)

print("A组数据")
print("-----------")
print("活跃用户数:%d" % num_active_uids_A)
print("打开书籍页面用户数:%d" % num_enterbook_uids_A)
print("试读用户数:%d" % num_trial_uids_A)
print("购书用户数:%d" % num_paid_uids_A)
print("    ")
print("B组数据")
print("-----------")
print("活跃用户数:%d" % num_active_uids_B)
print("打开书籍页面用户数:%d" % num_enterbook_uids_B)
print("购书用户数:%d" % num_paid_uids_B)


   得出以上A、B 两组关键数据后, 再次用柱状图来比较两组的购买转换漏斗:



在这里插入图片描述



import numpy as np
import matplotlib.pyplot as plt

active_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\active_uids_A.csv')
enterbook_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\enterbook_uids_A.csv')
trial_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\trial_uids_A.csv')
paid_uids_A = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\paid_uids_A.csv')

active_uids_B = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\active_uids_B.csv')
enterbook_uids_B = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\enterbook_uids_B.csv')
paid_uids_B = np.genfromtxt(r'C:\Users\Administrator\Desktop\funnel_analyst\AB\paid_uids_B.csv')

num_active_uids_A = len(active_uids_A)
num_enterbook_uids_A = len(enterbook_uids_A)
num_trial_uids_A = len(trial_uids_A)
num_paid_uids_A = len(paid_uids_A)

num_active_uids_B = len(active_uids_B)
num_enterbook_uids_B = len(enterbook_uids_B)
num_trial_uids_B = 0
num_paid_uids_B = len(paid_uids_B)

labels = ['Enter Book', 'Trial', 'Pay']
data_A = [num_enterbook_uids_A, num_trial_uids_A, num_paid_uids_A]
data_B = [num_enterbook_uids_B, num_trial_uids_B, num_paid_uids_B]

x = np.arange(len(labels))
width = 0.35
plt.bar(x - width/2, data_A, width, label='A')
plt.bar(x + width/2, data_B, width, label='B')

plt.xticks(x, labels)
plt.legend()
plt.show()


   我们可以发现在进入书籍页这一层,A、B 两组的数据是差不多的,因为我们的测试是针对书籍页面内部的试读按钮,并不会影响用户从书籍首页进入书籍页的判断,因为此时他们就看不到书籍页面长什么样。同时也可以看到 B 组支付的数据是明显高于 A 组的。我们是不是可以下结论,取消了试读后,销量会更好呢?经过把这个 AB 测试持续了一周,发现每天的结果都和第一天一样,也证明这测试的有效性。


   虽然数据验证了取消试读后用户反而更愿意购买,但是这背后的原因是什么呢?明明其它在线阅读软件、平台都有试读功能,难道他们都错了吗?因此要更深入了解原因,就必须分析试读的这部分用户的行为和数据。


用户开始试读后,第一次进入书籍阅读页面后,有以下三种可能的行为:

读书
下一页
退出阅读


   那我们就研究一下用户是怎样进行行为选择的。下一页、退出阅读都是对应具体的按钮,程序可以检测用户有没有点击这两个按钮,但是用户有没有读书,我们怎么知道呢?虽然我们不能直接知道用户有没有在读书,但是可以知道用户花了多少时间停留在这个阅读界面上啊,除去极少数例外,用户停留的时间越长,越有可能在读书。 于是,我们通过调用过去一周 这电子书的试读数据去深入分析:



在这里插入图片描述



import pandas as pd

prince_trial = r'C:\Users\Administrator\Desktop\funnel_analyst\AB\ice_trial.csv'
df = pd.read_csv(prince_trial)
print(df.head())

我们得到以上前5的数据,各自


user_id:用户 ID
time_stary: 停留时间(s)
next_page:是否点击下一页
quit_trial:退出阅读
finish_trial:完成试读
pay:购买


   以第一行为例,表示 ID 为 125777 的用户试读了,在第一页停留了 26 秒,点击了下一页,没有选择退出阅读,没有完成试读,最终没有购买。


   分析用户的停留时间分布:



在这里插入图片描述



import pandas as pd
import matplotlib.pyplot as plt

prince_trial = r'C:\Users\Administrator\Desktop\funnel_analyst\AB\ice_trial.csv'
df = pd.read_csv(prince_trial)

plt.hist(df['time_stay'], bins=10, facecolor="blue", edgecolor="black", alpha=0.7)
plt.xlabel("Time Staying")
plt.ylabel("Number of Users")
plt.show()


   可以发现,绝大部分试读用户在第一页的停留时间,不超过 30 秒,如果不超过 30 秒,很显然是读不完一页内容的,他们点击下一页的可能性应该也不大。为了验证这个猜想,我们将用户分成两组,一组阅读时间在 30 秒及以下,另一组在 30 秒以上,分别观察点击下一页的比例是多少?



在这里插入图片描述



import pandas as pd
import matplotlib.pyplot as plt
prince_trial = r'C:\Users\Administrator\Desktop\funnel_analyst\AB\ice_trial.csv'

df = pd.read_csv(prince_trial)

# 从所有数据中查找 time_stay 字段的值小于等于 30 的数据记录
under_30 = df[df['time_stay'] <= 30]

# 从所有数据中查找 time_stay 字段的值大 30 的数据记录
above_30 = df[df['time_stay'] > 30]

# 记录两组人数
num_under_30 = len(under_30)
num_above_30 = len(above_30)

under_30_and_next_page = under_30[under_30['next_page']]
above_30_and_next_page = above_30[above_30['next_page']]

num_under_30_and_next_page = len(under_30_and_next_page)
num_above_30_and_next_page = len(above_30_and_next_page)

ratio_under_30_and_next_page = num_under_30_and_next_page / num_under_30
ratio_above_30_and_next_page = num_above_30_and_next_page / num_above_30

print("阅读时间在30秒及以下,总人数为%d,点击下一页的人数为%d,比例为%.0f%%" %
  (num_under_30, num_under_30_and_next_page, 100 * ratio_under_30_and_next_page))
print("阅读时间在30秒以上,总人数为%d,点击下一页的人数为%d,比例为%.0f%%" %
  (num_above_30, num_above_30_and_next_page, 100 * ratio_above_30_and_next_page))


这样我们就可以得出以下的比例结果:


阅读时间在30秒及以下,总人数为1134,点击下一页的人数为9,比例为1%
阅读时间在30秒以上,总人数为188,点击下一页的人数为64,比例为34%


   我们已经发现了阅读时间和用户是否点下一页,甚至和购买之间的相关关系,那么,我们是不是可以说,只要想办法让用户阅读时间变长,就能最终增加购买呢?相关性不代表因果性。例如,一家超市发现雪糕和空调的销售量之间存在相关关系,并不代表超市想办法增加雪糕的销量,就能相应增加空调销量。因为夏天到了天气炎热才是这两者销量同时上升的原因。


  在产品里,很可能有一个因素,会同时导致用户阅读时间短,以及不愿意购买,是什么因素呢?这时候,我们又想到,用户看不懂一本中文书的主要原因是因为内容太复杂,而看不懂英文书则很可能是因为英语能力不够。所以说,那么多放弃的用户,是不是因为虽然想读英文版的,但是真的去读了,发现自己的英语能力不够所以直接放弃了呢?要验证这点,我们要么能够找到足够多的用户去做问卷调查和访谈,要么也可以在产品里直接询问用户。于是我们在用户点返回的环节上,做了一个弹窗,询问用户为什么放弃,是对内容本身不感兴趣,还是觉得太难,还是两者都有,或者都不是。


   通过搜集几天的数据,得到如下反馈数据:


不感兴趣 : 152


看不懂英文 : 888


两者都是 : 122


其他原因: 130


   通过绘制一个饼图来直观的显示反馈数据:



在这里插入图片描述



import matplotlib.pyplot as plt

labels = ['Not Interested', 'Don\'t Understand', 'Both', 'Neither']
data = [152, 888, 122, 130]

colors = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue']
explode = (0, 0.1, 0, 0)
plt.pie(data, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=140)
plt.show()


   现在我们可以确认了,之前 AB 测试中,A 组中选择了试读的大部分用户,的确是因为在试读阶段发现看不懂就草草放弃了;而 B 组的用户因为没有试读机会,很多本来看不懂的用户并不知道自己看不懂,于是先买了再说。而中文书阅读 APP 为什么可以大大方方的提供试读功能,是因为试读后因为看不懂就放弃购买的可能性不大。所以,我们完整的经历了一个发现问题、提出假设、试验分析、提出方案的过程。在这个过程中,数据分析发挥了不可或缺但是并非唯一的作用,因为发现问题和提出假设需要洞察力,提出方案需要创造力,这些能力并非仅仅看数字就能获得。因此,数据分析只是帮助我们发现问题的手段,我们可以将数据作为分析的起点,但是切勿作为分析的终点,一定要深入了解用户,在原理上弄明白他们的使用场景和遇到的困境,才能够持续迭代产品,也让自己不停地进步。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值