本次案例的数据来源于CDNOW,是美国的一家网上唱片公司,数据描述的是这家公司网站上的用户消费记录,分析目标旨在分析用户消费行为,建立RFM模型,分析复购率、回购率等关键指标。数据字典如下:
- user_id:用户ID
- order_dt:购买日期
- order_products:购买产品数
- order_amount:购买金额
数据集包含69659条记录,共有4个字段,时间范围从19970101-19980630之间,下面是数据集整理统计描述:
一、用户消费趋势分析(按月)
分别统计每月的消费总金额、消费次数、产品购买量、消费人数
grouped_month_info = grouped_month[['order_amount','user_id','order_products']].agg({'order_amount':sum, 'user_id': 'count', 'order_products':sum}).reset_index()
grouped_month_info.rename(columns = {'order_amount':'消费金额', 'user_id': '消费次数', 'order_products': '产品购买量'}, inplace=True)
grouped_month['user_id'].unique().map(len)
grouped_month_info['消费人次'] = grouped_month['user_id'].unique().map(len)
由上图可知,消费金额在前三个月达到最高峰,后续消费较为稳定,有轻微下降趋势
由上图可知,产品购买量在前三个月达到最高峰,后续消费较为稳定,有轻微下降趋势
前三个月消费订单人数在10000笔左右,后续月份的平均消费人数则在2500人,每月消费人数低于每月消费次数,但差异不大。
二、用户个体消费分析
1、用户消费金额,消费次数的描述统计
grouped_user=df.groupby('user_id').sum().describe()
out:
order_products order_amount
count 23570.000000 23570.000000
mean 7.122656 106.080426
std 16.983531 240.925195
min 1.000000 0.000000
25% 1.000000 19.970000
50% 3.000000 43.395000
75% 7.000000 106.475000
max 1033.000000 13990.930000
结果如下:
用户平均购买了7张,但是中位值只有3,说明小部分用户购买了大量货物,用户平均消费106元,中位值有43,判断同上,这说明也有极值干扰。
2、用户消费金额和消费次数的散点图
为排除极值干扰,order_amount筛选<4000,由散点图可知,用户消费金额与产品购买量几乎成线性关系,购买的商品越多,消费金额就越大。
3、用户消费金额和频次的分布图
grouped_user_sum_order_amount = grouped_user.sum().order_amount #每个用户的金额
grouped_user_sum_order_amount_lst = [i for i in range(0,int(grouped_user_sum_order_amount.max())+50,50)]
grouped_user_sum_order_amount = pd.cut(grouped_user_sum_order_amount, bins=grouped_user_sum_order_amount_lst,labels = grouped_user_sum_order_amount_lst[1:])
从直方图可知,用户消费金额,绝大部分呈现集中趋势,小部分异常值干扰了判断,可以使用过滤操作排除异常, 这里我们使用切比雪夫定理过滤掉异常值,因为切比雪夫定理说明,95%的数据都分布在5个标准差之内,剩下5%的极值就不要了。如下:
order_amount (mean = 106 ,std = 241) mean+5std = 1311
4、用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
# cumsum 是求累加值
user_cumsum=grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
按照用户消费金额进行升序排序,由图可以知道50%的用户仅贡献了11%的消费额度,而排名前5000的用户就贡献了60%的消费额度。
三、用户消费行为
1、用户第一次消费(首购)
grouped_user_min = grouped_user.min().order_dt.value_counts().reset_index().rename(columns={'index':'first_date'})
grouped_user_min['first_date'] =grouped_user_min['first_date'].astype(str)
用户第一次购买分布集中在前三个月。其中,在2月9日到2月25日之间有剧烈的波动。
2、用户最后一次消费
grouped_user_max = grouped_user.max().order_dt.value_counts().reset_index().rename(columns={'index':'last_date'})
grouped_user_max['last_date'] =grouped_user_max['last_date'].astype(str)
上图呈现断崖式下跌很正常,可以理解为用户流失比例基本一致,一开始用户迅猛增长数量比较多流失的也比较多,后面没有用户,用户最后一次购买的分布比第一次分布广,大部分最后一次购买,集中在前三个月,说明很多用户购买了一次后就不再进行购买。随着时间的递增,最后一次购买数量也在递增,消费呈现流失上升的状况(这也是正常,随着时间的增长,可能因为运营没有跟上或者用户忠诚度下降了)
3、新老客户消费比
- 多少用户仅消费一次
#新老客消费比
# 得到第一次和最后yc次消费情况,如果 min、max 日期相同,说明只消费了一次
user_life=grouped_user.order_dt.agg(['min','max'])
# 统计只消费了一次的用户
(user_life['min']==user_life['max']).value_counts()
结论得出大概有一半的用户,只消费了一次
- 每月新客占比
# 按照month、userid分组,第一次和最后一次消费日期
user_life_month=df.groupby(['month','user_id']).order_dt.agg(['min','max']).reset_index()
# 新增is_new字段,用于标记新用户
user_life_month['is_new']=(user_life_month['min']==user_life_month['max'])
# 再次按month分组,计算新用户占比
user_life_month_pct=user_life_month.groupby('month').is_new.apply(lambda x:x.value_counts()/x.count()).reset_index()
# level_1为True的作图
user_life_month_pct[user_life_month_pct.level_1].plot(x='month',y='is_new')
上图看出1997年1月新用户占比高达90%以上,后续有所下降,并逐渐趋于平稳,1997年4月到1998年6月维持在81%左右,1998年6月以后无新用户。
4、用户分层
- RFM模型
R:最后一次消费距今天数,F:消费总金额 ,M:消费总产品数
为得到最近一次消费,一般是计算 today 距离最近一次消费,这里因为时间太久远,就随便用的max值,数值越大就越久远,分子得到的是一些天数类似 545 days(因为是时间格式相减),再除以一个单位,就不会有单位了,只留下数值,如下:
# 重命名,也就是 R:最后一次消费距今天数
rfm['R']= -(rfm.order_dt - rfm.order_dt.max())/np.timedelta64(1,'D')
# F:消费金额 M:消费频次
rfm.rename(columns={'order_products':"F",'order_amount':'M'},inplace=True)
# RFM模型
def rfm_func(x):
level=x.apply(lambda x:'1' if x>=0 else '0')
# level 的类型是 series,index 是 R、F、M
#print(level)
#print(level.index)
label=level.R + level.F + level.M
#print(label)
d={
# R 为1 表示离均值较远即时间很久,F为1 表示 消费金额比较多,M 为1 表示消费频次比较多,所以是重要价值客户
'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要发展客户',
'001':'重要挽留客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般发展客户',
'000':'一般挽留客户',
}
result=d[label]
return result
# 注意这里是要一行行的传递进来,所以 axis=1,传递一行得到一个 111,然后匹配返回一个值
rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
# 归结为两类方便得出客户标签
rfm.loc[rfm.label=='重要价值客户','color']='重要价值客户'
rfm.loc[~(rfm.label=='重要价值客户'),'color']='非重要价值客户'
紫色部分是重要价值客户,消费频次较高。
rfm.groupby('label').sum()
M F R
label
一般价值客户 7181.28 650 36295.0
一般保持客户 19937.45 1712 29448.0
一般发展客户 438291.81 29346 6951815.0
一般挽留客户 196971.23 13977 591108.0
重要价值客户 167080.83 11121 358363.0
重要保持客户 1592039.62 107789 517267.0
重要发展客户 33028.40 1263 114482.0
重要挽留客户 45785.01 2023 56636.0
从RFM 分层可知,大部分用户是重要保持客户,但是这是由于极值的影响,所以 RFM 的划分标准应该以业务为准,也可以通过切比雪夫去除极值后求均值,并且 RFM 的各个划分标准可以都不一样.
- 新、老、活跃、回流、流失
# 数据透视, userid为索引,月为列,求每月的消费次数,这里填充了
pivoted_counts=df.pivot_table(index='user_id',
columns='month',
values='order_dt',
aggfunc='count').fillna(0)
# 转变一下消费,有消费为1,没有消费为0
df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
df_purchase.tail()
# 这里由于进行数据透视,填充了一些 null 值为0,而实际可能用户在当月根本就没有注册,
#这样会误导第一次消费数据的统计,所以写一个函数来处理
# 上面填充了一些null值为0,而实际可能用户在当月根本就没有注册,这样会误导第一次消费数据的统计,所以写一个函数来处理
def active_status(data):
status=[]
# 数据一共有18个月份,每次输入一行数据,也就是一个user_id的信息,进行逐月判断
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
关于active_status的说明:
return:回流 new:新客 unreg:未注册 active:活跃
若本月没有消费,这里只是和上个月判断是否注册,有一定的缺陷,应该判断是否存在就可以了
若之前有数据,是未注册,则依旧为未注册
若之前有数据,不是未注册,则为流失/不活跃
若之前没有数据,为未注册
若本月有消费
若是第一次消费,则为新用户
若之前有过消费,上个月为不活跃,则为回流
若之前有过消费,上个月为未注册,则为新用户
若之前有过消费,其他情况为活跃
purchase_stats=df_purchase.apply(lambda x: pd.Series(active_status(x),index=df_purchase.columns),axis=1)
purchase_stats.head()
# 这里把未注册的替换为空值,这样 count 计算时不会计算到
# 得到每个月的用户分布
purchase_stats_ct=purchase_stats.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_stats_ct
returnratee=purchase_stats_ct.apply(lambda x:x/x.sum(),axis=0)
purchase_stats_ct_info = purchase_stats_ct.fillna(0).T
前三个月有大量新用户涌入,新用户占比很高,而后面几个月不活跃用户占比非常高,普遍在90%以上。活跃用户,持续消费的用户,对应的是消费运营的质量。回流用户,之前不消费,本月才消费,对应的是唤回运营。不活跃用户,对应的是流失。
5、用户购买周期(按订单)
- 用户消费周期描述
# 用户购买周期(按订单)
# 计算相邻两个订单的时间间隔,shift 函数是对数据进行错位,所有数据会往下平移一下,所以可以
order_diff=grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
order_diff.head(10)
描述性统计:
- 用户消费周期分布
![用户消费周期分布].png](https://upload-images.jianshu.io/upload_images/7169608-1daba0a49d01c614.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
订单周期呈指数分布,用户的平均购买周期是68天,最小值0天,最大值533天,绝大部分用户的购买周期都低于100天。
6、用户生命周期(按第一次和最后一次消费)
-
用户生命周期描述
-
用户生命周期分布
用户平均生命周期134天,但中位数仅0天。用户的生命周期分布受只购买一次的用户(用户生命周期0天)影响比较严重,可以排除,得到:
用户平均生命周期276天,中位数302天。
7、复购率
复购率:自然月内,购买多次的用户占比(即,购买了两次以上)
# 区分一个,和一个以上的情况,以便于计算复购率,大于1为1,等于0 为NaN,等于1为0
purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
purchase_r.head()
purchase_r_reshop = (purchase_r.sum()/purchase_r.count()).reset_index(name = 'reshop')
复购率稳定在20%所有,前一个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率降低
8、回购率
回购率:曾经购买过的用户在某一时期的再次购买的占比(可能是在三个月内)
# 需要使用函数来判断是否回购:当月消费过的用户下个月也消费了叫做回购,这个定义可以改变
def purchase_back(data):
# 判断每一个月是否是回购,根据下个月是否购买来判断
status=[]
for i in range(17):
# 本月消费
if data[i]==1:
# 下个月回购
if data[i+1]==1:
status.append(1)
# 下个月没回购
if data[i+1]==0:
status.append(0)
# 本月没消费,赋予空值,不参与计算
else:
status.append(np.NaN)
# 第18个月补充NaN,因为没有下个月的数据了
status.append(np.NaN)
return status
indexs=df['month'].sort_values().astype('str').unique()
purchase_b = df_purchase.apply(lambda x :pd.Series(purchase_back(x),index = indexs),axis =1)
# 回购率,回购的次数/总购买次数
purchase_b_backshop = purchase_b.sum()/purchase_b.count()
回购率稳定在30%左右,前3个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致回购率较低。
四、小结
1、用户消费趋势(每月)方面,前3个月有大量新用户涌入,消费金额、消费订单数、产品购买量均达到高峰,后续每月较为稳定。前3个月消费次数都在10000笔左右,后续月份的平均2500;前3个月产品购买量达到20000甚至以上,后续月份平均7000;前3个月消费人数在8000-10000之间,后续月份平均2000不到。
2、用户个体消费方面大概符合二八法则,小部分用户购买了大量的CD,拉高了平均消费金额。用户消费金额集中在0100元,有大约17000名用户。用户购买量集中在05个,有大约16000名用户。50%的用户仅贡献了15%的消费额度,15%的用户贡献了60%的消费额度。
3、用户消费行为方面,首购和最后一次购买的时间,集中在前三个月,说明很多用户购买了一次后就不再进行购买。而且最后一次购买的用户数量也在随时间递增,消费呈现流失上升的状况。
4、从整体消费记录来看,有一半的用户,只消费了一次。从每月新用户占比来看,1997年1月新用户占比高达90%以上,后续有所下降,1997年4月到1998年6月维持在81%左右,1998年6月以后无新用户。
5、从RFM模型来看,在8种客户中,重要保持客户的消费频次和消费金额最高,人数排在第二位;而一般发展客户消费频次和消费金额排第二位,人数却是最多。
6、从用户分层情况来看,新用户从第4月份以后没有新增;活跃用户有所下降;回流用户数量趋于稳定,每月1000多。流失/不活跃用户,数量非常多,基本上每月都在20000以上。
7、用户购买周期方面,平均购买周期是68天,最小值0天,最大值533天。绝大部分用户的购买周期都低于100天。
8、用户生命周期方面,由于只购买一次的用户(生命周期为0天)占了接近一半,排除这部分用户的影响之后,用户平均生命周期276天,中位数302天。
9、复购率和回购率方面,复购率稳定在20%左右,回购率稳定在30%左右,前3个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率和回购率都比较低。