单车用户消费行为分析

一、项目介绍

CDNOW是一家网上唱片公司,通过18个月的用户消费记录,深入分析用户消费行为,建立RFM模型,进行用户分层,发掘高价值用户并进行针对性管理和维护,实现用户运营精细化。

二、RFM模型

简述:
RFM模型是网点衡量当前用户价值和客户潜在价值的重要工具和手段。RFM是Rencency(最近一次消费),Frequency(消费频率)、Monetary(消费金额),三个指标首字母组合
特点:
客观–利用客观的数字尺度,对客户进行简明而翔实的高水平描述。
简单–只需要客户的消费时间、消费频率和消费金额三个字段,业务人员就可以在不需要信息部门或复杂软件的情况下就能有效使用它。
直观–这种分割方法的输出很容易理解和解释。

基于RFM模型,将客户分为8种类型


客户分类:

RFM模型较为动态地显示了一个客户的全部轮廓,这对个性化的沟通和服务提供了依据,同时,如果与该客户打交道的时间足够长,也能够较为精确地判断该客户的长期价值(甚至是终身价值),通过改善三项指标的状况,从而为更多的营销决策提供支持。

三、项目过程

1. 总体消费趋势分析
分析指标:每月消费总金额、每月订单量、每月销量、每月的消费人数、平均客单价、人均消费次数
2.用户个体消费趋势分析
累计消费金额、消费次数、消费额与销量散点图、消费占比曲线
3. 用户消费行为分析
(1) 用户第一次消费与最后一次消费情况
(2) 用户价值分层(RFM)
(3) 用户活跃度分层(活跃用户、不活跃用户、新用户、回流用户)
(4) 用户生命周期
4.复购率和回购率分析

0.数据预处理

  • 通过数据观察,一共有69659条数据,没有缺失字段


字段解释如下:
user_id:用户id
order_dt:订单日期
order_products:产品数量
order_amount:订单金额

从csv中读取数据源,筛选所需要的字段,同时增加月份字段将用户按月进行统计

# 将order_dt保存为日期格式
df['order_dt'] = pd.to_datetime(df.order_dt,format = '%Y%m%d')
# 增加月份字段
df['month'] = df.order_dt.values.astype('datetime64[M]')

1. 总体消费趋势分析

使用groupby按月份将订单信息进行统计计算,每月消费总金额、每月订单量、每月销量、每月消费用户数量等指标,查看总体消费趋势。

fig, ax = plt.subplots(3,2,figsize = (14,12),dpi = 100)
ax[0,0].plot(grouped_month.sum().order_amount)
ax[0,1].plot(grouped_month.count().order_dt)
ax[1,0].plot(grouped_month.sum().order_products)
ax[1,1].plot(grouped_month.user_id.apply(lambda x:len(x.unique())))
ax[2,0].plot(grouped_month.sum().order_amount / grouped_month.user_id.apply(lambda x:len(x.unique())))
ax[2,1].plot(grouped_month.count().order_amount / grouped_month.user_id.apply(lambda x:len(x.unique())))
ax[0,0].set_title("消费额")
ax[0,1].set_title("订单量")
ax[1,0].set_title("产品销量")
ax[1,1].set_title("消费用户")
ax[2,0].set_title("平均客单价")
ax[2,1].set_title("人均消费次数")

plt.show()


观察图形得知:

  • 消费额、订单量、产品销量、消费用户指标折线图基本类似,都于前三个月较高,随后骤降在较低值趋于稳定,但整体仍有轻微下降趋势。初步猜测前三个月要么数据异常,要么就是存在某种营销活动的影响。
  • 平均客单价以及人均消费次数的趋势相近,前三个月稳步上升,随后稳定;客单价在47.5-57.5元区间波动,但最后也有下降势头,人均消费次数最后稳定与1.35次左右。
  • 以上分为两种趋势图,结合情况可能与用户复购率和回购率有关,需要后续进一步探讨。

2. 用户个体消费趋势分析

  • 用户整体消费情况统计
  • 消费金额与销量散点图
  • 消费额和消费订单数分布直方图
  • 用户占比与消费金额占比的关系曲线图

