用户行为分析
文章目录
这篇文章尝试着对由阿里提供的user_behavior_data_on_taobao_app公开数据集进行分析,期望通过此次分析能通推动产品迭代、实现精准营销,提供定制服务,驱动产品决策等,需要此数据的小朋友们可以前往天池下载,我也会将文中使用到的数据和源代码放在Github上以便下载: 点此访问Github
想要进行精细化运营,围绕的中心永远是用户。用户研究的常用方法有:情境调查、用户访谈、问卷调查、A/B测试、可用性测试与用户行为分析。其中用户行为分析是用户研究的最有效方法之一。
1、什么是用户行为分析
1.1 了解用户行为分析
用户行为分析是对用户在产品上的产生的行为及行为背后的数据进行分析,通过构建用户行为模型和用户画像,来改变产品决策,实现精细化运营,指导业务增长。
在产品运营过程中,对用户行为的数据进行收集、存储、跟踪、分析与应用等,可以找到实现用户自增长的病毒因素、群体特征与目标用户。从而深度还原用户使用场景、操作规律、访问路径及行为特点等。
1.2 用户行为分析的目的
对于互联网金融、新零售、供应链、在线教育、银行、证券等行业的产品而言,以数据为驱动的用户行为分析尤为重要。用户行为分析的目的是:推动产品迭代、实现精准营销,提供定制服务,驱动产品决策等。
主要体现在以下几个方面:
- 对产品而言,帮助验证产品的可行性,研究产品决策,清楚地了解用户的行为习惯,并找出产品的缺陷,以便需求的迭代与优化。
- 对设计而言,帮助增加体验的友好性,匹配用户情感,细腻地贴合用户的个性服务,并发现交互的不足,以便设计的完善与改进。
- 对运营而言,帮助裂变增长的有效性,实现精准营销,全面地挖掘用户的使用场景,并分析运营的问题,以便决策的转变与调整。
1.3 用户行为分析指标
对用户行为数据进行分析,关键是找到一个衡量数据的指标。根据用户行为表现,可以细分多个指标,主要分为三类:黏性指标、活跃指标和产出指标。
- 粘性指标:主要关注用户周期内持续访问的情况,比如新用户数与比例、活跃用户数与比例、用户转化率、用户留存率、用户流失率、用户访问率。
- 活跃指标:主要考察的是用户访问的参与度,比如活跃用户、新增用户、回访用户、流失用户、平均停留时长、使用频率等。
- 产出指标:主要衡量用户创造的直接价值输出,比如页面浏览数PV、独立访客数UV、点击次数、消费频次、消费金额等。
这些指标细分的目的是指导运营决策,即根据不同的指标去优化与调整运营策略。简而言之,用户行为分析指标细分的根本目的有:一是增加用户的粘性,提升用户的认知度;二是促进用户的活跃,诱导用户的参与度;三是提高用户的价值,培养用户的忠诚度。
1.4 实施用户行为分析
确定好用户行为分析指标后,我们可以借助一些模型对用户行为的数据进行定性和定量的分析。
常用的分析模型有:
- 行为事件分析
- 用户留存分析
- 漏斗模型分析
- 行为路径分析
- 福格模型分析
1.4.1 行为事件分析
行为事件分析是根据运营关键指标对用户特定事件进行分析。通过追踪或记录用户行为事件,可以快速的了解到事件的趋势走向和用户的完成情况。
作用:主要是解决用户是谁,从哪里来,什么时候来,干了什么事情,如何做的,归纳总结即为事件的定义遵循5W原则:Who、When、Where、What、How。主要用于研究某行为事件的发生对企业组织价值的影响以及影响程度。
1.4.2 用户留存分析
用户留存分析是一种用来分析用户参与情况与活跃程度的模型。通过留存量和留存率,可以了解用户的留存和流失状况。比如用次日留存、周留存、月留存等指标来衡量产品的人气或粘度。
作用:
用户留存一般符合40-20-10法则,即新用户的次日留存应该大于40%,周留存大于20%,月留存大于10%才符合业务标准。我们做用户留存分析主要验证是否达到既定的运营目标,进而影响下一步的产品决策。
1.4.3 漏斗模型分析
漏斗模型分析是用户在使用产品过程中,描述各个阶段中关键环节的用户转化和流失率情况。比如在日常活动运营中,通过确定各个环节的流失率,分析用户怎么流失、为什么流失、在哪里流失。找到需要改进的环节,要重点关注,并采取有效的措施来提升整体转化率。
作用:
漏斗模型分析可以验证整个流程的设计是否合理。通过对各环节相关转化率的比较,可以发现运营活动中哪些环节的转化率没有达到预期指标,从而发现问题所在,并找到优化方向。
1.4.4 行为路径分析
行为路径分析就是分析用户在产品使用过程中的访问路径。通过对行为路径的数据分析,可以发现用户最常用的功能和使用路径。并从页面的多维度分析,追踪用户转化路径,提升产品用户体验。
不管是产品冷启动,还是日常活动营销,做行为路径分析首先要梳理用户行为轨迹。用户行为轨迹包括认知、熟悉、试用、使用到忠诚等。轨迹背后反映的是用户特征,这些特征对产品运营有重要的参考价值。
在分析用户行为路径时,我们会发现用户实际的行为路径与期望的行为路径有一定的偏差。这个偏差就是产品可能存在的问题,需要及时对产品进行优化,找到缩短路径的空间。
1.4.5 福格模型分析
福格行为模型是用来研究用户行为原因的分析模型。福格行为模型用公式来简化就是B=MAT,即B=MAT。B代表行为,M代表动机,A代表能力,T代表触发。它认为要让一个行为发生,必须同时具备三个元素:动机、能力和触发器。因此可以借助福格行为模型来评估产品的合理性和能否达到预期目标。
1.5 AISAS模型
用户行为分析模型其实也是一种AISAS模型:Attention注意、Interest兴趣、Search搜索、Action行动、Share分享,也影响了用户行为决策。
-
Attention
Attention是指我们要想获得一定的业绩,就要首先吸引客户的注意。如果没有客户的话,那后面的一切营销活动都会没有任何用武之地。想要吸引客户的注意,我们可以从多方面来下手,比如说通过互动营销这种办法来吸引到店消费。 -
Interest
吸引住了客户之后,我们要想真正的留住这些客户,就要让客户对我们的产品产生一定的兴趣,让他们发自内心的想要购买我们的产品。这就要求我们在事先要对目标群体进行一定的市场调查,了解目标群体的痒点。 -
Search
当目标群体对我们产生一定的兴趣之后,他们可能就会通过一些线上或者线下的渠道来搜集我们产品的信息,这个阶段就是搜索阶段。如果要想使客户对我们留下较好的印象,线上要注意搜索引擎优化,线下要做到优化服务、提升口碑。 -
Action
如果客户经过一系列的调查之后对公司的产品较为满意的话,就会直接进行消费。在这个阶段里面促进订单成交的最主要的环节便是销售环节,所以会对销售能力有着较高的要求。 -
Share
如果客户使用该企业的产品获得了较好的使用感受,他可能会和周围的人进行分享,向周围的人推荐该企业的产品,这也就是所谓的口碑传播。我们一定要重视口碑传播的重要作用,它的说服力能够秒杀一切营销活动。
2、数据集描述
字段 | 描述 |
---|---|
user_id | 用户ID |
item_id | 商品ID |
behavior_type | 用户行为类别 |
user_geohash | 用户地理位置 |
item_category | 商品所属品类 |
time | 用户行为发生的时间 |
其中,用户行为类别包含点击、收藏、加购物车、支付四种类别,分别用数字1,2,3,4表示
3、明确分析目的
基于淘宝app平台数据,通过相关指标对用户行为进行分析,推动产品迭代、实现精准营销,提供定制服务,驱动产品决策等。
3.1 获得相关指标:
- 总量
- 日pv
- 日uv
3.2 用户消费行为分析
- 付费率
- 复购率
3.3 通过漏斗模型进行用户行为分析
3.4 RFM模型分析用户价值
4、理解数据
# 导入相关库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly as py
import plotly.graph_objects as go
import csv
import os
pyplot = py.offline.plot
os.getcwd()
import warnings
plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams.update({"font.size":15})
plt.style.use("seaborn-darkgrid")
warnings.filterwarnings("ignore")
os.chdir(r"F:\DataSets\user_behavior_data_on_taobao_app")
# 数据读入
dt = pd.read_csv("./tianchi_mobile_recommend_train_user.csv", dtype=str)
# 查看数据情况
dt.shape
(12256906, 6)
dt.columns
Index(['user_id', 'item_id', 'behavior_type', 'user_geohash', 'item_category',
'time'],
dtype='object')
dt.sample(5)
user_id | item_id | behavior_type | user_geohash | item_category | time | |
---|---|---|---|---|---|---|
1658950 | 5838287 | 11664497 | 1 | 9q9mas6 | 13713 | 2014-12-06 15 |
12147758 | 27068656 | 215433552 | 1 | NaN | 4625 | 2014-11-25 00 |
5986570 | 22060610 | 239655940 | 1 | NaN | 769 | 2014-12-08 11 |
5004260 | 127909205 | 142480396 | 1 | NaN | 6130 | 2014-12-15 22 |
7838152 | 37357777 | 253737813 | 1 | NaN | 3035 | 2014-12-04 19 |
5、数据清洗
5.1 缺失值处理
5.1.1 统计缺失值
统计缺失率
# 统计缺失率
dt.apply(lambda x: sum(x.isnull()) / len(x), axis=0)
user_id 0.00000
item_id 0.00000
behavior_type 0.00000
user_geohash 0.68001
item_category 0.00000
time 0.00000
dtype: float64
dt.user_geohash.isnull().sum()
8334824
从统计结果得知,存在缺失值的字段为user_geohash,缺失率为0.68001,共缺失8334824条,暂不做处理
5.2 日期时间数据处理
从抽样的5份数据看出,time字段包含日期及小时,这儿对日期与小时作拆分
# 拆分time
dt["date"] = dt["time"].str[0:10].str.strip()
dt["hour"] = dt["time"].str[11:].str.strip()
dt.sample()
user_id | item_id | behavior_type | user_geohash | item_category | time | date | hour | |
---|---|---|---|---|---|---|---|---|
8914805 | 8909639 | 56156672 | 1 | 95qoom0 | 12189 | 2014-12-11 14 | 2014-12-11 | 14 |
5.3 更改数据类型
# 查看数据类型
dt.info()
# dt.dtypes
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12256906 entries, 0 to 12256905
Data columns (total 8 columns):
user_id object
item_id object
behavior_type object
user_geohash object
item_category object
time object
date object
hour object
dtypes: object(8)
memory usage: 748.1+ MB
更改time、date为日期型数据,hour为int型数据
# 更改time、date为日期型数据,hour为int型数据
dt["date"] = pd.to_datetime(dt["date"])
dt["time"] = pd.to_datetime(dt["time"])
dt["hour"] = dt["hour"].astype("int")
dt.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12256906 entries, 0 to 12256905
Data columns (total 8 columns):
user_id object
item_id object
behavior_type object
user_geohash object
item_category object
time datetime64[ns]
date datetime64[ns]
hour int32
dtypes: datetime64[ns](2), int32(1), object(5)
memory usage: 701.3+ MB
5.4 异常值处理
dt.sort_values(by="time", ascending=True, inplace=True)
dt.reset_index(drop=True, inplace=True)
dt.describe(include="all")
user_id | item_id | behavior_type | user_geohash | item_category | time | date | hour | |
---|---|---|---|---|---|---|---|---|
count | 12256906 | 12256906 | 12256906 | 3922082 | 12256906 | 12256906 | 12256906 | 1.225691e+07 |
unique | 10000 | 2876947 | 4 | 575458 | 8916 | 744 | 31 | NaN |
top | 36233277 | 112921337 | 1 | 94ek6ke | 1863 | 2014-12-11 22:00:00 | 2014-12-12 00:00:00 | NaN |
freq | 31030 | 1445 | 11550581 | 1052 | 393247 | 54797 | 691712 | NaN |
first | NaN | NaN | NaN | NaN | NaN | 2014-11-18 00:00:00 | 2014-11-18 00:00:00 | NaN |
last | NaN | NaN | NaN | NaN | NaN | 2014-12-18 23:00:00 | 2014-12-18 00:00:00 | NaN |
mean | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1.481799e+01 |
std | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 6.474778e+00 |
min | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.000000e+00 |
25% | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1.000000e+01 |
50% | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1.600000e+01 |
75% | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2.000000e+01 |
max | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2.300000e+01 |
观察知并无异常数据
6、数据分析
6.1 总量
# 用户总量
totle_num = dt["user_id"].drop_duplicates().count()
totle_num
10000
6.2 pv、uv分析
- pv(访问量):PageView
- uv(访客量):UniqueVisitor
6.2.1 日访问分析
日pv : 记录每天用户访问次数
# 日pv : 记录每天用户访问次数
pv_d = dt.groupby("date").count()["user_id"]
pv_d.name="pv_d"
pv_d
date
2014-11-18 366701
2014-11-19 358823
2014-11-20 353429
2014-11-21 333104
2014-11-22 361355
2014-11-23 382702
2014-11-24 378342
2014-11-25 370239
2014-11-26 360896
2014-11-27 371384
2014-11-28 340638
2014-11-29 364697
2014-11-30 401620
2014-12-01 394611
...
dtype: int64
pv_d.index.name
'date'
日uv : 记录每日上线的用户数
# 日uv : 记录每日上线的用户数
uv_d = dt.groupby('date')["user_id"].apply(
lambda x: x.drop_duplicates().count())
uv_d.name = "uv_d"
uv_d
date
2014-11-18 6343
2014-11-19 6420
2014-11-20 6333
2014-11-21 6276
2014-11-22 6187
2014-11-23 6373
2014-11-24 6513
...
2014-12-18 6582
Name: uv_d, dtype: int64
合并uv_d与pv_d
# 合并uv_d与pv_d
pv_uv_d = pd.concat([pv_d, uv_d], axis=1)
pv_uv_d.head()
pv_d | uv_d | |
---|---|---|
date | ||
2014-11-18 | 366701 | 6343 |
2014-11-19 | 358823 | 6420 |
2014-11-20 | 353429 | 6333 |
2014-11-21 | 333104 | 6276 |
2014-11-22 | 361355 | 6187 |
# 查看pv_d与uv_d间的相关系数
method = ["pearson", "spearman"]
for i in method:
corr = pv_uv_d.corr(method=i)
print(f"{i}相关系数:{corr.iloc[0,1]:.3f}")
pearson相关系数:0.921
spearman相关系数:0.825
访问量与访问用户间的pearson相关系数为0.921、spearman相关系数为0.825,表现为强相关性
plt.rcParams["font.family"] = "SimHei"
plt.figure(figsize=(16, 9))
plt.subplot(211)
plt.plot(pv_d,c="m",label="pv")
plt.legend()
plt.subplot(212)
plt.plot(uv_d, c="c",label="uv")
plt.legend()
plt.suptitle("PV与UV变化趋势", size=25)
plt.show()
通过图形我们很容易发现双十二期间,pv与uv同时到达峰值
6.2.2 小时访问分析
# pv_h 记录每天中各小时访问次数
pv_h = dt.groupby(["date","hour"]).count()["user_id"]
pv_h.name = "pv_h"
pv_h.head()
date hour
2014-11-18 0 13719
1 7194
2 5343
3 3486
4 2782
Name: pv_h, dtype: int64
uv_h 记录每天中各小时访问用户数
# uv_h 记录每天中各小时访问用户数
uv_h = dt.groupby(["date", "hour"])["user_id"].apply(lambda x: x.drop_duplicates().count())
uv_h.name = "uv_h"
uv_h.sample(5)
date hour
2014-12-06 18 1128
2014-12-17 21 1643
2014-12-12 13 1832
2014-12-05 2 144
2014-12-03 21 1668
Name: uv_h, dtype: int64
合并uv_h与pv_h
# 合并uv_h与pv_h
pv_uv_h = pd.concat([pv_h, uv_h], axis=1)
pv_uv_h.sample(5)
pv_h | uv_h | ||
---|---|---|---|
date | hour | ||
2014-12-13 | 21 | 35747 | 1687 |
2014-12-16 | 22 | 36746 | 1571 |
2014-12-09 | 20 | 32912 | 1577 |
2014-11-27 | 20 | 26178 | 1397 |
2014-12-14 | 17 | 17307 | 1145 |
pd.MultiIndex.to_frame(pv_h.index)
# 查看pv_h与uv_h间的相关系数
method = ["pearson", "spearman"]
for i in method:
corr = pv_uv_h.corr(method=i)
print(f"{i}相关系数:{corr.iloc[0,1]:.3f}")
pearson相关系数:0.929
spearman相关系数:0.943
访问量与访问用户间的pearson相关系数为0.929、spearman相关系数为0.943,表现出极强的相关性
对某天不同时间的pv,uv变化趋势进行可视化
# 对某天不同时间的pv,uv变化趋势进行可视化
# 以2014-12-12为例
plt.figure(figsize=(16, 9))
plt.subplot(211)
plt.plot(pv_h.loc["2014-12-09"].values.tolist(), lw=3, label="每小时访问量")
plt.xticks(range(0, 24))
plt.legend(loc=2)
plt.subplot(212)
plt.plot(uv_h.loc["2014-12-09"].values.tolist(), c="c", lw=3, label="每小时访问客户数")
plt.suptitle("PV与UV变化趋势", size=22)
plt.xticks(range(0, 24))
plt.legend(loc=2)
plt.show()
PV与UV呈相同的变化趋势,0-5点呈下降趋势,5-10逐渐增长,21时附近达到峰值,18点-0点为淘宝app用户活跃时间段
6.3 不同行为类型用户PV分析
计算不同行为的用户,在每小时的访问量
# 计算不同行为的用户,在每小时的访问量
d_pv_h = pd.pivot_table(columns="behavior_type",
index=["hour"],
data=dt,
values="user_id",
aggfunc=np.size)
d_pv_h.sample(10)
behavior_type | 1 | 2 | 3 | 4 |
---|---|---|---|---|
hour | ||||
15 | 562238 | 12010 | 17289 | 7312 |
1 | 252991 | 6276 | 6712 | 1703 |
8 | 374701 | 7849 | 9970 | 3586 |
13 | 561513 | 11694 | 17419 | 7717 |
14 | 558246 | 11695 | 17067 | 7207 |
0 | 487341 | 11062 | 14156 | 4845 |
17 | 476369 | 9754 | 14515 | 5298 |
10 | 515960 | 11185 | 16203 | 7317 |
2 | 139139 | 3311 | 3834 | 806 |
9 | 456781 | 10507 | 12956 | 5707 |
d_pv_h.rename(columns={"1": "点击", "2": "收藏", "3": "加购物车", "4": "支付"})
behavior_type | 点击 | 收藏 | 加购物车 | 支付 |
---|---|---|---|---|
hour | ||||
0 | 487341 | 11062 | 14156 | 4845 |
1 | 252991 | 6276 | 6712 | 1703 |
2 | 139139 | 3311 | 3834 | 806 |
3 | 93250 | 2282 | 2480 | 504 |
4 | 75832 | 2010 | 2248 | 397 |
5 | 83545 | 2062 | 2213 | 476 |
6 | 150356 | 3651 | 3768 | 1023 |
7 | 272470 | 5885 | 7044 | 1938 |
8 | 374701 | 7849 | 9970 | 3586 |
9 | 456781 | 10507 | 12956 | 5707 |
10 | 515960 | 11185 | 16203 | 7317 |
11 | 493679 | 10918 | 15257 | 7086 |
12 | 500036 | 9940 | 15025 | 6956 |
13 | 561513 | 11694 | 17419 | 7717 |
14 | 558246 | 11695 | 17067 | 7207 |
15 | 562238 | 12010 | 17289 | 7312 |
16 | 541846 | 11127 | 16304 | 6930 |
17 | 476369 | 9754 | 14515 | 5298 |
18 | 517078 | 10342 | 14823 | 5140 |
19 | 696035 | 13952 | 18853 | 6352 |
20 | 885669 | 16599 | 25021 | 7872 |
21 | 1030483 | 20397 | 30469 | 8829 |
22 | 1027269 | 20343 | 32504 | 8845 |
23 | 797754 | 17705 | 27434 | 6359 |
plt.figure(figsize=(10, 4))
sns.lineplot(data=d_pv_h, lw=3)
plt.show()
plt.figure(figsize=(10, 4))
sns.lineplot(data=d_pv_h.iloc[:, 1:], lw=3)
plt.show()
用户行为类别1,2,3,4分别表示点击、收藏、加购物车、支付
我们可以发现四种用户行为的波动情况基本一致,加购物车的数量高于收藏数
计算各类行为间的流失率
# 计算各类行为间的流失率
d_pv_h["1-2流失率"] = (d_pv_h.iloc[:, 0] - d_pv_h.iloc[:, 1]) / d_pv_h.iloc[:, 0]
d_pv_h["1-3流失率"] = (d_pv_h.iloc[:, 0] - d_pv_h.iloc[:, 2]) / d_pv_h.iloc[:, 0]
d_pv_h["2-4流失率"] = (d_pv_h.iloc[:, 1] - d_pv_h.iloc[:, 3]) / d_pv_h.iloc[:, 1]
d_pv_h["3-4流失率"] = (d_pv_h.iloc[:, 2] - d_pv_h.iloc[:, 3]) / d_pv_h.iloc[:, 2]
d_pv_h
behavior_type | 1 | 2 | 3 | 4 | 1-2流失率 | 1-3流失率 | 2-4流失率 | 3-4流失率 |
---|---|---|---|---|---|---|---|---|
hour | ||||||||
0 | 487341 | 11062 | 14156 | 4845 | 0.977301 | 0.970953 | 0.562014 | 0.657742 |
1 | 252991 | 6276 | 6712 | 1703 | 0.975193 | 0.973469 | 0.728649 | 0.746275 |
2 | 139139 | 3311 | 3834 | 806 | 0.976204 | 0.972445 | 0.756569 | 0.789776 |
3 | 93250 | 2282 | 2480 | 504 | 0.975528 | 0.973405 | 0.779141 | 0.796774 |
4 | 75832 | 2010 | 2248 | 397 | 0.973494 | 0.970356 | 0.802488 | 0.823399 |
5 | 83545 | 2062 | 2213 | 476 | 0.975319 | 0.973511 | 0.769156 | 0.784907 |
6 | 150356 | 3651 | 3768 | 1023 | 0.975718 | 0.974939 | 0.719803 | 0.728503 |
7 | 272470 | 5885 | 7044 | 1938 | 0.978401 | 0.974148 | 0.670688 | 0.724872 |
8 | 374701 | 7849 | 9970 | 3586 | 0.979053 | 0.973392 | 0.543127 | 0.640321 |
9 | 456781 | 10507 | 12956 | 5707 | 0.976998 | 0.971636 | 0.456838 | 0.559509 |
10 | 515960 | 11185 | 16203 | 7317 | 0.978322 | 0.968596 | 0.345820 | 0.548417 |
11 | 493679 | 10918 | 15257 | 7086 | 0.977884 | 0.969095 | 0.350980 | 0.535557 |
12 | 500036 | 9940 | 15025 | 6956 | 0.980121 | 0.969952 | 0.300201 | 0.537038 |
13 | 561513 | 11694 | 17419 | 7717 | 0.979174 | 0.968978 | 0.340089 | 0.556978 |
14 | 558246 | 11695 | 17067 | 7207 | 0.979050 | 0.969427 | 0.383754 | 0.577723 |
15 | 562238 | 12010 | 17289 | 7312 | 0.978639 | 0.969250 | 0.391174 | 0.577072 |
16 | 541846 | 11127 | 16304 | 6930 | 0.979465 | 0.969910 | 0.377191 | 0.574951 |
17 | 476369 | 9754 | 14515 | 5298 | 0.979524 | 0.969530 | 0.456838 | 0.634998 |
18 | 517078 | 10342 | 14823 | 5140 | 0.979999 | 0.971333 | 0.502997 | 0.653242 |
19 | 696035 | 13952 | 18853 | 6352 | 0.979955 | 0.972914 | 0.544725 | 0.663077 |
20 | 885669 | 16599 | 25021 | 7872 | 0.981258 | 0.971749 | 0.525755 | 0.685384 |
21 | 1030483 | 20397 | 30469 | 8829 | 0.980206 | 0.970432 | 0.567142 | 0.710230 |
22 | 1027269 | 20343 | 32504 | 8845 | 0.980197 | 0.968359 | 0.565207 | 0.727880 |
23 | 797754 | 17705 | 27434 | 6359 | 0.977806 | 0.965611 | 0.640836 | 0.768207 |
获取有支付行为的客户信息
# 获取有支付行为的客户信息
plt.figure(figsize=(10, 8))
plt.subplot(211)
sns.lineplot(data=d_pv_h.iloc[:, 4:6], lw=3)
plt.subplot(212)
sns.lineplot(data=d_pv_h.iloc[:, 6:], lw=3)
plt.show()
我们能够看到在点击到加购物车和点击到收藏行为间的流失率基本稳定在97.7%左右;在10-15日期间从收藏到支付与从加购物车到支付的流失率较低。
刚开始接触到这类指标,可能得不到多少有效的结论。但不用担心,数据收集和分析持续一段时间后,数据会稳定,你也会适应应用特有的数据分布模式。若是没有这个积累过程,就算面对一个用户严重流失的层次,你也可能完全说不出个所以然。
在获得基线之后,我们可以将数据与基线比较,衡量改动。改进之后,重新收集相关数据。为积累足够访问量,收集过程需要相当时间。获得的数据能清楚地表明改动的效果:若改动后,用户流失比原来小了,那就说明改动成功。相反则需重新考虑设计。
6.3 消费行为分析
6.3.1 购买频次分析
获取有支付行为的客户信息
dt_buy = dt[dt.behavior_type=="4"]
dt_buy.sample(5)
user_id | item_id | behavior_type | user_geohash | item_category | time | date | hour | |
---|---|---|---|---|---|---|---|---|
2495275 | 101601722 | 34047414 | 4 | NaN | 3628 | 2014-11-24 22:00:00 | 2014-11-24 | 22 |
4498818 | 121456686 | 263967408 | 4 | NaN | 9885 | 2014-11-30 14:00:00 | 2014-11-30 | 14 |
675580 | 114497121 | 9517999 | 4 | NaN | 5699 | 2014-11-19 22:00:00 | 2014-11-19 | 22 |
10087048 | 137760555 | 152460064 | 4 | NaN | 2513 | 2014-12-13 15:00:00 | 2014-12-13 | 15 |
1640944 | 132039263 | 28241579 | 4 | NaN | 11406 | 2014-11-22 19:00:00 | 2014-11-22 | 19 |
获取客户消费次数
# 获取客户消费次数
buy_c = dt_buy.groupby("user_id").size()
buy_c.sample(10)
user_id
20487789 12
3791755 1
62871223 1
61779777 2
50698254 9
134118557 6
110374516 10
94335711 2
1344672 1
48304965 2
dtype: int64
buy_c.describe()
count 8886.000000
mean 13.527459
std 19.698786
min 1.000000
25% 4.000000
50% 8.000000
75% 17.000000
max 809.000000
dtype: float64
从以上统计可以看出,用户平均购买次数为13.5次,标准差19.6,具有一定波动性。中位数是8次,75分位数是17次,说明用户购买次数大部分都在20次以下。而最大值是809次,这差别有点大。
- 一般情况,消费类型的数据分布,大部分呈现的是长尾形态;绝大多数用户是低频次消费客群,但用户贡献率集中在少数分群里,符合二八法则。
plt.hist(x=buy_c,bins=100)
plt.show()
plt.hist(x=buy_c[buy_c.values<=30],bins=10)
(array([2047., 1552., 1248., 937., 666., 491., 368., 301., 222.,
172.]),
array([ 1. , 3.9, 6.8, 9.7, 12.6, 15.5, 18.4, 21.3, 24.2, 27.1, 30. ]),
<a list of 10 Patch objects>)
6.3.2 日ARPPU分析
ARPPU(average revenue per paying user)是指从每位付费用户身上获得的收入,即统计周期内,付费用户对产品产生的平均收入
ARPPU = 总收入 / 付费用户数
因数据集中没有消费金额信息,本次采用消费次数代替消费金额
人均消费次数 = 消费总次数 / 消费总人次数
# 人均消费次数 = 消费总次数 / 消费总人次数
dt_arppu = dt[dt.behavior_type == "4"].groupby(
["date", "user_id"])["behavior_type"].count().reset_index().rename(
columns={"behavior_type": "buy_count"})
dt_arppu.sample(10)
date | user_id | buy_count | |
---|---|---|---|
23176 | 2014-12-03 | 3141933 | 3 |
20672 | 2014-12-01 | 92780565 | 1 |
726 | 2014-11-18 | 31663890 | 1 |
9891 | 2014-11-24 | 70891589 | 1 |
10118 | 2014-11-24 | 89261071 | 1 |
46671 | 2014-12-17 | 22981352 | 1 |
20587 | 2014-12-01 | 86323571 | 1 |
25053 | 2014-12-04 | 54214799 | 1 |
15754 | 2014-11-28 | 61114029 | 1 |
18632 | 2014-11-30 | 61754447 | 1 |
dt_arppu.describe()
buy_count | |
---|---|
count | 49201.000000 |
mean | 2.443141 |
std | 3.307288 |
min | 1.000000 |
25% | 1.000000 |
50% | 1.000000 |
75% | 3.000000 |
max | 185.000000 |
计算ARPPU
# ARPPU = 每日消费总次数除以消费总人数
ARPPU = pd.DataFrame(
dt_arppu.groupby("date").sum()["buy_count"] /
dt_arppu.groupby("date").count()["buy_count"]).rename(
columns={"buy_count": "ARPPU"})
ARPPU.describe()
ARPPU | |
---|---|
count | 31.000000 |
mean | 2.368446 |
std | 0.296108 |
min | 2.204384 |
25% | 2.262436 |
50% | 2.313460 |
75% | 2.358159 |
max | 3.913523 |
ARPPU.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1faa0a64518>
绝大部分消费客户每天消费次数在3次以内,双十二期间达到峰值
6.3.3 日ARPU情况分析
ARPU值 (每用户平均收入,Average Revenue Per User) 就是指每用户平均收入。ARPU注重的是一个时间段内运营商从每个用户所得到的利润。很明显,高端的用户越多,ARPU越高。在这个时间段,从运营商的运营情况来看,ARPU值高说明利润高,这段时间效益好。它可以衡量产品的盈利和发展活力。
ARPU = 消费总收入 / 用户数
因数据集中没有消费金额信息,本次采用消费次数代替消费金额
# 新增一列以便记录各行为次数
dt["behavior_count"] = 1
dt.sample(3)
user_id | item_id | behavior_type | user_geohash | item_category | time | date | hour | behavior_count | |
---|---|---|---|---|---|---|---|---|---|
10017159 | 117929882 | 313405220 | 1 | 95rilhv | 10392 | 2014-12-13 11:00:00 | 2014-12-13 | 11 | 1 |
7263735 | 111073682 | 26727890 | 1 | NaN | 13041 | 2014-12-07 13:00:00 | 2014-12-07 | 13 | 1 |
4786992 | 67759870 | 179797004 | 1 | NaN | 12982 | 2014-12-01 07:00:00 | 2014-12-01 | 7 | 1 |
dt_arpu = dt.groupby(["date", "user_id", "behavior_type"
])["behavior_count"].count().reset_index()
dt_arpu.sample(10)
date | user_id | behavior_type | behavior_count | |
---|---|---|---|---|
364514 | 2014-12-18 | 110058496 | 1 | 161 |
300329 | 2014-12-12 | 87658501 | 1 | 212 |
313130 | 2014-12-13 | 85994287 | 2 | 1 |
293802 | 2014-12-12 | 38915660 | 1 | 87 |
224580 | 2014-12-07 | 123963959 | 3 | 3 |
218121 | 2014-12-06 | 55305887 | 1 | 51 |
197641 | 2014-12-04 | 90414084 | 2 | 4 |
44511 | 2014-11-21 | 85004126 | 4 | 2 |
347688 | 2014-12-16 | 61068008 | 3 | 2 |
174498 | 2014-12-03 | 107471039 | 1 | 143 |
ARPU = dt_arpu.groupby("date").apply(
lambda x: x[x.behavior_type == "4"].sum()/len(x.user_id.unique()))
ARPU
behavior_count | |
---|---|
date | |
2014-11-18 | 0.588050 |
2014-11-19 | 0.574143 |
2014-11-20 | 0.546660 |
2014-11-21 | 0.481358 |
2014-11-22 | 0.577016 |
2014-11-23 | 0.525184 |
2014-11-24 | 0.526025 |
2014-11-25 | 0.545426 |
2014-11-26 | 0.562058 |
2014-11-27 | 0.577135 |
2014-11-28 | 0.519955 |
2014-11-29 | 0.515906 |
2014-11-30 | 0.566860 |
2014-12-01 | 0.597341 |
2014-12-02 | 0.552824 |
2014-12-03 | 0.589977 |
2014-12-04 | 0.565151 |
2014-12-05 | 0.521282 |
2014-12-06 | 0.508075 |
2014-12-07 | 0.507007 |
2014-12-08 | 0.520871 |
2014-12-09 | 0.525282 |
2014-12-10 | 0.483464 |
2014-12-11 | 0.467943 |
2014-12-12 | 1.975518 |
2014-12-13 | 0.513282 |
2014-12-14 | 0.522346 |
2014-12-15 | 0.554590 |
2014-12-16 | 0.560410 |
2014-12-17 | 0.544182 |
2014-12-18 | 0.544819 |
ARPU.describe()
behavior_count | |
---|---|
count | 31.000000 |
mean | 0.585811 |
std | 0.259981 |
min | 0.467943 |
25% | 0.520413 |
50% | 0.544819 |
75% | 0.566005 |
max | 1.975518 |
ARPU.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1fa9ea20da0>
淘宝app活跃用户(有过操作行为的用户)在2014-11-18至2014-12-18这31天内,每天消费次数在0.5次上下波动,而在双十二期间到达峰值1,976,即平均每人双十二消费2次
6.3.4 付费率
付费率 = 消费人数 / 总用户数
从此份数据中我们不嫩得到淘宝总用户数,故使用活跃用户总数代替总用户数
# 从此份数据中我们不嫩得到淘宝总用户数,故使用活跃用户总数代替总用户数
rate_pay = dt_arpu.groupby("date").apply(lambda x: x[
x.behavior_type == "4"].count() / len(x.user_id.unique())).iloc[:, 1]
rate_pay.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1fa9f2a90b8>
rate_pay.describe()
count 31.000000
mean 0.241566
std 0.050087
min 0.210183
25% 0.225660
50% 0.235358
75% 0.240304
max 0.504793
Name: user_id, dtype: float64
在每天活跃用户群中,具有消费行为的占24%左右,双十二到达50%
6.3.5 同一时间段用户消费次数分布
pay_f = dt[dt.behavior_type=="4"].groupby(["user_id","date","hour"])["behavior_count"].sum()
sns.distplot(pay_f)
<matplotlib.axes._subplots.AxesSubplot at 0x1fa9d526588>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sDi8sY72-1587527913399)(output_124_1.png)]
pay_f.describe()
count 65223.000000
mean 1.842985
std 2.295531
min 1.000000
25% 1.000000
50% 1.000000
75% 2.000000
max 97.000000
Name: behavior_count, dtype: float64
pay_f.mode()
0 1
dtype: int64
在同一小时段中,用户消费次数最多的为一次,75分位数为2次
6.3.6 复购情况分析
复购情况:存在两天及以上有购买行为,一天多次购买算作一次
复购率 = 又复购行为的用户数 / 有购买行为的用户数
6.3.6.1 复购率
每个用户在不同日期购买总次数
# 每个用户在不同日期购买总次数
dt_rebuy = dt[dt.behavior_type == "4"].groupby('user_id')["date"].apply(
lambda x: len(x.unique())).rename("rebuy_count")
dt_rebuy.sample(5)
user_id
107209058 22
112806422 5
61966309 18
13103318 13
95839581 7
Name: rebuy_count, dtype: int64
print("复购率为:%.3f"%(dt_rebuy[dt_rebuy>=2].count()/dt_rebuy.count()))
复购率为:0.872
6.3.6.2 复购时间分析
计算不同时间,不同用户的购买次数
# 计算不同时间(天),不同用户的购买次数
dt_buy_d = dt[dt.behavior_type == "4"].groupby(
["user_id", "date"])["behavior_count"].count().reset_index()
dt_buy_d.sample(10)
user_id | date | behavior_count | |
---|---|---|---|
39965 | 76314785 | 2014-11-20 | 1 |
20195 | 23376907 | 2014-11-20 | 1 |
12578 | 131701813 | 2014-12-15 | 1 |
12840 | 132231447 | 2014-12-15 | 2 |
8693 | 121756245 | 2014-12-05 | 1 |
46422 | 93127487 | 2014-11-19 | 2 |
32495 | 56592437 | 2014-11-19 | 1 |
5923 | 114971408 | 2014-11-28 | 2 |
45646 | 91087067 | 2014-12-17 | 1 |
27333 | 42208524 | 2014-12-13 | 1 |
不同用户购物时间间隔
# 不同用户购物时间间隔
dt_buy_d["d_diff"] = dt_buy_d.groupby("user_id").date.apply(
lambda x: x.sort_values().diff(1)).map(lambda x:x.days)
dt_buy_d.describe()
behavior_count | d_diff | |
---|---|---|
count | 49201.000000 | 40315.000000 |
mean | 2.443141 | 3.732333 |
std | 3.307288 | 3.858599 |
min | 1.000000 | 1.000000 |
25% | 1.000000 | 1.000000 |
50% | 1.000000 | 2.000000 |
75% | 3.000000 | 5.000000 |
max | 185.000000 | 30.000000 |
# 绘图
dt_buy_d.iloc[:,-1].dropna().value_counts().plot(kind="bar")
plt.xlabel("day_diff")
plt.ylabel("count")
Text(0, 0.5, 'count')
不同用户平均复购时间
# 不同用户平均复购时间
sns.distplot(dt_buy_d.groupby("user_id").d_diff.mean().dropna())
<matplotlib.axes._subplots.AxesSubplot at 0x1fae9d95c88>
计算分位数
dt_buy_d.quantile(np.linspace(0,1,11)).iloc[:,1]
0.0 1.0
0.1 1.0
0.2 1.0
0.3 1.0
0.4 2.0
0.5 2.0
0.6 3.0
0.7 4.0
0.8 6.0
0.9 9.0
1.0 30.0
Name: d_diff, dtype: float64
80%的淘宝用户复购复购时间在6天以内
6.4 漏斗流失分析
dt_c = dt.groupby("behavior_type").size()
dt_c
behavior_type
1 11550581
2 242556
3 343564
4 120205
dtype: int64
print("从点击到收藏流失率为%.3f" % ((dt_c[0] - dt_c[1]) * 100 / dt_c[0]))
从点击到收藏流失率为97.900
print("从点击到加购物车流失率为%.3f" % ((dt_c[0] - dt_c[2]) * 100 / dt_c[0]))
从点击到加购物车流失率为97.026
print("从加购物车到支付流失率为%.3f" % ((dt_c[2] - dt_c[3]) * 100 / dt_c[2]))
从加购物车到支付流失率为65.012
print("从加收藏到支付流失率为%.3f" % ((dt_c[1] - dt_c[3]) * 100 / dt_c[2]))
从加收藏到支付流失率为35.612
6.5 用户价值RFM模型分析
因数据集中无消费金额相关信息,因此此处仅对R、F两方面进行用户价值分析
每位用户最近的购买时间
# 参考时间
from datetime import datetime
datenow = datetime(2014, 12, 19)
# 每位用户最近的购买时间
recently_pay_time = dt[dt.behavior_type == "4"].groupby("user_id").date.apply(
lambda x: datenow - x.sort_values().iloc[-1])
recently_pay_time = recently_pay_time.rename("recent")
recently_pay_time = recently_pay_time.reset_index()
recently_pay_time.recent = recently_pay_time.recent.map(lambda x: x.days)
recently_pay_time.head(5)
user_id | recent | |
---|---|---|
0 | 100001878 | 1 |
1 | 100011562 | 3 |
2 | 100012968 | 1 |
3 | 100014060 | 1 |
4 | 100024529 | 3 |
每位用户消费频率
# 每位用户消费频率
buy_freq = dt[dt.behavior_type == "4"].groupby("user_id").date.count().rename(
"freq").reset_index()
buy_freq.head()
user_id | freq | |
---|---|---|
0 | 100001878 | 36 |
1 | 100011562 | 3 |
2 | 100012968 | 15 |
3 | 100014060 | 24 |
4 | 100024529 | 26 |
因为只有31天的数据,所以这儿只基于等频分段,简单的将R、F分为两个等级
# 因为只有31天的数据,所以这儿只基于等频分段,简单的将R、F分为两个等级(分数越高越好)
RFM = pd.merge(recently_pay_time,buy_freq,on="user_id",how="outer")
RFM["R_value"] = pd.qcut(RFM["recent"],2,labels=["2","1"])
RFM["F_value"] = pd.qcut(RFM["freq"],2,labels=["1","2"])
RFM["RFM"] = RFM["R_value"].str.cat(RFM["F_value"])
RFM.head()
user_id | recent | freq | R_value | F_value | RFM | |
---|---|---|---|---|---|---|
0 | 100001878 | 1 | 36 | 2 | 2 | 22 |
1 | 100011562 | 3 | 3 | 2 | 1 | 21 |
2 | 100012968 | 1 | 15 | 2 | 2 | 22 |
3 | 100014060 | 1 | 24 | 2 | 2 | 22 |
4 | 100024529 | 3 | 26 | 2 | 2 | 22 |
通过RFM对用户进行分组后,可对不同组别的客户拟制实施不同的营销方式
7、总结
7.1 pv、uv分析得知:
7.1.1 日访问
- 访问量与访问用户间,表现为强相关性
- 双十二期间,pv与uv同时到达峰值
7.1.2 小时访问
- PV与UV呈相同的变化趋势,0-5点呈下降趋势,5-10逐渐增长,21时附近达到峰值,18点-0点为淘宝app用户活跃时间段
7.1.3 不同行为类型用户PV分析
我们能够看到在点击到加购物车和点击到收藏行为间的流失率基本稳定在97.7%左右;在10-15日期间从收藏到支付与从加购物车到支付的流失率较低。
7.2 消费行为分析
- 用户平均购买次数为13.5次,标准差19.6,具有一定波动性。中位数是8次,75分位数是17次,说明用户购买次数大部分都在20次以下。而最大值是809次,这差别有点大。
- 一般情况,消费类型的数据分布,大部分呈现的是长尾形态;绝大多数用户是低频次消费客群,但用户贡献率集中在少数分群里,符合二八法则。
7.2.1 ARPPU分析:
- 绝大部分消费客户每天消费次数在3次以内,双十二期间达到峰值
7.2.2 日ARPU情况分析
- 淘宝app活跃用户(有过操作行为的用户)在2014-11-18至2014-12-18这31天内,每天消费次数在0.5次上下波动,而在双十二期间到达峰值1,976,即平均每人双十二消费2次
7.3 付费情况
- 在每天活跃用户群中,具有消费行为的占24%左右,双十二到达50%
- 在同一小时段中,用户消费次数最多的为一次,75分位数为2次
7.4 复购情况
- 80%的淘宝用户复购复购时间在6天以内
- 复购率为:0.872
7.5 漏斗流失分析
- 从点击到收藏流失率为97.900
- 从点击到加购物车流失率为97.026
- 从加购物车到支付流失率为65.012
- 从加收藏到支付流失率为35.612
7.6 RFM
- 我们通过RFM将用户分为了多组,可对不同组别的客户拟制实施不同的营销方式
以上是我对这份数据进行的一次探索分析,相信其中会有很多不足之处,欢迎有缘读到此篇文章的小朋友们批评指正
如有能启发或帮助到你的地方,我将倍感荣幸。(●’◡’●)
转载:https://blog.csdn.net/weixin_44390462/article/details/105678576