数据集来源于和鲸社区,某健身房2019年3月至2020年2月会员消费购买行为。
数据集一共包含四个属性:用户ID,购买日期,购买数量,购买金额。
以秦路老师的数据分析课程的CDNow用户消费案例为参考,对该健身平台的用户进行消费特征分析。
分析框架如下:
1. 描述性统计
从数据的描述性统计中可以看出,会员用户每次消费平均购买1.47个商品,每次平均消费22.90元。
购买数量和消费金额的均值皆略小于中位数,说明购买数量和消费金额呈右偏分布。符合消费类数据的分布状况。
2. 用户消费特征分析
2.1 用户整体消费分析
不同月份的消费金额波动较大。
三月份到七月份的购买量和消费次数随着消费人数的增加而增加,进入八月份以后消费人数开始减少,说明出现了部分用户流失的情况,随之而来的是消费次数和购买量出现了明显下降。
2.2 用户个人消费分析
对用户分组,得到时长一年内用户个体的消费数据描述性统计
平均每个用户一年内购买12件商品左右(消费次数为12),最多的用户购买了277件商品。
平均每个用户一年内的消费金额是186元,标准差是641,而中位数是0,平均值比75分位数还要高很多,因此属于
画出用户消费金额和消费次数的散点图,可以看到消费金额和消费次数不完全呈线性关系,极值较多,用户的消费规律性不强。
画出用户一年内消费次数的分布图(去除掉个别极值的影响,可以更好的看出分布状况)(筛选出消费次数小于20 的用户)
从消费次数的右偏分布中可以看出,大部分用户一年内的消费次数在1次到5次之间,少部分用户在10次左右。
画出用户一年内消费次数的分布图(去除掉个别极值的影响,可以更好的看出分布状况)(筛选出消费金额小于200 的用户)
从消费次数的右偏分布中可以看出大部分人的消费金额较低,尽管均值在186元左右,但这是由于出现了极个别高消费用户整体提高了平均水平。
2.3 用户生命周期分析
从用户的生命周期直方图和描述性统计中可以得知,所有用户的平均生命周期是32天,中位数是1天,存在50%以上的用户首次消费后再也没有消费。
75分位数为13天,说明该健身平台绝大部分用户的生命周期都比较短。
极少部分用户生命周期较长,该部分用户是从开始到最后都有消费行为的高质量用户。
3. 用户价值度分析
按用户价值分层,采用RFM模型对用户价值指数(衡量历史到当前用户贡献的收益)进行计算,其中 最近一次消费-R:客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,反之则交易发生的日期越近。 消费频率-F:客户在最近一段时间内交易的次数。F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。 消费金额-M:客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。 根据上述三个维度,对客户做细分.
从RFM模型的结果来看,该健身平台的精细化运营并没有做的非常合适。重要价值用户和重要保持用户、重要发展用户的占比都很低。该健身平台应该主动联系用户来调查清楚哪方面出了问题,并注重对用户进行精细化运营,不断将用户转化为重要价值用户。
4. 用户质量分析
4.1 不同消费次数占比
有超过一半的用户仅消费了一次,说明了运营不利,留存效果不好。
4.2 复购率
复购率:在某时间窗口内消费两次及以上的用户在总消费用户中占比。
分析:四月份到八月份的复购率下降可能是由于新用户的加入拉低了复购率,八月份往后复购率逐渐回升可能是由于用户不断流失,剩下的老客继续消费,使得复购率继续上升。
4.3 回购率
回购率:是某一个时间窗口内消费的用户,在下一个时间窗口仍旧消费的占比。
回购率和复购率对比
5. 分析方法及过程
导入包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
plt.style.use('bmh')
plt.rc('font', family='SimHei', size=15)# 显示中文标签
导入数据
data=pd.read_excel(r'J:\JupyterLab\my_dataset\cuscapi.xls',order_dt=['date'])
data.head(10)
data.info()
pd.set_option('display.float_format',lambda x:'%.2f' % x)
描述性统计
data.describe()
用户整体消费趋势分析
plt.figure(figsize=(15,10))
plt.subplot(221)
data.groupby('month').order_amount.sum().plot(fontsize=15)
plt.xlabel('月份',fontsize=15)
plt.ylabel('消费金额',fontsize=15)
plt.title('每月消费金额',fontsize=15)
plt.subplot(222)
data.groupby('month').order_products.sum().plot(fontsize=15)
plt.xlabel('月份',fontsize=15)
plt.ylabel('购买量',fontsize=15)
plt.title('每月购买量',fontsize=15)
plt.subplot(223)
data.groupby('month').order_dt.count().plot(fontsize=15)
plt.xlabel('月份',fontsize=15)
plt.ylabel('消费次数',fontsize=15)
plt.title('每月消费次数',fontsize=15)
plt.subplot(224)
data.groupby('month').user_id.apply(lambda x:len(x.unique())).plot(fontsize=15)
plt.xlabel('月份',fontsize=15)
plt.ylabel('消费人数',fontsize=15)
plt.title('每月消费人数',fontsize=15)
plt.tight_layout() # 设置子图的间距
用户个人消费分析
## 以用户为单位进行分组
group_user=data.groupby('user_id').sum()
group_user.describe()
## 为了克服极值的影响,对消费次数进行筛选
## 画出一年内用户消费次数的分布直方图
group_user.query('order_products<20')['order_products'].hist(bins=40)
plt.xlabel('消费次数',fontsize=15)
plt.ylabel('人数',fontsize=15)
## 对消费金额进行筛选
## 画出一年内用户消费金额的分布直方图
group_user.query('order_amount<200')['order_amount'].hist(bins=40)
plt.xlabel('消费金额',fontsize=15)
plt.ylabel('人数',fontsize=15)
## 画出消费次数和消费金额的散点图
group_user.plot.scatter(x='order_amount',y='order_products')
用户生命周期分析
## 用户第一次消费和最后一次消费之间的时间间隔
order_dt_min=data.groupby('user_id').order_dt.min()
order_dt_max=data.groupby('user_id').order_dt.max()
life_time=(order_dt_max-order_dt_min).reset_index()
life_time.head(10)
life_time.describe()
## 画出用户的生命周期直方图
((order_dt_max-order_dt_min)/np.timedelta64(1,'D')).hist(bins=15)
plt.title('用户生命周期直方图',fontsize=15)
plt.xlabel('天数')
plt.ylabel('人数')
用户价值度分析
user_rfm=data.pivot_table(index='user_id',values=['order_dt','order_products','order_amount'],
aggfunc={'order_dt':'max','order_products':'count','order_amount':'sum'})
user_rfm['period']=(user_rfm.order_dt.max()-user_rfm.order_dt)/np.timedelta64(1,'D')
user_rfm=user_rfm.rename(columns={'period':'R','order_products':'F','order_amount':'M'})
## 定义RFM模型
def rfm_func(x):
level=x.apply(lambda x:'1' if x>=0 else '0')
label=level.R+level.F+level.M
d={'111':'重要价值客户',
'011':'重要保持客户',
'101':'重要挽留客户',
'001':'重要发展客户',
'110':'一般价值客户',
'010':'一般保持客户',
'100':'一般挽留客户',
'000':'一般发展客户'}
result=d[label]
return result
user_rfm['label']=user_rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
## 统计各层次用户人数
user_rfmp=user_rfm.groupby('label').count()
## 画出各层次用户分布的饼图
plt.figure(figsize=(20,10))
patches=plt.pie(user_rfmp.M.values,labels=['一般保持客户','一般发展客户','一般挽留客户','重要价值客户','重要保持客户','重要发展客户','重要挽留客户'],
explode=[0,0,0,0.4,0.3,0.2,0.1],autopct='%.2f%%',textprops={'fontsize':15} )
for t in p_text:
t.set_size(20)
plt.show()
用户质量分析
不同消费次数占比:一次消费和多次消费对比
a=data.groupby('user_id')['order_dt'].agg(['min','max']).reset_index()
new_old=(a['min']==a['max']).value_counts().values
plt.pie(x=new_old,autopct='%.1f%%',shadow=False,explode=[0.08,0],textprops={'fontsize':11})
plt.axis('equal')
plt.legend(['消费一次','多次消费'],fontsize=10)
复购率变化
#每个用户在每月的订单数
pivoted_df=data.pivot_table(index='user_id',columns='month',values='order_dt',aggfunc='count').fillna(0)#某些用户在某月没有消费过,用nan表示,这里用0填充
pivoted_df_transf=pivoted_df.applymap(lambda x: 1 if x>1 else np.nan if x==0 else 0)
pivoted_df_transf.head()
#count统计所有非空数据个数表示总消费用户数,sum计算非0数据的和表示消费两次以上的用户数
df_duplicate =pd.DataFrame(pivoted_df_transf.sum()/pivoted_df_transf.count()).reset_index()
df_duplicate.columns = ['Date', 'DuplicatedRate']
df_duplicate['Date'] = df_duplicate.Date.astype(str).apply(lambda x:x[:-3])
plt.figure(figsize = (15,6))
plt.plot(df_duplicate.Date, df_duplicate.DuplicatedRate)
plt.xlabel('时间', fontsize=24)
plt.ylabel('复购率',fontsize=24)
# plt.ylim(0,1)
plt.title('复购率的变化',fontsize=24)
回购率变化
pivoted_money=data.pivot_table(index='user_id',columns='month',values='order_amount',aggfunc='mean').fillna(0)
columns_month=data.month.sort_values().astype('str').unique()
pivoted_money.columns=columns_month
pivoted_money.head()
pivoted_purchase=pivoted_money.applymap(lambda x:1 if x>0 else 0)
pivoted_purchase.head()
def purchase_return(data):
status = []
for i in range(11):
if data[i] >= 1:
if data[i + 1] >= 1:
status.append(1)
else:
status.append(0)
else:
status.append(np.NaN)
status.append(np.NaN)
return pd.Series(status)
pivoted_purchase_return = pivoted_purchase.apply(purchase_return,axis=1)
pivoted_purchase_return.columns=columns_month
pivoted_purchase_return .head()
pivoted_purchase_return_rate=pivoted_purchase_return.sum()/pivoted_purchase_return.count()
plt.figure(figsize = (15,6))
plt.plot(df_duplicate.Date,pivoted_purchase_return_rate)
plt.title('回购率的变化')
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.xticks(fontsize=15)
回购率和复购率对比
a,b=plt.subplots(figsize=(15,6))
b.plot(df_duplicate.Date,pivoted_purchase_return_rate)
b.plot(df_duplicate.Date,df_duplicate.DuplicatedRate)
legends=['回购率','复购率']
b.legend(legends)
plt.title('回购率和复购率对比')
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.xticks(fontsize=15)