数据背景:用户在一家CD网站的消费记录,仅包含4列,不确定是具体是哪类数据
使用工具:jupyter
0、数据准备
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
导入所需包
columns =['user_id','order_dt','order_products','order_amount']
df = pd.read_table('CDNOW_master.txt',names=columns,sep='\s+')
df.head()
数据仅包含四列
user_id:用户ID
order_dt:购买日期
order_prodects:购买产品数
order_amount:购买金额
df.describe()
数据描述 根据数据面熟结果,75%的客户的购买量在3件以内,购买金额也较低,符合一个普通CD店的消费习惯分布
df['order_dt'] = pd.to_datetime(df.order_dt,format='%Y%m%d')
df['month'] = df.order_dt.values.astype('datetime64[M]')
df.head()
将购买日期列的格式更改为日期格式,并添加月份(month)列
![](https://upload-images.jia
nshu.io/upload_images/14624538-62b90c62c24b829e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1、进行用户消费趋势的分析(按月)
- 每月的消费总金额
- 每月的消费次数
- 每月的产品购买量
- 每月的消费人数
grouped_month=df.groupby('month')
order_month_amount=grouped_month.order_amount.sum()
order_month_amount.head()
plt.style.use('ggplot')
order_month_amount.plot()
消费金额前三个月最高,后续波动下降(原因?)
user_id列不唯一,是用户消费次数数据,或与产品关联的订单数据(仅猜测)
grouped_month.user_id.nunique().plot()
grouped_month.order_products.sum().plot()
购买金额、用户数、数量高度关联,可知多数ID购买的金额、数量相差不大,主营CD价格相差不大(推测)
df.pivot_table(index= 'month',
values = ['order_products','order_amount','user_id'],
aggfunc = {'order_products':'sum','order_amount':'sum','user_id':'count'})
2.用户个体消费分析
- 用户消费金额,消费次数的秒速统计
- 用户消费金额和消费次数的散点图
- 用户消费金额的分布图
- 用户消费次数的分布图
- 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
grouped_user = df.groupby('user_id')
grouped_user.sum().describe()
用户平均购买了7张CD,中位数3,部分用户购买了较多数量的CD;用户平均消费106元,中位数43,可验证上条结论
grouped_user.sum().query('order_amount<4000').plot.scatter(x= 'order_amount',y = 'order_products')
去除极值(>=4000)
grouped_user.sum().query('order_products<100').order_products.plot.hist(bins=40)
去除极值(>=100)
从直方图可知,用户消费金额,绝大部分呈现集中趋势,小部分异常值干扰了判断,使用过滤操作排除异常(利用切比雪夫定理过滤异常值,95%的数据都分布在5个标准差之内)
user_cumsum =grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum() / x.sum())
user_cumsum.reset_index().order_amount.plot()
按照用户消费金额进行升序排序,由图可以知道50%的用户仅贡献了15%的消费额度,而排名前5000的用户就贡献了60%的消费额度
3.用户消费行为
- 用户第一次消费(首购)
- 用户最后一次消费
- 新老客户消费比
- 多少用户仅消费一次
- 每月新客占比
- 用户分层
- RFM模型
- 新、老、活跃、回流、流失
- 用户购买周期(按订单)
- 用户消费周期描述
- 用户消费周期分布
- 用户生命周期(按第一次和最后一次消费) -用户生命周期描述
- 用户生命周期分布
grouped_user.min().order_dt.value_counts().plot()
grouped_user.max().order_dt.value_counts().plot()
断崖式下跌,看热闹人可能意味着前期活动引流效果明显,但未能留住客户
大部分最后一次购买,集中在前三个月,说明很多用户购买了一次后就不再进行购买
user_life = grouped_user.order_dt.agg(['min','max'])
user_life.head()
(user_life['min'] ==user_life['max']).value_counts()
过半客户仅消费一次
rfm = df.pivot_table(index ='user_id',
values = ['order_products','order_amount','order_dt'],
aggfunc ={'order_dt':'max','order_amount':'sum','order_products':'sum'})
rfm.head()
rfm['R'] = -(rfm.order_dt-rfm.order_dt.max())/np.timedelta64(1,'D')
rfm.rename(columns = {'order_products':'F','order_amount':'M'},inplace = True)
rfm[['R','F','M']].apply(lambda x:x-x.mean())
def rfm_func(x):
level = x.apply(lambda x:'1' if x>=1 else '0')
label = level.R +level.F +level.M
d = {
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要发展客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'一般挽留客户',
}
result = d[label]
return result
rfm['label'] = rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.groupby('label').sum()
rfm.loc[rfm.label == '重要价值客户','color'] = 'g'
rfm.loc[~(rfm.label == '重要价值客户'),'color'] = 'r'
rfm.plot.scatter('F','R',c=rfm.color)
RFM分析。将用户以三个维度分为8种进行区分,认为可能在一张图中对八种用户进行分类,需缩减坐标轴长度,划分更多颜色等
从RFM 分层可知,大部分用户是重要保持客户,但是这是由于极值的影响,所以 RFM 的划分标准应该以业务为准,也可以通过切比雪夫去除极值后求均值,并且 RFM 的各个划分标准可以都不一样
pivoted_counts = df.pivot_table(index='user_id',
columns='month',
values='order_dt',
aggfunc='count').fillna(0)
pivoted_counts
df_purchase = pivoted_counts.applymap(lambda x :1 if x >0 else 0)
df_purchase.tail()
def active_status(data):
status = []
for i in range(18):
if data[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:
status.append('new')
else:
if status[i-1]=='unactive':
status.append('return')
elif status[i-1]=='unreg':
status.append('new')
else :
status.append('active')
return status
indexs=df['month'].sort_values().astype('str').unique()
purchase_status = pivoted_counts.apply(lambda x:pd.Series(active_status(x),index=indexs),axis=1)
purchase_status.head(5)
这里遇到个麻烦,可能由于pandas版本是23.4的关系,导出的结果并非表格。所以需要对产生的数据再设置
purchase_status_ct = purchase_status.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_status_ct
purchase_status_ct.fillna(0).T.plot.area()
新用户仅前期存在。如果数据完整且正常,该网站长期未招新(?不合理)
purchase_status_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis =1)
order_diff = grouped_user.apply(lambda x:x.order_dt - x.order_dt.shift())
order_diff.head(10)
order_diff.describe()
订单周期呈指数分布
用户的平均购买周期是68天
绝大部分用户的购买周期都低于100天
(order_diff / np.timedelta64(1,'D')).hist(bins=20)
(user_life['max']-user_life['min']).describe()
、
u_1=(user_life['max']-user_life['min'])/np.timedelta64(1,'D')
u_1[u_1>0].hist(bins = 40)
4.复购率和回购率分析
- 复购率
- 自然月内,购买多次的用户占比(即,购买了两次以上)
pivoted_counts.head()
purchase_r = pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x ==0 else 0)
purchase_r.head()
(purchase_r.sum()/purchase_r.count()).plot(figsize = (10,4))
复购率稳定在20%所有,前一个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率降低