项目背景
为了平台创造出更多的利润,并且能够合理的投放广告,使用网站16月以后销售数据进行分析,根据用户个体消费指标和整体用户生命周期等指标以及消费模型得到高价值的用户进行有针对的客户管理和维护。
目的
本项目主要探索以下问题的答案:
- 在addventure平台中,几个大类的销量和销售额的趋势如何?
- 用户个体的消费频次和消费金额的分布情况分别是怎样的?
- 使用RFM模型为给每个用户贴标签,各个用户全体的占比如何?
- 每月的用户构成是怎样的,同期用户的留存率如何?为什么活跃用户越来越少?
- 用户的生命周期分布是怎样的?购买周期又是如何分布的?
数据探索
在这个项目中,数据是从adventure数据库中获取的MySQL数据,数据本身相对完整,不需要再进行数据深度处理。
本项目采用Python作为分析工具对数据进行分析和处理。
建立一个IPython文件来编写代码,首先应当导入本项目中可能用到的库,比如Pandas,matplotlib, seaborn等,代码如下:
import pandas as pd
import numpy as np
from datetime import datetime
from sqlalchemy import create_engine
import pymysql
from matplotlib import pyplot as plt
import seaborn as sns
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.style.use('ggplot')
然后需要对数据本身有个大致的了解。利用pandas的read_sql方法读取数据,并将前几行数据打印出来,还可以使用info()方法观察数据的整体状况:
## 导入数据
dic={'host':'127.0.0.1',
'user':'root',
'port':3306,
'password':'root',
'database':'adventure'}
con=pymysql.connect(**dic)
sql="select * from orderCustomer_mdx"
df_order=pd.read_sql(sql,con)
df_order.head()
df_order.info()
RangeIndex: 197313 entries, 0 to 197312
Data columns (total 17 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 index 197313 non-null int64
1 sales_order_key 197313 non-null int64
2 create_date_x 197313 non-null object
3 customer_key 197313 non-null object
4 product_key 197313 non-null object
5 english_product_name 197313 non-null object
6 cpzl_zw 197313 non-null object
7 cplb_zw 197313 non-null object
8 unit_price 197313 non-null float64
9 create_date_y 197313 non-null object
10 birth_date 197313 non-null object
11 gender 197313 non-null object
12 marital_status 197313 non-null object
13 yearly_income 197313 non-null object
14 province 197313 non-null object
15 city 197313 non-null object
16 chinese_territory 197313 non-null object
dtypes: float64(1), int64(2), object(14)
memory usage: 25.6+ MB
可以看到,数据集中共有16个字段,197313条记录。字段包括订单号、产品价格、品类(cpzl_zw)、大类(cplb_zw)、顾客ID、顾客所在地区、省市等;
其中create_date_x 是订单日期,create_date_y是用户注册日期;
参考前面我所关注的几个问题,在数据集中customer_key,cplb_zw, unit_price, create_date_x这几个字段将是我重点关注的字段。我将对这几个字段信息进行探索和分析。数据集中不存在字段缺失情况,因而可以直接分析数据。
第一个问题:在addventure平台中,几个大类的销量和销售额的趋势如何?
侧重整体销售情况
为了更加直观的查看分布情况,我使用matplotlib库对数据进行可视化。
具体步骤如下:
- 使用Pandas的groupby()方法对数据按照月分组;
- 使用Pandas的sum()和count() 方法对每组进行金额汇总及销量计数;
- 使用Pandas的plot()方法绘制图形。
2020-5数据不完整,仅供参考
# 趋势要按月观察,因此需要引入年月字段,并按月份聚合
df_order['year_month']=df_order.create_date_x.apply(lambda x:str(x)[:7])
#按月份和大类分组并计算每月销售额
a=df_order.groupby(['year_month','cplb_zw'],as_index=False
)['unit_price'].sum()
#按月份和大类分组并计算每月销售量
c=df_order.groupby(['year_month','cplb_zw'],as_index=False
)['unit_price'].count()
fig,ax=plt.subplots(1,2,figsize=(12,4))
plt.subplots_adjust(wspace =0.2, hspace =0.7)
for i in ['服装','自行车','配件']:
b=a[a['cplb_zw']==i]
ax1=b.plot('year_month','unit_price',label=i,ax=ax[0])
ax1.title.set_text('大类产品销售额趋势图')
x = list(b.year_month)
x.insert(0,0)
x.insert(1,1)
label=x[1::2]
ax1.set_xticklabels(x[::2],rotation=-45)
ax1.axhline(5700000,ls='--')
ax1.annotate(xy=(5,5700000),xytext=(3,4500000),s="570万参考线",size=12,bbox=dict(boxstyle="round", fc="0.8"),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle3,angleA=0,angleB=-90", color='blue'))
ax1.set_xlabel('时间')
ax1.set_ylabel('金额')
plt.legend()
# 由于和自行车的销售额数量级差异大,服装和配件的销售额显示不清楚,因此这两个单独成图观察
for i in ['服装','配件']:
b=a[a['cplb_zw']==i]
ax2=b.plot('year_month','unit_price',label=i,ax=ax[1])
x = list(b.year_month)
x.insert(0,0)
x.insert(1,1)
label=x[1::2]
ax2.set_xticklabels(x[::2],rotation=-45)
ax2.set_xlabel('时间')
ax2.set_ylabel('金额(元)')
plt.title('配件/服装销售额趋势图')
plt.legend()
fig,ax=plt.subplots(1,1,figsize=(12.5,4))
for i in ['服装','自行车','配件']:
b=c[c['cplb_zw']==i]
plt.plot(b.year_month,b.unit_price,label=i)
plt.xticks(rotation=-45)
plt.title('大类产品销量趋势图')
plt.xlabel('时间')
plt.ylabel('销量(件)')
plt.legend()
No handles with labels found to put in legend.
No handles with labels found to put in legend.
No handles with labels found to put in legend.
上面的图形清楚的展示了三个大类产品的销售额趋势和销售量趋势情况:
- 自行车的销售额在570万/月左右。配件和服装的销售额分别在14万/月和7万/月左右;
- 销量方面:配件:自行车:服装=7.5 : 3 : 2;
- 配件在销量方面占绝对优势,但销售额远小于自行车类。这是由于配件和服装的单价小,而自行车的单价比较高;
不难看出Adventure公司主营业务是自行车,配件类产品销量最高,整体销售量不存在明显的季节性影响;
第二个问题:用户个体的消费频次和消费金额的分布情况分别是怎样的?
具体的执行步骤是:
- 使用Pandas的groupby()方法对数据按照性别分组;
- 使用Pandas的count()和sum() 方法对每组进行计数;
- 使用Pandas的describe() 方法观察描述性统计情况;
- 使用Pandas的hist()方法绘制频次和消费金额分布图。 代码如下:
grouped_user=df_order.groupby('customer_key') # 根据用户id聚合
consume_times=grouped_user['create_date_x'].agg('count') # 计算每个用户的消费次数
consume_times.describe()
count 173261.000000
mean 1.138819
std 0.419065
min 1.000000
25% 1.000000
50% 1.000000
75% 1.000000
max 10.000000
Name: create_date_x, dtype: float64
# 用户的消费金额描述性统计
grouped_user['unit_price'].sum().describe()
# ** 从这个结果中,我们可以得出以下几个结论:**
count 173261.000000
mean 557.398775
std 1016.186028
min 2.290000
25% 8.990000
50% 34.990000
75% 564.990000
max 10734.810000
Name: unit_price, dtype: float64
从上面输出的结果中已经可以明显看到,用户人数共计173261人
- 至少有75%的人 仅仅消费过一次;
- 人均消费次数1.14次;
- 用户群体庞大,然而消费者回头率很低;
- 50%的用户,其消费金额不足35元;
- 用户平均消费金额557元,而标准差则去到1016元;这表明用户的消费金额差异很大;
接下来为了更直观查看用户的消费频次和金额分布,以及消费帕累托图,我使用matplotlib进行可视化:
fig,ax=plt.subplots(1,2,figsize=(12,4))
# ax1,ax2 分别表示所有用户的消费频次分布和 回购用户的消费频次分布
ax1=consume_times.hist(bins=[0,1,2,3,4,5,6,7,8,9,10,11],ax=ax[0],color='steelblue')
ax1.title.set_text(' 图a. 用户消费频次分布图')
ax1.set_xlabel('消费次数',size=12)
ax1.set_ylabel('人数',size=12)
ax2=consume_times[consume_times>1].\
hist(bins=[1,2,3,4,5,6,7,8,9,10,11],ax=ax[1],color='forestgreen')
ax2.title.set_text('图b. 回购用户消费频次分布图')
ax2.set_xlabel('消费次数',size=12)
ax2.set_ylabel('人数',size=12)
fig,ax=plt.subplots(1,2,figsize=(12,4))
ax3=grouped_user['unit_price'].sum().hist(bins=[0,50,100,200,500,1000,1500,\
2000,2500,3000,3500,4000,5000,\
6000,7000,8000,10000],ax=ax[0],
color='orange'
)
ax3.set_xlabel('消费金额',size=12)
ax3.set_ylabel('人数',size=12)
ax3.title.set_text('图c. 用户消费金额分布图')
# 用户消费金额占比帕累托图;即用户按照消费金额由大到小排序,计算累加金额占总金额的百分比
ax4=pd.DataFrame(grouped_user['unit_price'].sum().
sort_values(ascending=False)).\
apply(lambda x:x.cumsum()/x.sum()).\
reset_index().plot( ax=ax[1])
ax4.title.set_text('图d. 用户累计消费占比图')# 设置子图标题
ax4.set_xlabel('人数',size=12)
ax4.set_ylabel('消费金额占比',size=12)
ax4.axhline(0.9,ls='--') #设置参考线
ax4.axvline(37000,ls='--')
ax4.annotate(xy=(37000,0.4),xytext=(75000,0.2),s="3.7万人参考线",\
size=12,bbox=dict(boxstyle="round", fc="0.8"),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle3,angleA=0,angleB=-90",
color='blue')) #添加标注
ax4.annotate(xy=(75000,0.9),xytext=(100000,0.6),s="消费额占比90%参考线",\
size=12,bbox=dict(boxstyle="round", fc="0.8"),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle3,angleA=0,angleB=-90",
color='blue')) #添加标注
ax4.annotate(xy=(37000,0.9),xytext=(-1000,0.70),s="坐标\n(37000,\n0.9)",\
size=12,bbox=dict(boxstyle="round", fc="0.8"),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle3,angleA=0,angleB=-90",
color='blue')) #添加标注
plt.scatter(37000, 0.9, color='', marker='o', edgecolors='b', s=200)
从上面四幅图中可以更直观的显示出:
- 约85%以上的用户仅仅消费一次;
- 去除只消费一次的客户 发现约有10%的顾客消费两次;
- 消费金额的人数分布集中在消费额50以内(65%以上),其次是2000以上。差距明显,原因可能是:
- 消费总额和购买总量都集中刚在低段,长尾分布,这个跟用户需求有关;
- 结合上文三个产品的销量来看,显然2000—2500的消费产品主要是自行车类;
- 可以对商品进行多元文化价值的赋予,增强其社交价值属性,提高用户的价值需求;
- 按照用户消费金额进行升序排序,计算累计金额占总金额的百分比。由图d可以知道排名前37000(21%)的用户就贡献了90%的消费额度,而80%的用户仅贡献了约10%的消费额度,这表明:
- 高质量用户贡献突出,但是由于自行车的本身非消耗品的特性,高质量用户若短期回流很可能是购买自行车配件类产品。
- 开发新客户时,应注重自行车类产品高质量客户的开发。需要专门为此类用户优化购物体验,比如专线接听、特殊优惠等等。
第三个问题:使用RFM模型为给每个用户贴标签,各类用户的占比如何?各类人群的侧重品类是怎样的?
本项目RFM模型分层是根据平均值做分界线区分的:
R:最近一次消费时间,F:消费频次,M:消费金额
- RR>0 表示该用户很久未消费,时间差超过平均值(不好的迹象)
- F>0 表示用户的消费频率超过均值1.13次 (好迹象)
- M>0 表示用户的消费金额超过均值557元 (好迹象)
time_delta=grouped_user['create_date_x'].agg(['max','min'])
#R 最近一次消费
#F 消费频次
#M 消费金额
## 只用pivot_table 得到每个用户最近一次消费时间、总的消费次数、总消费金额
RFM=pd.pivot_table(df_order,index='customer_key',
values=['create_date_x','product_key','unit_price'],
aggfunc={'create_date_x':'max','product_key':'count','unit_price':'sum'})
## 重命名字段
RFM_layer=RFM.rename(columns={'create_date_x':'R','product_key':'F','unit_price':'M'})
# 最近一次消费时间-用户最后一次的消费时间 代表 距今的消费时间,RR越大,代表最近一次消费时间越早,越可能流失
RFM_layer['RR']=-(RFM_layer.R-RFM_layer.R.max())/np.timedelta64(1,'D')
def RFM_model(df):
# df.apply(lambda x:x-x.mean())
level=df.apply(lambda x:'1' if x>=0 else '0')
label=level['RR']+level['F']+level['M']
#RR>0 表示该用户很久未消费,时间差超过平均值(不好的迹象)
# F>0 表示用户的消费频率超过均值 (好迹象)
# M>0 表示用户的消费金额超过均值 (好迹象)
dic={
'111':'重要价值客户', #很久未消费,其他都很好
'011':'重要保持客户', #各方面都很好
'101':'重要发展客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'一般挽留客户'
}
return dic[label]
RFM_layer['lab']=RFM_layer[['RR','F','M']].apply(lambda x:x-x.mean()).apply(RFM_model,axis=1)
fig,ax=plt.subplots(1,2,figsize=(12,4))
plt.subplots_adjust(wspace =0.3, hspace =0.7)
# 各种标签的人数占比
ax1= RFM_layer.lab.value_counts().plot.pie(autopct='%1.2f%%',ax=ax[0])
ax1.title.set_text('图1. 不同标签的人数占比')
# 要观察不同标签的人群的消费侧重情况,即不同标签人群消费大类的数量,需要和df_order做联结
# 然后 根据标签和大类分组后计数
df_layer=RFM_layer.merge(df_order,on='customer_key')
lab_value=df_layer.groupby(['lab','cplb_zw'],as_index=False)['R'].count()
# 使用seaborn画簇状图——不同标签消费大类的数量
ax2=sns.barplot(x='lab',y='R',hue='cplb_zw',data=lab_value,ax=ax[1])
ax2.title.set_text('图2. 不同标签消费大类的数量')
ax2.set_xlabel('标签类别',size=12)
ax2.set_ylabel('消费数量',size=12)
plt.xticks(rotation=-20)
fig,ax=plt.subplots(1,1,figsize=(11,4))
sns.scatterplot('F','M',hue='lab',data=RFM_layer)
plt.title("不同标签用户消费频率和消费金额关系散点图")
Text(0.5, 1.0, '不同标签用户消费频率和消费金额关系散点图')
1、从饼图可以看出一般发展和挽留客户占比可达到68%以上,而重要保持客户仅占比2.73%,整体看 用户群体不够优质,可能是依靠电商的'长尾理论'经营
2、从"不同标签消费大类的数量"一图中可以看出:一般发展和挽留客户的主要消费品类是配件,其次是服装类,而越重要的客户,越偏重自行车类消费
3、重要挽留和重要发展客户的消费频率都在平均值1.138819以下,这说明只购买自行车的人很可能只消费一次,结合簇状图观察,其原因可能是:
- 对于重要发展客户,目标产品是自行车,自行车的生命周期比较长,短期内无需更换,因而很难回头购买类似的自行车产品
- 对于重要挽留客户,已经入手了自行车,RR还在最近一次购买时间差的平均范围之内,是有可能转化成重要价值和重要保持客户的,可以采取一定的激励或者优惠措施吸引该部分用户回购;
4、如何挽留重要挽留客户和重要发展客户呢?品类方面主要是增加服装类和配件类的回购,保持用户粘性
- 自行车以旧换新优惠
- 针对自行车客户推送购物券或积分,过期作废
- 针对自行车客户配件和服装类产品折扣优惠等
5、通过散点图和大类数量图可以看出 重要价值客户和重要保持客户的消费习惯相似,不同的是最近一次购买时间距离现今太久,如何挽回重要价值客户呢? 这需要其他数据的支持
- 首先判断这部分客户是否流失了。流失标准是什么?明确是否流失;
- 如果是流失,那么他们是不是集中在某个时间段流失的?有没有过投诉或纠纷?最后停留在哪个浏览页面呢?
- 判定是否流失后,判断用户是否值得挽回
- 若值得挽回:判断用户流失的原因可否是可恢复的;是否可以通过召回、奖励或新产品吸引用户回流;
- 通过以上分析,对流失原因可恢复造成的值得挽回的用户,通过相应的方式进行挽回;
第四个问题:每月的用户构成是怎样的,同期用户的留存率如何?
- 要回答这个问题,我们首先要对用户分类(新用户、回流用户、活跃用户)
- 那么要定义好什么是活跃用户,什么是回流用户:
- 本项目活跃定义:连续两个月有消费记录为活跃
- 不活跃:已有消费记录,但在某月未消费,则用户在该月不活跃
pivoted_counts=df_order.pivot_table(index='customer_key',
columns='year_month',
values='unit_price',
aggfunc='count').fillna(0)
# 定义函数,贴标签:未注册、新用户、回流用户、活跃用户和不活跃用户
def aarrr(x):
status=[]
for i in range(17):
if x[i]==0:
if len(status)>0:
if status[i-1]=='unreg':
status.append('unreg')
else:
status.append('unactive')
else:
status.append('unreg')
else:
if len(status)>0:
if status[i-1]=='unreg':
status.append('new')
else:
if status[i-1]=='unactive':
status.append('return')
else:
status.append('active')
else:
status.append('new')
return status
# 无论在该月购买了几次,只要购买就记1次,没有购买就记为0
df_purchase=pivoted_counts.applymap(lambda x: 1 if x>0 else 0)
# 使用上述的自定义函数,得到AARRR模型表
aarrr=df_purchase.apply(lambda x:pd.Series(aarrr(x)),axis=1)
aarrr.columns=df_purchase.columns
fig,ax=plt.subplots(1,2,figsize=(12,4))
plt.subplots_adjust(wspace =0.3, hspace =0.7)
# 各种标签的人数占比
# 将未注册的用户标记为NaN,这样合计每月人数时,未注册用户不会计算在内
status_count=aarrr.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
ax1=status_count.T.iloc[:,:3].plot.bar(stacked=True,ax=ax[0])
ax1.title.set_text('每月消费人群构成堆积图')
ax2=status_count.fillna(0).T.plot.area(ax=ax[1])
ax2.title.set_text('各类消费人群趋势图')
从上图的柱状图可以观察到每月新用户居多,回流用户和活跃用户占极少数;
而从面积图上可以看出,每月不活跃用户直线上升,新用户中的80~90%转化成为不活跃用户
由于不活跃用户的数量级比较大,其他用户的消费趋势显示的不明显,我使用pyecharts模块画交互式面积图来观察其他三类用户的趋势:
from pyecharts.charts import Line,Grid
import pyecharts.options as opts
M=status_count.fillna(0).T
c1 = (
Line()
.add_xaxis(M.index.to_list())
.add_yaxis("active", M['active'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
.add_yaxis("new", M['new'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
.add_yaxis("return", M['return'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5),
itemstyle_opts=opts.ItemStyleOpts(color='blue'))
.add_yaxis("unactive", M['unactive'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
.set_global_opts(title_opts=opts.TitleOpts(title="各类人群消费趋势图"),
xaxis_opts=opts.AxisOpts(name='月份',name_location = 'center',name_gap = 28,),
yaxis_opts=opts.AxisOpts(name = '人数',name_location = 'center',name_gap = 45,))
)
#### 由于不活跃的人数数量级大,其他三类标签的趋势不明显。因此将之去除,单独观察其他三个标签的趋势
c2 = (
Line()
.add_xaxis(M.index.to_list())
.add_yaxis("active", M['active'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
.add_yaxis("new", M['new'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
.add_yaxis("return", M['return'], areastyle_opts=opts.AreaStyleOpts(opacity=0.3),
itemstyle_opts=opts.ItemStyleOpts(color='blue'))
.set_global_opts(title_opts=opts.TitleOpts(title="各类人群消费趋势图"))
.set_global_opts(
title_opts=opts.TitleOpts(title=" "),
legend_opts=opts.LegendOpts(type_="scroll", pos_top='3%'),
xaxis_opts=opts.AxisOpts(name='月份',name_location = 'center',name_gap = 35,),
yaxis_opts=opts.AxisOpts(name = '人数',name_location = 'center',name_gap = 45,)
) #设置图例的位置
)
# 将两个图合并到一起
grid = (
Grid()
.add(c1, grid_opts=opts.GridOpts(pos_top='10%', pos_bottom="55%"))#从下往上压缩
.add(c2, grid_opts=opts.GridOpts(pos_top='55%'))#从上往下压缩
)
grid.render_notebook()
可以观察到
1、每月新客数量平稳增加,老客回流也稳定在1200左右,但是活跃客户数量不断下降;
2、 不仅活跃人数一路下降,虽然老客回流稳定,其实也算是变相的老客流失。因为新客是稳定增加的,回流用户不但没有大幅增长,还在某个区间波动,这算是变相流失了。
为了便于查看是否流失,我们看一下同期群的留存率:
# 按照时间顺序,提取出月份
ls=df_order.sort_values(by='create_date_x').year_month.unique()
l=[] #定义一个空列表 放留存率
m=[] #定义一个空列表 放留存数
for i in ls:
re={} # 定义一个空字典 放留存率
return_num={} # 定义一个空字典 放留存数
present_order=df_order[df_order['year_month']==i]
history_order=df_order[df_order['year_month']i] #未来订单数据
new_customer=present_order.loc[present_order['customer_key'].
isin(history_order['customer_key'])==False,:]#本月新增顾客数
# re['新增用户']=new_customer.customer_key.nunique()
#(由于新增和留存不是同一数量级,热力图对留存的数量显示的颜色相同导致无法区分。前文也已经观察到每月新增稳定,因此这里去除新增数)
future_month=future_order.sort_values(by='create_date_x').year_month.unique()
for j,k in zip(future_month,range(1,len(future_month)+1,1)): #读取唯一月份前,务必先排序
hj_customer=df_order[df_order['year_month']==j]
#未来每个月的订单数据中有当月的,就表示当月客户在未来月份的留存
history_customer=hj_customer.loc[hj_customer['customer_key'].
isin(new_customer['customer_key'])==True,:]
re['+%d月留存率'%k]=history_customer.customer_key.nunique()/new_customer.customer_key.nunique() #将未来每月的留存率都存到字典re中
return_num['+%d月留存数'%k]=history_customer.customer_key.nunique() #将未来每月的留存数都存到字典return_num中
l.append(pd.DataFrame(re,index=[i])) #将每个月的 未来几个月的留存放入列表中,将该月份作为index
m.append(pd.DataFrame(return_num,index=[i]))
group_l=pd.concat(l)
group_m=pd.concat(m)
# 使用seaborn画热力图观察留存率情况
from matplotlib.colors import ListedColormap
fig=plt.figure(figsize=[15,5])
sns.heatmap(group_l,cmap=ListedColormap(
['fuchsia','gainsboro','ghostwhite','gold','goldenrod','gray',
'green','greenyellow','honeydew','hotpink'] ), annot=True)#annot 标注显示
plt.title('留存率热力图')
Text(0.5, 1, '留存率热力图')
从同期群的留存情况可以看出,从2019年1月份开始,客户的次月留存率就持续下降,从开始的9% 下降到3月份的次月留存0.75%
- 2020年1月份的次月留存率(0.89%)甚至少于2019年1月第15月的留存率(1.6%) 5月数据不完整,因此2020-05月留存数据仅作参考
从留存率图和各类人群消费趋势图可以观察到:次月留存率在不断下降,活跃人数也在不断下降,那这两者有关联吗?
将每月的活跃人数和每月的上月新客留存人数取出作图,查看二者是否存在关联:
return_number=group_m.shift()
# status_count.T[['active']] 每月的活跃人数
# return_number.iloc[:,[0]] 上个月的新增客户在本月的留存数
retention_active=pd.merge(status_count.T[['active']],return_number.iloc[:,[0]],left_index=True,right_index=True)
fig,ax=plt.subplots(1,2,figsize=(9,4))
plt.subplots_adjust(wspace =0.2, hspace =0.7)
ax1=retention_active.plot(ax=ax[0])
ax1.title.set_text('次月留存数与活跃人数时间变化趋势图')
ax1.set_ylabel('人数')
retention_active.plot(x='+1月留存数',y='active',ax=ax[1])
plt.title('次月留存数与活跃人数关系图')
plt.xlabel('上月新客在本月留存数')
plt.ylabel('活跃人数')
Text(0, 0.5, '活跃人数')
留存下降的原因有哪些?
- 人:客服售后服务意识不够?人手不足?技巧不熟练?态度、投诉情况、客户满意度调查如何? 顾客层面,考虑是否获取的客户不够优质
- 货:产品是否有质量问题,是否流行风向变化?落地页设置是否有问题?转化页是否指示流程不清晰?老顾客活动的各渠道信息打开率如何?
- 场:基本盘是怎样的?竞争对手的用户留存趋势如何?竞对的销售策略有无调整?
- 各个渠道的留存是怎样的,哪个渠道做得最好?做得最好的渠道,它的ROI和时间成本是怎样的?能否作为标杆,有没有复制的可能?
活跃顾客数下降有哪些原因?
- 首先:活跃顾客下降是一个非突发、无季节性、持续性的状况;
- 其次:次月留存率同样在不断下降;
- 通过对比次月留存率和活跃客户数并做图“次月留存数与活跃人数关系图”可以发现两者有直接关系;
- 因为此处活跃的定义是:连续两个月有购买记录,那么次月留存率高,表示连续两月有购买记录的人较多,这说明次月留存直接影响了活跃人数;
- 而且19000多个回购用户中约有17000的用户仅购买两次,这也不难解释为什么次上面两图中次月留存和活跃人数有明显线性关系了;
- 留存和活跃息息相关,想要提升活跃,必须先提升留存,减少用户流失,再提升用户消费频率;
怎样提升留存 主要还是针对问题寻找答案。
- 1、要检讨是不是获客的质量不高,要在新增用户的数量和质量之间求取平衡,整体上努力做好新客数量和质量的平衡,以及老客重复购买的平衡
- 2、客服问题:保证人手充足,增加客服培训,控制新人和经验丰富的人员比例,设定客服的投诉KPI指标和奖励;
- 3、获客问题:客户不优质,是否渠道问题?对标杆渠道进行分析,看可否通过加大执行或者改进执行进行提升;
- 4、产品问题:质量问题:改进,召回,补偿,页面改版、页面调整;风向变化:探索新的需求
- 5、竞对问题:同行是怎样做的?可否作为标杆?哪些可以为我所用?
留存下降,每个月的人均消费有什么变化吗?将人均消费趋势可视化:
# 按照月份和用户ID聚合
month_user=df_order.groupby(['year_month','customer_key'],\
as_index=False)['unit_price'].agg({'unit_price':'sum'})
#准备画图
fig=plt.figure(figsize=(8,6))
month_user.groupby(['year_month']).\
apply(lambda x:x['unit_price'].sum()/x['customer_key'].count()).plot()
plt.xticks(rotation=-45)
plt.ylabel('人均消费额')
plt.title('月人均消费金额')
# 添加参考线和参考的标记
plt.axhline(495,ls='--')
plt.annotate(xy=(5,495),xytext=(3,510),s="495参考线",size=14,bbox=dict(boxstyle="round", fc="0.8"),
arrowprops=dict(arrowstyle="->",
connectionstyle="angle3,angleA=0,angleB=-90", color='blue'))
Text(3, 510, '495参考线')
从上图可以看出每月的人均消费从550元跌至495元上下波动。
从前文的“大类产品销售量趋势图”一图中可以看出,自行车的销量在3000-3300之间波动,而配件的销量在7000-8000间波动(有回购的人群中配件的销量最多)。因此自行车种类的销量提升速度小于配件类的销量提升,导致低价产品拉低了人均消费额。
因此拉新要注重提升自行车类的产品购买人数,而留存和回流要注重提升配件类和服装类的销售;
对自行车类产品要针对目标人群大力推广:
提高自行车产品知名度 增加品牌竞争力
1、加大广告投入,传递令人难以忘却的品牌信息或押韵的标语,曝光品牌标志,增强消费者购买信心的记忆、体验和印象使其产生强烈的品牌联想;
2、赞助比赛;
3、可以联合其它企业举办一些有意义的活动;
创造自行车产品需求
1、采取传统的促销策略,如折价券,产品展示,示范表演等;
2、组织一些区域性的自行车体验赛,让大众亲身感受产品;
3、通过概念性广告或宣传册给消费者植入“健康、环保、快乐”等观念,以体现产品的必须性;
第五个问题:用户的生命周期分布是怎样的?购买周期又是如何分布的?
这里分别按照订单和用户区分计算了购买周期的分布情况和描述性统计
# 计算初次订单和末次订单的时间差 得到生命周期 (时间差为0 表示仅消费一次)
time_delta=grouped_user['create_date_x'].agg(['max','min'])
date_delta=(time_delta['max']-time_delta['min'])/np.timedelta64(1,'D')
date_delta.describe()
count 173261.000000
mean 15.730995
std 57.631400
min 0.000000
25% 0.000000
50% 0.000000
75% 0.000000
max 485.000000
dtype: float64
# 75%以上的顾客进消费一次,为了查看有回购顾客的情况,排除消费一次的顾客查看描述性统计
date_delta[date_delta>0].describe()
count 19953.000000
mean 136.599409
std 111.044766
min 1.000000
25% 43.000000
50% 110.000000
75% 208.000000
max 485.000000
dtype: float64
- 173261人中,消费两次及以上的人数只有19953,占总人数的11.5%,即88.5%的用户只消费一次。
fig,ax=plt.subplots(1,2,figsize=(12,4))
plt.subplots_adjust(wspace =0.3, hspace =0.7)
ax1=date_delta.plot.hist(bins=50,ax=ax[0])
ax1.title.set_text('生命周期分布图-1')
ax1.set_xlabel('生命周期')
ax1.set_ylabel('人数')
#由于绝大多数人指只购买一次,因此去除该部分客户
ax2=date_delta[date_delta>0].plot.hist(bins=25,ax=ax[1])
ax2.title.set_text('生命周期分布图-2')
ax2.set_xlabel('生命周期')
ax2.set_ylabel('人数')
Text(0, 0.5, '人数')
- 有二次及以上消费的用户的平均生命周期是136天,50%的顾客生命周期小于110天
- 生命周期的标准差很大,数据偏左,即生命周期偏短的顾客居多
- 用户的生命周期分别在20天内与20至200天间,应该在20天内对客户进行引导,促进其再次消费并形成消费习惯,延长其生命周期;在20至200天的用户,也要根据其特点推出有针对性的营销活动,引导其持续消费。
可以看到有回购的用户其大类消费占比和整体用户的消费情况基本一致
#先将订单日期转化为日期格式
df_order['create_date_x']=pd.to_datetime(df_order['create_date_x'],format = '%Y-%m-%d')
# 计算相邻两个订单的时间间隔,按照ID和日期排序,用shift 函数对数据进行错位,所有数据会往下平移一下
# 相减便得到日期差
order_diff1=df_order.sort_values(by=['customer_key','create_date_x']).\
groupby('customer_key').apply(lambda x:(x.create_date_x-x.create_date_x.shift()))
order_diff1=order_diff1/np.timedelta64(1,'D')
# 按照用户ID聚合并计算平均购买周期
order_diff1.groupby(level=0).mean().dropna().head()
order_diff1.describe()
# 按照订单的描述性统计
count 24052.000000
mean 113.319807
std 103.179123
min 0.000000
25% 29.000000
50% 82.000000
75% 174.000000
max 485.000000
Name: create_date_x, dtype: float64
order_diff1.groupby(level=0).mean().\
dropna().describe()
# 按照用户的描述性统计
count 20231.000000
mean 118.611324
std 100.561583
min 0.000000
25% 37.000000
50% 92.500000
75% 176.000000
max 485.000000
Name: create_date_x, dtype: float64
fig,ax=plt.subplots(1,2,figsize=(12,4))
plt.subplots_adjust(wspace =0.2, hspace =0.7)
# 准备画图
ax1=order_diff1.groupby(level=0).mean().\
dropna().hist(ax=ax[0])
ax1.title.set_text('各用户的平均购买周期分布')
ax1.set_xlabel('天数',size=12)
ax1.set_ylabel('人数',size=12)
## 每次下单的购买周期 按订单算
ax2=order_diff1.hist(ax=ax[1] )
ax2.title.set_text('各订单的购买周期分布')
ax2.set_xlabel('天数',size=12)
ax2.set_ylabel('订单量',size=12)
# # order_diff1.groupby(level=0).mean().\
# # dropna().hist(bins=[0,20,50,80,100,130,
# # 160,200,250,300,350,400,450,500])
# # 每个用户的平均购买周期
# plt.title('各用户的平均购买周期分布-2')
Text(0, 0.5, '订单量')
- 在回购的这19953人中,回购天数在100天以内的人数约10000+,即50%以上的人在100天内回购
- 用户的购买周期均值和订单购买周期的均值差别不大
- 所有订单的平均回购周期是113天
- 二次消费的订单中,50%订单的回购周期在82天以内,因此在订单下单后60-80天内,可以对客户刺激引导,促进客户再次消费。
- 比如:建立用户流失预警,短期内评分获得积分,40天发放满减券,70天提醒优惠券使用等方式刺激用户再度消费
分析总结
此项目使用pandas库对数据进行了整理和计算,并使用matplotlib库的pyplot模块、seaborn模块和pyecharts模块将数据可视化。
通过对数据的计算和对图形的观察,顺利的解决了在项目开始时提出的五个问题。但是需要说明的是,本项目中进行的分析仅仅是从数据本身展现出来的情况进行的,仅仅能表明数据之间的相关关系。
在所有的分析结论中,数据之间的因果关系或者逻辑关系,仅仅是一种合理推测,并非严格的统计论证。 本项目仅初步探索Adventure公司的用户消费频次分布、消费金额分布以及不同用户群体的消费习惯和用户的整体构成及留存情况,探讨了影响流失和留存的部分因素,以及可能的提升留存的方法,并未进行更加深入的挖掘。实际工作中影响因素可能会更为复杂,数据也会更庞大,可以从更多维度和角度分析。