按照user_id字段对用户进行统计,计算消费金额、订单量、销量等指标,再对不同指标绘制分布散点图。

2.1 用户整体消费情况统计
grouped_user.agg({"order_products":"sum","order_amount":"sum","order_dt":"count"}).describe()
  • 以上结果信息分别为产品销量、消费金额、订单量的描述统计
  • 平均销量、消费额、订单量分别为7.12,106,2.9但是中位数为3,43,1
  • 销量、消费金额、订单量均存在明显的极值偏差(左偏)
2.2 绘制消费金额与销量散点图
grouped_user.sum().plot.scatter(x='order_amount',y='order_products',fontsize = 14)
  • 结果发现存在极值,现在需要剔除极值,选择order_products<400的部分
grouped_user.sum().query('order_products < 400').plot.scatter(x='order_amount',y='order_products')
  • 剔除偏差值后,销量与销售额基本呈线性关系。
2.3 用户消费额和消费次数分布直方图

绘制每位用户消费额和订单数的直方图

fig3,ax3 = plt.subplots(1,2,figsize = (14,4),dpi = 80)
grouped_user.sum().order_amount.plot.hist(bins = 30,ax = ax3[0])
grouped_user.count().order_dt.plot.hist(bins = 30, ax = ax3[1])
ax3[0].set_title("消费额")
ax3[1].set_title("订单数")
plt.show()
  • 由于均存在明显的极值偏差,需进行筛选处理
fig,ax = plt.subplots(1,2,figsize = (14,4),dpi = 80)
grouped_user.sum().query('order_amount <2000').order_amount.plot.hist(bins = 30,ax = ax[0])
grouped_user.count().query('order_dt <50').order_dt.plot.hist(bins = 30, ax = ax[1])
ax3[0].set_title("消费额")
ax3[1].set_title("订单数")
plt.show()
  • 大部分用户消费金额分布在0-250之间,大部分用户消费次数在0-5次之间(0-1次尤为较多)
2.4 绘制用户消费占比曲线图

将每位用户的累计消费金额从低到高排序,然后进行累加求和,并计算当前用户的累加与消费总额的关系,绘制消费金额比例与用户比例关系的曲线图。

user_amount = grouped_user.sum().order_amount.sort_values()   #根据金额排序
user_amount_pet = user_amount.cumsum()/user_amount.sum()   #换算为百分比
plt.style.use('ggplot')  #设置matplotlib格式
# 字体设置
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname="C:\Windows\Fonts\msyh.ttc",size=16)
x = np.arange(1/23570,1+1/23570,1/23570)  #取x刻度
y = user_amount_pet.reset_index(drop = True)
fig = plt.figure(figsize=(8,5),dpi = 80)
plt.plot(x,y)
plt.xlabel('用户比例',fontproperties=my_font)
plt.ylabel('消费金额比例',fontproperties=my_font)
plt.title('消费金额比例与用户比例关系',fontproperties=my_font)
plt.axhline(y = 0.8,ls = "--",lw = 1, c="b",alpha = 0.5)
plt.axvline(x = 0.8,ls = "--",lw = 1, c="b",alpha = 0.5)
plt.show()
  • 用户的消费遵循二八法则,20%的用户贡献了近70%的消费额,消费额的主要贡献还是出自于少部分客户

从用户个体消费趋势情况来看,大部分用户消费金额偏低,订单数极少(很多1次订单),我们推测可能是用户仅享用了首次购买的福利,便不再进行后续消费

3. 用户消费行为分析

  • 用户整体消费情况统计
  • 消费金额与销量散点图
  • 消费额和消费订单数分布直方图
  • 用户占比与消费金额占比的关系曲线图
3.1 用户首次与最后一次消费折线图

先将用户按照user_id进行分组,根据最小消费订单日期记为第一次消费,最大消费订单日期记为最后一次消费

grouped_user = df.groupby('user_id')
fig,ax = plt.subplots(1,2,figsize=(14,5),dpi = 80)
grouped_user.order_dt.min().value_counts().plot(ax = ax[0])
grouped_user.order_dt.max().value_counts().plot(ax = ax[1])
ax[0].set_title("用户第一次消费")
ax[1].set_title("用户最后一次消费")
plt.show()
  • 用户第一次消费值存在于前三个月呈钟型,最后一次消费也在前三个月较多达到170人左右,随后在每月20人左右的基础上略微上涨;
  • 再次验证可能是前三个月有活动,有大量客户涌入,但很多客户仅消费一次;3个月后没有新客户的输入,随着时间的增长老,客户也在以每月20人的数量流失,且逐渐增加。
