项目简介
这是一份用户消费行为的分析报告
数据来源于网上,是用户在一家CD网站上的消费记录

CD项目数据分析.png
报告目录
字段名
- user_id:用户ID
order_dt:购买日期
order_prodects:购买产品数
order_amount:购买金额
01 趋势分析
02 用户个体消费分析
03 用户消费行为
04 复购率和回购率分析
观察数据
#导入数据 观察数据
import pandas as pd
import numpy as np
columns=['user_id','order_dt','order_products','order_amount']
df_cd=pd.read_table('CDNOW_master.txt',names=columns,sep='\s+')
df_cd.info()
df_cd.describe()

df_cd describe.png
- 大部分订单只消费了少量商品(平均2.4),有一定值干扰
- 用户的消费金额比较稳定,平均消费35元,中位数在25元,有一定极值的干扰
#添加月份字段
df_cd['order_dt']=df_cd['order_dt'].apply(lambda x:pd.to_datetime(x,format='%Y%m%d'))
df_cd['year_month']=df_cd['order_dt'].apply(lambda x:str(x)[:7])
01 趋势分析
- 每月的消费总金额
- 每月的消费次数
- 每月的产品购买量
- 每月的消费人数
- 每月用户平均消费金额的趋势
- 每月用户平均消费次数的趋势
from matplotlib import pyplot as plt
%matplotlib inline
grouped_month=df_cd.groupby(['year_month'])
#按月分组聚合
month_amount=grouped_month['order_amount'].sum()
# 每月的消费总金额
month_amount.plot()

用户消费总金额趋势图.png
# 每月的消费次数(订单数)
grouped_month_times=grouped_month['user_id'].count()
grouped_month_times.plot()

月订单数趋势图.png
# 每月的产品购买量
month_sumOrder=grouped_month['order_products'].sum()
month_sumOrder.plot()

用户购买产品量趋势图.png
# 每月的消费人数
month_customerNum=grouped_month['user_id'].apply(lambda x:len(x.drop_duplicates()))
month_customerNum.head()
# 每月用户平均消费金额的趋势
month_avg_cus_amount=month_amount/month_customerNum
month_avg_cus_amount.plot()

用户消费金额趋势图.png
# 每月用户平均购买次数的趋势
month_cus_times=df_cd.groupby(['year_month','user_id'],as_index=False) ['order_products'].count()
avg_cus_times=month_cus_times.groupby(['year_month']).\
order_products.sum()/ month_cus_times.groupby(['year_month']).order_products.count()
avg_cus_times.plot()

用户平均购买次数趋势图.png
02 用户个体消费分析
- 用户消费金额,消费次数的描述统计
按照ID 计数 并describe
grouped_id=df_cd.groupby(['user_id']).sum().reset_index()
grouped_id.describe()
用户平均购买了7张CD,但是中位值只有3,说明小部分用户购买了大量的CD
用户平均消费106元,中位值有43,判断同上,有极值干扰
- 用户消费金额和消费数量的散点图
plt.scatter(x=grouped_id.order_products,y=grouped_id['order_amount'])
# 用户消费金额,消费数量的关系(散点图)

消费金额和购买数量关系.png
- 用户消费金额的分布图
直方图
grouped_id[grouped_id['order_amount']<1800]['order_amount'].plot.hist(bins=10)
# grouped_id.query('order_products<100').order_amount.plot.hist(bins=10)
#直接做直方图,绝大部分呈现集中趋势,小部分异常值干扰了判断,可以使用过滤操作排除异常
# 使用切比雪夫定理过滤掉异常值,因为切比雪夫定理说明
# 95%的数据都分布在5个标准差之内,剩下5%的极值就不要了

客户消费金额分布.png
大多数用户购物金额<250元
- 用户消费次数的分布图
直方图
df_cd.groupby(['user_id'])[['order_amount']].count().\
rename(columns={'order_amount':"shopping_times"}).\
query('shopping_times<100').plot.hist(bins=100)

客户消费次数分布.png
只购买过一次的客户占比很大
- 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
类似帕累托图
按照id求和,从小到大排序
累计求和(百分比) 画图
# 用户累计消费金额占比
grouped_id.sort_values(by='order_amount',inplace=True)
grouped_id['cumsum_prop']=grouped_id.order_amount.cumsum()/grouped_id.order_amount.sum()
grouped_id.reset_index()['cumsum_prop'].plot()

用户累计消费金额占比.png
按照用户消费金额进行升序排序,由图可以知道50%的用户仅贡献了15%的消费额度,而排名前5000的用户就贡献了60%的消费额度
03用户消费行为分析
- 用户第一次消费(首购)
#首购
df_min=df_cd.groupby('user_id').order_dt.min()
- 用户最后一次消费
df_max=df_cd.groupby('user_id').order_dt.max()
#最后消费时间
#仅购买一次的客户占比
date_delta[date_delta==0].count()/len(df_min)

