文章目录
项目背景
以淘宝app平台为数据集,通过行业的指标对淘宝用户行为进行分析,从而探索淘宝用户的行为模式,具体指标包括:日PV和日UV分析,付费率分析,复购行为分析,漏斗流失分析和用户价值RFM分析。
数据来源
https://tianchi.aliyun.com/dataset/dataDetail?dataId=649&userId=1
数据介绍
列名称 | 说明 |
---|---|
用户ID | 整数类型,序列化后的用户ID |
商品ID | 整数类型,序列化后的商品ID |
商品类目ID | 整数类型,序列化后的商品所属类目ID |
行为类型 | 字符串,枚举类型,包括(‘pv’, ‘buy’, ‘cart’, ‘fav’) |
时间戳 | 行为发生的时间戳 |
行为类型 | 说明 |
---|---|
pv | 商品详情页pv,等价于点击 |
buy | 商品购买 |
cart | 将商品加入购物车 |
fav | 收藏商品 |
分析目标
- 用户行为分析/销售品类分析/用户分类/漏斗分析;
- 用户流失分析/用户复购分析
A. 从整体数据来看,PV,UV,平均访问量,交易总数、交易用户比例,复购率和跳失率,用户流失分析(漏斗转换),用户消费行为分析当日UV、当日平均访问量,当日交易用户数、交易用户比例(当日交易用户数/当日UV),当日ARPU(总交易量/当日UVor活跃用户数)、当日ARPPU(总交易量/当日交易用户数or活跃交易用户量),当日活跃用户数(自定义“活跃”);——用户量变化趋势图
B. 当日行为(pv,buy,cart,fav)数,当日行为转化率,分析三条路径:点击->收藏->购买;点击->加购->购买;点击->购买;——行为变化趋势图 - 时间维度分析——用户在哪些时间、时段活跃
A. 用户行为时段分析
B. 用户量(UV,交易用户数)时段分析 - 根据RFM模型对用户分类
- 商品分析——用户对哪些产品、类目感兴趣
A. 热门商品top
B. 热门商品类目top
技术栈
- numpy
- pandas
- matplotlib
- seaborn
- pyecharts
数据读取与展示
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from pyecharts.globals import CurrentConfig, NotebookType
from pyecharts import options as opts
from pyecharts.charts import Line
from pyecharts.charts import Bar
CurrentConfig.NOTEBOOK_TYPE = NotebookType.JUPYTER_NOTEBOOK
# 数据量过大,这里只选取前1000w行
# 根据官网介绍给定列名,具有可读性
columns=["userid", 'itemid', 'categoryid', 'type', 'timestamp']
data = pd.read_csv('/home/fonttian/Data/dataset/User Behavior Data from Taobao for Recommendation/UserBehavior.csv',
engine='python',
encoding='utf-8',
names=columns,
chunksize=10000000,
iterator=True)
dataframe = data.get_chunk(10000000)
# 查看数据的基本信息
dataframe.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000000 entries, 0 to 9999999
Data columns (total 5 columns):
# Column Dtype
--- ------ -----
0 userid int64
1 itemid int64
2 categoryid int64
3 type object
4 timestamp int64
dtypes: int64(4), object(1)
memory usage: 381.5+ MB
# 缺失值查看
dataframe.isnull().sum()
userid 0
itemid 0
categoryid 0
type 0
timestamp 0
dtype: int64
dataframe.nunique()
userid 97811
itemid 1561016
categoryid 7967
type 4
timestamp 760501
dtype: int64
取一百万数据做分析,维度如下
维度 | 数量 |
---|---|
用户数量 | 97,811 |
商品数量 | 1,561,016 |
商品类目数量 | 7,967 |
所有行为数量 | 10,000,000 |
dataframe.head()
userid | itemid | categoryid | type | timestamp | |
---|---|---|---|---|---|
0 | 1 | 2268318 | 2520377 | pv | 1511544070 |
1 | 1 | 2333346 | 2520771 | pv | 1511561733 |
2 | 1 | 2576651 | 149192 | pv | 1511572885 |
3 | 1 | 3830808 | 4181361 | pv | 1511593493 |
4 | 1 | 4365585 | 2520377 | pv | 1511596146 |
数据清洗
-
将时间戳转为日期
-
数据集说明中写的是本数据集的日期范围是2017年11月25日至2017年12月3日,所以剔除这日期以外的数据
import datetime
# 时区转换to_datetime的默认时区不是中国,所以要加8小时
dataframe['time']=pd.to_datetime(dataframe['timestamp'],unit='s')+datetime.timedelta(hours=8)
# 保留2017.11.25-2017.12.3期间的数据
startTime = datetime.datetime.strptime("2017-11-25 00:00:00","%Y-%m-%d %H:%M:%S")
endTime = datetime.datetime.strptime("2017-12-03 23:59:59","%Y-%m-%d %H:%M:%S")
dataframe = dataframe[(dataframe.time>=startTime)&(dataframe.time<=endTime)]
dataframe = dataframe.reset_index(drop=True)
# 按照日期和小时进行时间拆分
dataframe['date'] = dataframe.time.dt.date
dataframe['hour'] = dataframe.time.dt.hour
# 删除时间戳节约内存
dataframe.drop('timestamp', inplace=True, axis=1)
dataframe.head()
userid | itemid | categoryid | type | time | date | hour | |
---|---|---|---|---|---|---|---|
0 | 1 | 2268318 | 2520377 | pv | 2017-11-25 01:21:10 | 2017-11-25 | 1 |
1 | 1 | 2333346 | 2520771 | pv | 2017-11-25 06:15:33 | 2017-11-25 | 6 |
2 | 1 | 2576651 | 149192 | pv | 2017-11-25 09:21:25 | 2017-11-25 | 9 |
3 | 1 | 3830808 | 4181361 | pv | 2017-11-25 15:04:53 | 2017-11-25 | 15 |
4 | 1 | 4365585 | 2520377 | pv | 2017-11-25 15:49:06 | 2017-11-25 | 15 |
dataframe.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 9994446 entries, 0 to 9994445
Data columns (total 7 columns):
# Column Dtype
--- ------ -----
0 userid int64
1 itemid int64
2 categoryid int64
3 type object
4 time datetime64[ns]
5 date object
6 hour int64
dtypes: datetime64[ns](1), int64(4), object(2)
memory usage: 533.8+ MB
数据分析
用户行为分析
整体概况
从整体数据来看,PV,UV,平均访问量,交易总数、交易用户比例,复购率和跳失率,用户流失分析(漏斗转换)
# 取消科学计数法,保留两位小数
pd.set_option("float_format", lambda x: "%.2f" % x)
# 9天总用户量,有操作的商品及商品类目
total_unique_users = dataframe.userid.nunique() # 独立访客数UV
total_unique_itemid = dataframe.itemid.nunique() # 有操作的商品
total_unique_categoryid = dataframe.categoryid.nunique() # 有操作的商品类目
user_bought_count = dataframe[dataframe['type']=='buy'].userid.nunique() # 付费用户数
user_nobought_count = total_unique_users - user_bought_count # 非付费用户数
print(f" UV:{total_unique_users}")
print(f" 商品数:{total_unique_itemid}")
print(f" 类目数:{total_unique_categoryid}")
print(f" 付费用户数:{user_bought_count}")
print(f"付费用户占比:{user_bought_count/total_unique_users*100:.2f}%")
UV:97810
商品数:1560525
类目数:7966
付费用户数:66452
付费用户占比:67.94%
type_series = dataframe.type.value_counts()
plt.figure()
plt.pie(x=type_series,labels=type_series.index,autopct='%1.2f%%')
plt.show()
type_df=pd.DataFrame([type_series,type_series/9,type_series/total_unique_users],
index=['total','avg_day','avg_user'])
# 付费用户行为记录
type_df.loc['paying_user']=dataframe[dataframe['userid'].isin(dataframe[dataframe['type']=='buy']['userid'])].type.value_counts()
type_df
pv | cart | fav | buy | |
---|---|---|---|---|
total | 8944510.00 | 559132.00 | 291657.00 | 199147.00 |
avg_day | 993834.44 | 62125.78 | 32406.33 | 22127.44 |
avg_user | 91.45 | 5.72 | 2.98 | 2.04 |
paying_user | 6638346.00 | 432612.00 | 211633.00 | 199147.00 |
跳失率和复购率
跳失率=只有点击行为的用户/总用户数
其实真正的跳失率应该是只浏览一个页面就离开的访问次数 / 该页面的全部访问次数
这边只是为了突出这些有待发展的客户
复购率=购买2次及以上用户数/总购买用户数
复购率可以分为按客户计算和按交易计算,这里我采用的是按客户计算。
一定要确定统计周期,像这个数据的统计周期就是9天
groupby_userid = dataframe.groupby(by='userid')
user_type = groupby_userid.type.value_counts().unstack() # 使用unstack进行不堆叠操作,列方向上的索引转成行方向的索引
user_type.tail()
type | buy | cart | fav | pv |
---|---|---|---|---|
userid | ||||
1017990 | nan | 3.00 | nan | 56.00 |
1017994 | nan | 3.00 | 3.00 | 29.00 |
1017997 | 2.00 | nan | 3.00 | 90.00 |
1018000 | nan | 4.00 | nan | 181.00 |
1018011 | 1.00 | nan | nan | 41.00 |
# 跳失率
# sum(axis=1)对DataFrame进行横向相加,如果一个userid的pv值==横向相加的和,那就表明他只有点击行为
only_pv_users = user_type[user_type['pv']==user_type.sum(axis=1)]
# 计算跳失率
bounce_rate = only_pv_users.shape[0]/total_unique_users
print("跳失率:{:.2f}%".format(bounce_rate*100))
跳失率:5.74%
分析:跳失率为5.74%,数值看上去较小,但跳失率一定程度上反映了商品的受欢迎程度,最好还是结合行业数据和以往数据分析是否处于正常范围。
影响跳失率的相关因素有:商品吸引力、商品加载时长等。
# 复购率
repurchase_users = user_type[user_type['buy']>=2].shape[0] # 购买记录超过1次的用户数
repurchase_rate = repurchase_users/user_bought_count
print("复购率:{:.2f}%".format(repurchase_rate*100))
# 进一步分析复购次数
sns.distplot(user_type[user_type['buy']>=2]['buy']-1,kde=False)
plt.show()
复购率:66.01%
结论:淘宝用户复购率能达到66.01%,但是进一步查看用户复购次数,发现绝大多数用户复购次数很少;
推测:淘宝的市场份额一直稳居前列,用户量足够庞大,足够的用户量复购一次也能提高复购率。
个人思考:在淘宝下沉扩展获取新用户的同时,促进老用户复购次数增加,进一步稳定提高复购率应是更重要的事情。购买一次可能是被吸睛的标题、精美的图片或是诱人的营销活动吸引,而复购就要求产品质量过关、服务到位,消费者对第一次的购物体验很满意才会进行第二次,所以淘宝可以重点在这些方面帮助商家。
用户转化漏斗分析
行为(pv,buy,cart,fav)数,行为转化率,分析两条路径:点击->收藏->购买;点击->加购->购买
pv_df = dataframe[dataframe['type']=='pv']
buy_df = dataframe[dataframe['type']=='buy']
cart_df = dataframe[dataframe['type']=='cart']
fav_df = dataframe[dataframe['type']=='fav']
# process1 点击->加购->购买
pv_cart_df = pd.merge(left=pv_df,right=cart_df,how='inner',on=['userid','itemid','categoryid'],suffixes=('_pv','_cart'))
cart_buy_df = pd.merge(left=cart_df,right=buy_df,how='inner',on=['userid','itemid','categoryid'],suffixes=('_cart','_buy'))
count_users_pv_cart = pv_cart_df[pv_cart_df.time_pv < pv_cart_df.time_cart].userid.nunique()
count_users_cart_buy = cart_buy_df[cart_buy_df.time_cart < cart_buy_df.time_buy].userid.nunique()
# process2 点击->收藏->购买
pv_fav_df = pd.merge(left=pv_df,right=fav_df,how='inner',on=['userid','itemid','categoryid'],suffixes=('_pv','_fav'))
fav_buy_df = pd.merge(left=fav_df,right=buy_df,how='inner',on=['userid','itemid','categoryid'],suffixes=('_fav','_buy'))
count_user_pv_fav = pv_fav_df[pv_fav_df.time_pv < pv_fav_df.time_fav].userid.nunique()
count_user_fav_buy = fav_buy_df[fav_buy_df.time_fav < fav_buy_df.time_buy].userid.nunique()
fav_cart_ratio = (count_user_pv_fav+count_users_pv_cart)/total_unique_users
buy_ratio=(count_user_fav_buy+count_users_cart_buy)/total_unique_users
print('收藏加购用户转化率为:%.2f%%'%(fav_cart_ratio*100))
print('购买用户转化率为:%.2f%%'%(buy_ratio*100))
收藏加购用户转化率为:59.40%
购买用户转化率为:31.32%
from pyecharts.charts import Funnel
# 漏斗图datapair
process_data_pair = [("点击量", total_unique_users),
("收藏加购量", count_user_pv_fav+count_users_pv_cart),
("购买量", count_user_fav_buy+count_users_cart_buy)]
(
Funnel(init_opts=opts.InitOpts(width='500px', height='400px'))
.add("type",
data_pair=process_data_pair,
label_opts=opts.LabelOpts(position="top"),
gap=2,
tooltip_opts=opts.TooltipOpts(is_show=True))
.set_global_opts(title_opts=opts.TitleOpts(title="用户转化率", subtitle="process 浏览->收藏/加购->购买"))
).render_notebook()
/home/fonttian/anaconda3/envs/keras/lib/python3.8/site-packages/pyecharts/charts/chart.py:14: PendingDeprecationWarning: pyecharts 所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 :)
super().__init__(init_opts=init_opts)
<div id="cb60083ae4ee4896b839e0046a959c31" style="width:500px; height:400px;"></div>
时间维度分析
- 用户行为时间维度分析
- 用户量时间维度分析
用户行为变化
用户行为变化趋势
- 点击量、收藏量、加购量、购买量在2017/12/02当天上升明显,尤其,2017/12/02和17/11/25同为周六,相比之下,2017/12/2点击量上升尤为明显,经过查找和推测,2017/12/02当天淘宝开始为“双十二”活动进行预热,开启商品精选活动,因此吸引了更多的点击量。
- 周末的各项指标都优于周内,周六周日用户尤为活跃,用户有更多的时间可以逛淘宝,因此一些营销活动应当在周六周日进行。
用户行为时段分布
- 各时段指标走势大致一致。
- 5:00-10:00及18:00-21:00两段时间是用户活跃度迅速增长的时段。
- 10:00-18:00这个时间段的用户活跃度上下浮动,但基本保持着同一水平。
- 13:00,15:00这两个时间段是用户活跃度稳定阶段的两个小高峰,我们可以猜测13:00是因为用户工作午休结束了拿起手机再摸一会儿鱼造成的,15:00是因为工作了一两个小时又想摸鱼。17:00开始一部分用户下班了或马上下班,可以开始正大光明摸鱼。
- 21:00达到用户操作量峰值。
- 一些广告推广或者活动营销可以在18:00-21:00这段时间加大力度;
用户量分别情况
- 每日用户量统计情况
- 每日的活跃用户量基本在71%左右,而成交客户基本维持在20%
- 2017/12/02和2017/12/03购买量和购买人数是上涨的,而活跃用户比例较前三天下降了一个百分点,且付费用户占比,ARPU、ARPPU均下降了一到两个百分点。
- 这9天内,用户活跃天数呈现正态分布,用户活跃天数主要集中在3-7天(用户当天操作记录达3条算作当天活跃)
behavior_types=list(dict(dataframe['type'].value_counts()).keys())
behavior_types
['pv', 'cart', 'fav', 'buy']
groupby_date = dataframe.groupby(by=dataframe.date) # 根据日期分组
dates = sorted(list(dict(dataframe['date'].value_counts()).keys()))
dates_df = pd.DataFrame(data=None, index=dates, columns=behavior_types) # 创建按日期分组的数据框
for d in dates:
dates_df.loc[d] = groupby_date.get_group(d).type.value_counts() # 按日期填充数据框
# 日期转换为星期,datetime.datetime.isoweekday()返回的1-7代表周一--周日
dates_df['weekday'] = [datetime.datetime.isoweekday(datetime.date(x.year,x.month,x.day)) for x in dates_df.index]
dates_df
pv | cart | fav | buy | weekday | |
---|---|---|---|---|---|
2017-11-25 | 931880 | 56283 | 30168 | 19719 | 6 |
2017-11-26 | 952269 | 59469 | 31281 | 20211 | 7 |
2017-11-27 | 897421 | 55010 | 29723 | 22225 | 1 |
2017-11-28 | 883696 | 54194 | 29002 | 20996 | 2 |
2017-11-29 | 913153 | 55802 | 30030 | 21814 | 3 |
2017-11-30 | 929352 | 56722 | 30469 | 21731 | 4 |
2017-12-01 | 972109 | 62885 | 31048 | 20941 | 5 |
2017-12-02 | 1238785 | 80377 | 40210 | 25868 | 6 |
2017-12-03 | 1225845 | 78390 | 39726 | 25642 | 7 |
这里用分别用matplotlib和pyecharts进行绘图,通过可视化可以观察到由pyecharts对用户多种行为变化趋势的观察更为友好,本项目后续可视化将采用pyecharts库实现;
并不是说matplotlib就不好,个人觉得就一般静态图或比较对象相差较大的可以用matplotlib就能观察并得出结论,但像下图这样除了pv其他用户行为几乎都挤在一起很不利于肉眼观测,而pyechart可以通过鼠标拖动能显示数量,更清晰直接。
dates_df.plot(rot=60)
plt.show()
(
Line(init_opts=opts.InitOpts(width="800px", height="500px"))
.add_xaxis(xaxis_data=dates_df.index)
.add_yaxis("pv", y_axis=dates_df['pv'],is_symbol_show=False)
.add_yaxis("cart",y_axis=dates_df['cart'],is_symbol_show=False)
.add_yaxis("fav",y_axis=dates_df['fav'],is_symbol_show=False)
.add_yaxis("buy",y_axis=dates_df['buy'],is_symbol_show=False)
.add_yaxis("ops",y_axis=dataframe.groupby(by=['date'])['userid'].count(),is_symbol_show=False)
.set_global_opts(
title_opts=opts.TitleOpts(title="用户行为变化趋势图",
subtitle="2017/11/25-2017/12/03期间用户行为变化趋势"),
tooltip_opts=opts.TooltipOpts(trigger='axis'),
toolbox_opts=opts.ToolboxOpts(is_show=True),
xaxis_opts=opts.AxisOpts(type_='category', boundary_gap=False))
).render_notebook()
/home/fonttian/anaconda3/envs/keras/lib/python3.8/site-packages/pyecharts/charts/chart.py:14: PendingDeprecationWarning: pyecharts 所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 :)
super().__init__(init_opts=init_opts)
<div id="de7f59fe737e4e3791f71fe974fc4d40" style="width:800px; height:500px;"></div>
groupby_hour = dataframe.groupby(by='hour') # 根据时段分组
hours = [x for x in range(0, 24)]
hours_df = pd.DataFrame(data=None, index=hours, columns=behavior_types)
for h in hours:
hours_df.loc[h] = groupby_hour.get_group(h).type.value_counts()
hours_df['uv'] = [groupby_hour.get_group(hour).userid.nunique() for hour in hours] # 独立访客量
(
Line(init_opts=opts.InitOpts(width="800px", height="500px"))
.add_xaxis(xaxis_data=hours_df.index)
.add_yaxis("pv", y_axis=hours_df['pv'],is_symbol_show=False)
.add_yaxis("cart",y_axis=hours_df['cart'],is_symbol_show=False)
.add_yaxis("fav",y_axis=hours_df['fav'],is_symbol_show=False)
.add_yaxis("buy",y_axis=hours_df['buy'],is_symbol_show=False)
.set_global_opts(
title_opts=opts.TitleOpts(title="用户行为时段分布图",
subtitle="用户行为的时段分布情况"),
tooltip_opts=opts.TooltipOpts(trigger='axis'),
toolbox_opts=opts.ToolboxOpts(is_show=True),
xaxis_opts=opts.AxisOpts(type_='category', boundary_gap=False))
).render_notebook()
/home/fonttian/anaconda3/envs/keras/lib/python3.8/site-packages/pyecharts/charts/chart.py:14: PendingDeprecationWarning: pyecharts 所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 :)
super().__init__(init_opts=init_opts)
<div id="2c999a4679e2411881c8ca4a8c3e675e" style="width:800px; height:500px;"></div>
当日UV、当日平均访问量,当日交易用户数、交易用户比例(当日交易用户数/当日UV),当日ARPU(总交易量/当日UVor活跃用户数)、当日ARPPU(总交易量/当日交易用户数or活跃交易用户量),当日活跃用户数(自定义“活跃”);——用户量变化趋势图
dates_df['uv'] = [groupby_date.get_group(d).userid.nunique() for d in dates] # 每日独立访客量
# 自定义当天使用淘宝app进行5次操作(无论是查看详情页、收藏、加入购物车还是购买都算)的用户就是活跃用户
active_user_standard = 3 # 自定义活跃用户操作次数基准
dates_df['dau'] = [(groupby_date.get_group(d).groupby(by='userid').size()>active_user_standard).value_counts()[True] for d in dates]
dates_df['au_rate'] = dates_df['dau']/dates_df['uv'] # 活跃用户比例
dates_df['buyer'] = dataframe[dataframe['type']=='buy'].groupby(by=['date','userid']).size().count(level=0)
dates_df['buyer_rate'] = dates_df['buyer']/dates_df['uv'] # 付费用户比例
dates_df['ARPU'] = dates_df['buy']/dates_df['uv'] # 人均购买量=总交易量/当日UV
dates_df['ARPPU'] = dates_df['buy']/dates_df['buyer'] # 付费用户人均购买量
dates_df
pv | cart | fav | buy | weekday | uv | dau | au_rate | buyer | buyer_rate | ARPU | ARPPU | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2017-11-25 | 931880 | 56283 | 30168 | 19719 | 6 | 69932 | 50321 | 0.72 | 12960 | 0.19 | 0.28 | 1.52 |
2017-11-26 | 952269 | 59469 | 31281 | 20211 | 7 | 70851 | 51801 | 0.73 | 13408 | 0.19 | 0.29 | 1.51 |
2017-11-27 | 897421 | 55010 | 29723 | 22225 | 1 | 70215 | 50604 | 0.72 | 14367 | 0.20 | 0.32 | 1.55 |
2017-11-28 | 883696 | 54194 | 29002 | 20996 | 2 | 70304 | 50393 | 0.72 | 13862 | 0.20 | 0.30 | 1.51 |
2017-11-29 | 913153 | 55802 | 30030 | 21814 | 3 | 71298 | 51666 | 0.72 | 14295 | 0.20 | 0.31 | 1.53 |
2017-11-30 | 929352 | 56722 | 30469 | 21731 | 4 | 72459 | 52370 | 0.72 | 14418 | 0.20 | 0.30 | 1.51 |
2017-12-01 | 972109 | 62885 | 31048 | 20941 | 5 | 73266 | 53565 | 0.73 | 13983 | 0.19 | 0.29 | 1.50 |
2017-12-02 | 1238785 | 80377 | 40210 | 25868 | 6 | 96072 | 68189 | 0.71 | 17395 | 0.18 | 0.27 | 1.49 |
2017-12-03 | 1225845 | 78390 | 39726 | 25642 | 7 | 95785 | 67360 | 0.70 | 17341 | 0.18 | 0.27 | 1.48 |
(
Line(init_opts=opts.InitOpts(width="800px", height="500px"))
.add_xaxis(xaxis_data=dates_df.index)
.add_yaxis("uv", y_axis=dates_df['uv'],is_symbol_show=False)
.add_yaxis("dau",y_axis=dates_df['dau'],is_symbol_show=False)
.add_yaxis("buyer",y_axis=dates_df['buyer'],is_symbol_show=False)
.set_global_opts(
title_opts=opts.TitleOpts(title="用户量变化趋势",
subtitle="2017/11/25-2017/12/03期间用户量变化趋势"),
tooltip_opts=opts.TooltipOpts(trigger='axis'),
toolbox_opts=opts.ToolboxOpts(is_show=True),
xaxis_opts=opts.AxisOpts(type_='category', boundary_gap=False))
).render_notebook()
/home/fonttian/anaconda3/envs/keras/lib/python3.8/site-packages/pyecharts/charts/chart.py:14: PendingDeprecationWarning: pyecharts 所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 :)
super().__init__(init_opts=init_opts)
<div id="7460f44ab92e45ddb829d5069c3b1d95" style="width:800px; height:500px;"></div>
# 用户活跃天数统计
tmp = dataframe[['userid','date','type']].groupby(by=['userid','date']).count()
user_active_days_df = tmp[tmp['type']>active_user_standard].count(level=0)
sorted_user_active_days_df = user_active_days_df['type'].value_counts().sort_index()
(
Bar(init_opts=opts.InitOpts(width='600px', height='400px'))
.add_xaxis(xaxis_data=list(sorted_user_active_days_df.index))
.add_yaxis("用户活跃天数", y_axis=sorted_user_active_days_df.to_list())
.set_series_opts(label_opts=opts.LabelOpts(is_show=True))
.set_global_opts(title_opts=opts.TitleOpts(title="用户累计活跃天数分布图"),
toolbox_opts=opts.ToolboxOpts(is_show=True))
).render_notebook()
/home/fonttian/anaconda3/envs/keras/lib/python3.8/site-packages/pyecharts/charts/chart.py:14: PendingDeprecationWarning: pyecharts 所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 :)
super().__init__(init_opts=init_opts)
<div id="2915e76f6a714ece89b11fc953eae376" style="width:600px; height:400px;"></div>
用户价值分析——RFM分析(Recency,Frequency,Monetary)
RFM模型通过一个客户的近期购买行为、购买的总体频率以及花了多少钱3项指标来描述该客户的价值状况。
- R(Recency):客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,反之则表示客户交易发生的日期越近。
- F(Frequency):客户在最近一段时间内交易的次数。F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。
- M(Monetary):客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。
本次分析数据集不含金额,因此仅从R、F两个维度进行分析
# R:Recency最近一次交易日期间隔;F:Frequency频率,交易次数
groupby_buy_userid = dataframe[dataframe['type']=='buy'].groupby(by='userid')
# 先创建一个空的DataFrame
RF = pd.DataFrame(index=groupby_buy_userid.groups.keys(), columns=['R', 'F'])
RF['F'] = groupby_buy_userid.type.count()
RF['last_buy_time'] = groupby_buy_userid.time.max()
# 假设获取数据集的第二天进行分析,所以选择2017/12/04为对照日期,保留天数
RF['R'] = (pd.to_datetime('2017-12-04')-RF['last_buy_time']).dt.days
# 最近的一次交易记录距离2017/12/04为0天
# 即12/03购买相差还不到一天,最远的为9天,平均为2.53天
# R我们划分4个区域 0-1,2-3,4-6,7-9,分别得分4,3,2,1
# 交易次数最少为1次最多为93次,平均3次
# 这里的3次分母是所有购买过商品的用户
# 而之前得出的人均购买次数2次分母是所有用户
# F划分4个区域 1,2,3,4+,分别得分1,2,3,4
RF[['R','F']].describe()
R | F | |
---|---|---|
count | 66452.00 | 66452.00 |
mean | 2.53 | 3.00 |
std | 2.41 | 2.88 |
min | 0.00 | 1.00 |
25% | 0.00 | 1.00 |
50% | 2.00 | 2.00 |
75% | 4.00 | 4.00 |
max | 9.00 | 93.00 |
def R_score(x):
if 0 <= x <= 1:
return 4
elif 2 <= x <= 3:
return 3
elif 4 <= x <= 6:
return 2
elif 7 <= x <= 9:
return 1
else:
return 0
def F_score(x):
if x == 1:
return 1
elif x == 2:
return 2
elif x == 3:
return 3
elif x >= 4:
return 4
else:
return 0
# 根据R,F进行评分
RF['R_score'] = RF.R.map(R_score)
RF['F_score'] = RF.F.map(F_score)
RF['R>mean?']=(RF['R_score']>RF['R_score'].mean())*1
RF['F>mean?']=(RF['F_score']>RF['F_score'].mean())*1
def user_classfication(tup):
R_score, F_score = tup
if R_score == 0 and F_score == 1:
return "重要保持客户"
elif R_score == 1 and F_score == 0:
return "重要发展客户"
elif R_score == 1 and F_score == 1:
return "重要价值客户"
elif R_score == 0 and F_score == 0:
return "重要挽留客户"
else:
return None
RF['user_classification'] = RF[['R>mean?','F>mean?']].apply(user_classfication, axis=1)
RF.head()
R | F | last_buy_time | R_score | F_score | R>mean? | F>mean? | user_classification | |
---|---|---|---|---|---|---|---|---|
27 | 2 | 2 | 2017-12-01 16:56:00 | 3 | 2 | 0 | 0 | 重要挽留客户 |
43 | 0 | 6 | 2017-12-03 16:04:17 | 4 | 4 | 1 | 1 | 重要价值客户 |
100 | 5 | 8 | 2017-11-28 09:51:17 | 2 | 4 | 0 | 1 | 重要保持客户 |
117 | 5 | 10 | 2017-11-28 16:09:39 | 2 | 4 | 0 | 1 | 重要保持客户 |
119 | 4 | 3 | 2017-11-29 20:43:31 | 2 | 3 | 0 | 1 | 重要保持客户 |
# 统计用户分类情况
RF.user_classification.value_counts()
重要挽留客户 24819
重要价值客户 17023
重要发展客户 13246
重要保持客户 11364
Name: user_classification, dtype: int64
# 用户分类占比
RF.user_classification.value_counts(1)
重要挽留客户 0.37
重要价值客户 0.26
重要发展客户 0.20
重要保持客户 0.17
Name: user_classification, dtype: float64
根据RFM模型对用户分类后发现重要挽留客户比例最高,其次是重要价值用户,淘宝作为成熟的电子商务平台,重要价值客户达到了一定的比例,在其他电商平台相继发展的大环境下,淘宝应该注重重要挽留客户,但是淘宝目前是中国最受欢迎的电商平台,目前只要保证口碑,适当营销并推出一系列的活动就能稳固部分重要挽留客户,同时,需要提高社群管理的效率,将重要保持客户和重要发展客户转变为重要价值客户,可采取定期发送文案、赠送优惠券等方式。要抓住用户渴望被认同、提升优越感、爱占便宜等心理进行考虑。
商品销售分析
商品统计
分析指标:销量前十的种类categoryid,销量前十的商品itemid
关于“受欢迎”的产品,有的人理解是点击量高,有的人理解是销量高;
但有的点击量高的产品可能是因为被页面或广告等吸引而来,或者只是感兴趣,用户并不一定会购买;而销量高的产品有可能是用户真正需要的,搜索和点击购买的目标也比较明确。
衡量商品的市场情况,最好同时分析点击量和购买量。
groupby_itemid = dataframe.groupby(by='itemid') # 按商品分组
item_type_df = groupby_itemid.type.value_counts().unstack() # 展开为一个dataframe
item_type_df.replace(to_replace=np.nan, value=0, inplace=True) # 缺失值补0
item_type_df = item_type_df.sort_values(by='buy', ascending=False) # 按购买量降序排列
item_type_df['buy_pv_conversion_rate']=item_type_df['buy']/item_type_df['pv'] # 点击到购买的转化率
item_type_df.head(10)
type | buy | cart | fav | pv | buy_pv_conversion_rate |
---|---|---|---|---|---|
itemid | |||||
3122135 | 134.00 | 32.00 | 21.00 | 192.00 | 0.70 |
3031354 | 81.00 | 178.00 | 50.00 | 1827.00 | 0.04 |
2964774 | 76.00 | 71.00 | 15.00 | 712.00 | 0.11 |
1910706 | 69.00 | 13.00 | 5.00 | 164.00 | 0.42 |
2560262 | 61.00 | 136.00 | 27.00 | 1127.00 | 0.05 |
1116492 | 59.00 | 17.00 | 2.00 | 91.00 | 0.65 |
3964583 | 56.00 | 68.00 | 10.00 | 465.00 | 0.12 |
1415828 | 55.00 | 55.00 | 3.00 | 265.00 | 0.21 |
1168232 | 53.00 | 39.00 | 15.00 | 307.00 | 0.17 |
3189426 | 52.00 | 40.00 | 6.00 | 390.00 | 0.13 |
结论:在购买率前十的商品中,可以观察到点击量到购买量的转化率差别巨大。
推测:根据上面购买量前十的商品,可以大致将商品分为三类——
- 转化率极高(0.6,1],该商品也许是特定群体非常需要的,他们搜索和点击的目标比较明确。电商平台可以收集用户信息,分析用户画像,结合商品特点,核实是否如此。如果是某类特征明显的用户群体购买更多,可以集中向该类用户多推送。如果没有明显的群体需求,建议对这类商品多做推广,因为原有的购买量比较高,若是能够提高点击量,可能购买量也会再上一个台阶。
- 转化率一般(0.15,0.6],电商平台应该重点推送该商品,因为该商品有市场,并且可以多做活动,吸引更多的潜在客户变成购买客户。
- 转化率极低(0,0.15],该商品应该首先从商品本身进行分析,部分转化率极低而销量却排在靠前的商品可能通过广告赚取了一定的点击量,但是购买量相对点击量极低可能是因为用户因为广告推广点击了但是这类商品本身不是用户需要的,又或者是价格过高?社会热点造成了炒作营销导致用户好奇的点击?更深的原因需要结合更多的信息进行进一步分析。
groupby_categoryid = dataframe.groupby(by='categoryid')
category_type_df = groupby_categoryid.type.value_counts().unstack()
category_type_df.replace(to_replace=np.nan, value=0, inplace=True)
category_type_df = category_type_df.sort_values(by='buy', ascending=False)
category_type_df['buy_pv_conversion_rate'] = category_type_df['buy']/category_type_df['pv']
category_type_df.head(10)
type | buy | cart | fav | pv | buy_pv_conversion_rate |
---|---|---|---|---|---|
categoryid | |||||
1464116 | 3555.00 | 6316.00 | 2743.00 | 70782.00 | 0.05 |
2735466 | 3529.00 | 9913.00 | 3789.00 | 115530.00 | 0.03 |
4145813 | 3350.00 | 18251.00 | 11456.00 | 326440.00 | 0.01 |
2885642 | 3093.00 | 5853.00 | 3146.00 | 95712.00 | 0.03 |
4756105 | 2944.00 | 23627.00 | 15007.00 | 483732.00 | 0.01 |
4801426 | 2645.00 | 12503.00 | 7087.00 | 189092.00 | 0.01 |
982926 | 2496.00 | 15949.00 | 9062.00 | 286661.00 | 0.01 |
2640118 | 1809.00 | 6236.00 | 1642.00 | 72804.00 | 0.02 |
3002561 | 1744.00 | 8397.00 | 5585.00 | 144378.00 | 0.01 |
1320293 | 1683.00 | 9532.00 | 5348.00 | 177275.00 | 0.01 |
sns.distplot(category_type_df[(category_type_df['buy_pv_conversion_rate']<=1)&(category_type_df['buy_pv_conversion_rate']>0)]['buy_pv_conversion_rate'],
kde=False)
plt.show()
结论:在购买率前十的商品类目中,分布比较集中,基本上转化率集中在(0,0.2]这个区间,而绝大多数转化率在0.1以内。
推测:这类商品转化率低可能因为同一类商品包含很多种商品,用户存在“货比三家”的心理,用户对于需要的该类商品可能不会购买多种商品,而是在该类商品中购买具体的一个商品。
个人思考:对于提高商品类目的转化率,可以考虑优化商品类目所包含的商品对于用户的推荐算法,首先推测用户可能感兴趣的商品类目,然后从用户可能感兴趣的商品类目中推荐有比较性的具体商品,这样可以减少用户比较多个商品来回跳转的点击量,能在更短的时间做出比较并选择需要购买的商品。
帕累托分析
帕累托分析(贡献度分析) → 帕累托法则:二八定律
category_type_df['cumsum'] = category_type_df['buy'].cumsum()
key = category_type_df['buy'].sum()*0.8
category_type_df['class'] = category_type_df['cumsum'].map(lambda x: 'up_80' if x<=key else 'down_20' )
category_type_df['class'].value_counts(1)
down_20 0.92
up_80 0.08
Name: class, dtype: float64
前80%销量有8%左右的商品品类提供,后20%的销量由92%左右的商品品类提供,接近二八定律所表示的由少数商品品类掌控了大部分的销量。
总结
从整体概况来看,用户操作记录购买率占比很低,而在对用户进行漏斗分析后能发现付费用户占比达到了31.32%,这表明淘宝平台用户具有一定粘性,想要提高销售额,就是要想办法提高用户购买率,一方面是促进收藏加购用户朝付费用户的转化,另一方面是促进浏览不购买的用户对商品的兴趣从而促进商品的销量。
一些参考:
分析:
http://www.woshipm.com/data-analysis/4123802.html
https://www.kesci.com/home/project/5df87bc02823a10036aca279
https://zhuanlan.zhihu.com/p/119293836
https://blog.csdn.net/lqq6315/article/details/103224178
https://blog.csdn.net/violette_lx/article/details/104281619
pyecharts绘图:
http://gallery.pyecharts.org/#/README