3.2 用户RFM分层

R:最后一次消费时间间隔,F:消费销量,M:消费额

  • 根据以上指标创建用户透视表
  • 根据order_dt.max()-now()计算R指标
# 创建R、F、M的原始数据指标
rfm_1 = df.pivot_table(index = 'user_id',
                       values = ['order_dt','order_products','order_amount'],
                       aggfunc = {'order_dt':'max','order_products':'sum','order_amount':'sum'})
rfm_1['R'] = (rfm_1.order_dt - rfm_1.order_dt.max()) / np.timedelta64(1,'D')
rfm_1.rename(columns = {'order_amount':'M','order_products':'F'},inplace = True)

# 使原始指标减去对应平均值得到R、F、M指标
rfm_2 = rfm_1[['R','F','M']].apply(lambda x:x-x.mean())
  • 得到每位用户的R、F、M指标后,给用户分级(重要价值客户、重要保持客户、重要挽留客户...)
  • 如果相应指标>0则视为活跃指标
def user_label(data):
    level = data.apply(lambda x: '0' if x < 0 else '1' )
    label = level.R + level.F + level.M
    a = {'111':'重要价值客户',
         '011':'重要保持客户',
         '101':'重要挽留客户',
         '001':'重要发展客户',
         '110':'一般价值客户',
         '010':'一般保持客户',
         '100':'一般挽留客户',
         '000':'一般发展客户'}
    return a[label]
rfm_1['label'] = rfm_2.apply(user_label,axis = 1)
# 进行统计
RFM = rfm_1.groupby('label').agg({"order_dt":"count","M":"mean","F":"mean","R":"mean"})
RFM["rate"] = RFM.order_dt/RFM.order_dt.sum()
RFM.sort_values("rate",ascending = False)

# 作图
plt.figure(figsize = (14,12),dpi = 80)
plt.rcParams["font.size"] = "13"
plt.subplot(221)
RFM.order_dt.plot(kind = "pie", autopct = "%.1f%%")
plt.title("人数")
plt.subplot(222)
RFM.M.plot(kind = "bar")
plt.title("金额")
plt.subplot(223)
RFM.F.plot(kind = "bar")
plt.title("订单量")
plt.subplot(224)
RFM.R.plot(kind = "bar")
plt.title("购买周期")
plt.tight_layout(pad = 1)

观察数据得知:

  • 59%的客户属于一般发展客户,19%的客户属于重要价值客户,14%的客户属于一般挽留客户;
  • 消费金额与订单量均是重要价值客户遥遥领先,同时这一类客户是第二大群体,需要做好维护工作避免流失;
  • 整体情况上不容乐观,只有20%左右的客户是忠诚客户,其余大多数为流失客户。
3.3 活跃、新、回流、不活跃用户每月占比

根据每位用户的消费情况,将用户分为活跃用户、新用户、回流用户、不活跃用户

活跃用户:当月有消费的用户
新用户:当月消费且属于第一次消费的用户
回流用户:上一个月未消费,本月消费了的老用户
不活跃用户:当月未消费,且不是新用户

根据每位用户的消费情况,给每月打上0,1印记(1表示有消费,0表示未消费)

pivot_count = df.pivot_table(index = 'user_id',values = 'order_dt',columns = 'month',aggfunc = 'count')
df_purchase = pivot_count.fillna(0).applymap(lambda x:1 if x>= 1 else 0)

创建规则,将用户归属于上述4种类型

def user_label(data):
    status = []
    for i in range(18):
        #当月无消费
        if data[i] == 0:
            if len(status) == 0:   # 本月是第一个月
                status.append('unreg')
            else:
                if status[i-1] == 'unreg':  #前一个月是未注册用户
                    status.append('unreg')
                else:
                    status.append('unactive')
        #当月有消费            
        else: 
            if len(status) == 0:
                status.append('new')
            else:
                if status[i-1] == 'unreg':
                    status.append('new')
                elif status[i-1] == 'unactive':
                    status.append('return')
                else:
                    status.append('active')
    return status