一次性消费人数占比.png
50%以上的客户只消费了一次
- 新老客户消费比
- 多少用户仅消费一次
- 每月新客占比
- 用户分层
- RFM模型
df_R=df_cd.groupby('user_id').order_dt.agg([max]).reset_index() # 最近一次购买时间 Resently
df_FM=df_cd.groupby(['user_id'])[['order_amount']]\
.agg(['count','sum']).reset_index() #累计购买次数和购买金额 frequency\monetary
df_RFM=df_R.merge(df_FM,on='user_id')
# 得到最近一次消费,一般是计算 today 距离最近一次消费,这里因为时间太久远,就用的max值
# 数值越大就越久远,分子得到的是一些天数类似 545 days
#(因为是时间格式相减),除以一个单位,就不会有单位了只留下数值
df_RFM['dt_delta']=-(df_RFM['max']-df_RFM['max'].max())/np.timedelta64(1,'D')
# 重命名,也就是 R:最后一次消费距今天数,F:消费总金额 ,M:消费总产品数
# R :消费时间 F:消费金额 M:消费频次
df_RFM.rename(columns={('order_amount', 'count'):'F',\
('order_amount', 'sum'):'M','dt_delta':'R'},inplace=True)
def RFM(x):
level=x.apply(lambda x:'1' if x> 0 else '0')
label=level.R+level.F+level.M
d={
# R 为1 表示离均值较远即时间很久,F为1 表示 消费金额比较多,
#M 为1 表示 消费频次比较多,所以是重要价值客户
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要发展客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'一般挽留客户'
}
return d[label]
df_RFM['label']=df_RFM[['R','F','M']].apply(lambda x:x-x.mean()).apply(RFM,axis=1)
df_RFM.loc[df_RFM['label']=='重要价值客户','color']='g'
df_RFM.loc[~(df_RFM['label']=='重要价值客户'),'color']='r'
# 使用分层的结果画图 并将重要价值客户重点标出
df_RFM.plot.scatter('F','R',c=df_RFM.color)

重要价值客户占比.png
df_RFM['label'].value_counts()/len(df_RFM['label']) #人数占比
df_RFM.groupby('label').sum()/df_RFM.sum() #销售额占比

客户RFM 类别占比及消费额占比.png
从RFM 分层可知,重要保持客户占总客户的20%,却贡献了60% 销售额.
但是这是由于极值的影响,所以 RFM 的划分标准应该以业务为准,也可以通过切比雪夫去除极值后求均值,并且 RFM 的各个划分标准可以都不一样
不要为了数据好看划分等级
- 用户生命周期
- 新、老、活跃、回流、流失
# 数据透视, userid为索引,月为列,求每月的消费次数,这里填充了
pivoted_counts=df_cd.pivot_table(index='user_id',
columns='year_month',
values='order_dt',
aggfunc='count').fillna(0)
pivoted_counts.head()
# 由于本文 定义生命周期 主要在于是否近期有消费 暂时和消费次数无关
# 只要消费就计数为1 不消费计数为0
df_purchase=pivoted_counts.applymap(lambda x: 1 if x>0 else 0)
df_purchase.head()
df_purchase.shape[1]
# x是一个list if的多层嵌套
def user_life(x):
status=[]
for i in range(18):
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
# 定义用户所处的生命周期的阶段
#使用函数 得出用户所处的阶段
purchase=df_purchase.apply(lambda x:pd.Series(user_life(x)),axis=1)
purchase.columns=df_purchase.columns
purchase.head()
# 这里把未注册的替换为空值,这样 count 计算时不会计算到
# 得到每个月的用户分布
purchase_stats_ct=purchase.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_stats_ct.T
#面积图(pyecharts)
from pyecharts.charts import Line
import pyecharts.options as opts
M=purchase_stats_ct.fillna(0).T
c = (
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))
.add_yaxis("unactive", M['unactive'], areastyle_opts=opts.AreaStyleOpts(opacity=0.5))
.set_global_opts(title_opts=opts.TitleOpts(title="Line-面积图"))
)
c.render_notebook()

每月用户分布.png
- 用户购买周期(按订单)
order_diff1=df_cd.groupby('user_id').apply\
(lambda x:x.order_dt-x.order_dt.shift())/np.timedelta64(1,'D')
order_diff1.hist(bins=[0,10,50,100,200,500,600])
# 每次下单的购买周期

订单周期分布.png
order_diff1.describe()
# 用户平均购买周期 (每个用户每次的购买周期相加/次数)

order_diff1 describe.png
订单周期呈指数分布
用户的平均购买周期是68天
绝大部分用户的购买周期都低于100天
- 用户生命周期分布
date_delta.plot.hist(bins=50)
# 用户生命周期(按第一次和最后一次消费)
date_delta.describe()

date_delta describe.png

用户生命周期分布001.png

用户生命周期分布002.png
用户的生命周期受只购买一次的用户影响比较厉害(可以排除)
用户均消费134天,中位数仅0天
# 购买一次的用户后的分布图
date_delta[date_delta>0].hist(bins=40)
4.复购率和回购率分析[]
- 复购率
- 自然月内,购买多次的用户占比(即,购买了两次以上)
# 月内为购买的用户不做数,变成NaN
# 只够买一次的不计数,变为0
pivoted_counts[pivoted_counts == 0]=np.nan
pivoted_counts[pivoted_counts == 1]=0
# 计算复购率 :购买次数>1的人数/月内总人数
repeat_purchase=pivoted_counts.applymap(lambda x: 1 if x>1 else x)
repeat_pur=repeat_purchase.apply(lambda x:x.sum()/x.count())
#复购率趋势图
repeat_pur.plot()

复购率.png
- 回购率
- 曾经购买过的用户在某一时期的再次购买的占比(可能是在三个月内)
df_purchase[df_purchase==0]=np.nan
# 定义函数。月内未下单的客户,变成NaN
# 只要购买过的都为1,因此只要本月下单了次月诶呦下单
def binary(data):
for i in range(0,data.shape[0]):
for j in range(0,data.shape[1]-1):
if data.iloc[i,j]==1:
if data.iloc[i,j+1]!=1:
data.iloc[i,j]=0
return data
如果本月购买的人下月也购买了 说明属于本月的回购人群
repurchase=binary(df_purchase)
repurchaseing=repurchase.iloc[:,:17].apply(lambda x:x.sum()/x.count())
repurchaseing.plot()

回购率.png