purchase_status = df_purchase.apply(lambda x:pd.Series(user_label(x)),axis = 1)

每月对各种用户进行统计,绘制折线图

purchase_T = purchase_status.replace('unreg',np.nan).apply(lambda x:x.value_counts()).T
purchase_T= purchase_T.fillna(0)
# 绘图
purchase_T.div(purchase_T.sum(axis = 1),axis=0).plot(figsize = (10,6), fontsize = 15)
plt.legend(fontsize = 16)
plt.show()
  • 活跃用户与回流用户始终占比较低在5%以下
  • 3个月以后已经没有新用户输入,且不活跃用户在3个月后急剧增长达到90%左右
3.4 用户生命周期
  • 用户生命周期:用户第一次与最后一次消费的时间间隔
user_life = grouped_user.order_dt.apply(lambda x:x.max()-x.min()) / np.timedelta64(1,'D')
  • 绝大部分用户声明周期都在0天,为了方便观察,剔除0
user_life[user_life>0].hist(bins = 100)
user_life[user_life>0].describe()
count    11516.000000
mean       276.044807
std        166.633990
min          1.000000
25%        117.000000
50%        302.000000
75%        429.000000
max        544.000000
Name: order_dt, dtype: float64
  • 除开0的影响,用户平均周期为276天,中位数为302天几乎不存在极值偏差
  • 周期分布呈凹型,生命周期为0-50与400-500之间的用户较多

4. 复购率和回购率

  • 复购率:自然月内重复购买的用户占比
  • 回购率:本月购买,上一个月也购买的用户占比
4.1 复购率
pivot_return = pivot_count.fillna(0).applymap(lambda x:1 if x > 1 else 0 if x == 1 else np.nan)
pivot_return_pet = pivot_return.apply(lambda x:x[x==1].count()) / pivot_return.count()
# 作图
pivot_return_pet.plot()
  • 每月的复购率在21%左右,且较为稳定,存在一部分忠诚客户
4.2 回购率
# 创建用户回购标签
def back(data):
    status = []
    for i in range(18):
        # 本月未购买
        if data[i] == 0:
            status.append(np.nan)
        else:  #本月有购买
            if len(status) == 0:   #为第一个月
                status.append(0)
            else: #不是第一个月
                if data[i-1] == 0:   #上个月未购买
                    status.append(0)
                else:
                    status.append(1)
    return status
reback_user = df_purchase.apply(lambda x:pd.Series(back(x)),axis = 1)

#进行统计
reback_pet = reback_user.apply(lambda x:x[x==1].count()) / reback_user.count()
reback_pet.plot()

综上:

  • 初期用户回购率并不高,其中1月仅有10%左右,随后逐渐增长在3月的60%达到最高,但同时开始下降最后在30%趋于稳定。
  • 再次验证,从用户角度来看前三个月吸引力较大,而后续需要使用营销策略进行积极引导。

四、总结

  • 用户总体趋势方面:前三个月有大量新用户的涌入,各项数据指标如消费额、订单量等均达到最大值。但三个月之后,整体突然骤降,随后也处于轻微下降趋势。

  • 用户个体方面:其中有少量用户贡献了大量消费、订单量,将平均值拉高。大约有17000用户消费金额集中在0-100元之间,16000名用户的订单量集中在0-5之间。50%的用户仅贡献了15%的消费额,而20%的用户贡献了70%的消费额,符合二八法则。

  • 用户生命周期:声明周期为0或者1的用户占了大半,排除这部分用户,用户平均生命周期在276,中位数为302不存在明显的极值偏差。

  • 用户分层方面:从RFM模型来看,重要价值客户的消费频次和消费金额最高,占比人数排第二,这类客户需要重点维持。从用户活跃分层来看,第四个月开始没有新用户的产生,并且活跃用户也在一直下降,回流用户处于稳定状态,流失用户一直增加并且占比最高。

  • 复购率和回购率方面:排除前三个月的营销活动影响,真事复购率在20%左右,回购率为30%左右。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345