基于RFM的用户管理

案例背景

用户价值细分是了解用户价值度的重要途径,销售型公司对于订单交易尤为关注,因此基于订单交易的价值度模型将更适合运营需求。针对交易数据分析的常用模型是RFM模型,该模型不仅简单、容易理解,且业务落地能力非常强。

一、导入库

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier

二、读取数据

本项目选择4年的订单数据,可以从不同年份对比不同时间下各个分组的变化情况,方便了解会员的波动。

col_ = ['userID','orderID','date','bill']
df_2015 = pd.read_excel('sales.xlsx',sheet_name='2015', names=col_)

df_2016 = pd.read_excel('sales.xlsx',sheet_name='2016', names=col_)

df_2017 = pd.read_excel('sales.xlsx',sheet_name='2017', names=col_)

df_2018 = pd.read_excel('sales.xlsx',sheet_name='2018', names=col_)
df_member = pd.read_excel('sales.xlsx',sheet_name='会员等级')
df0 = pd.concat([df_2015,df_2016,df_2017,df_2018], axis=0)
df = df0.copy()

三、数据审查

1、数据概况

df.head()
userIDorderIDdatebill
01527800246830003046812015-01-01499.0
13923637897230003057912015-01-012588.0
23872203957830006417872015-01-01498.0
31104964006330007989132015-01-011572.0
43503875229230008215462015-01-0110.1
df.shape
(204240, 4)
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 204240 entries, 0 to 81348
Data columns (total 4 columns):
 #   Column   Non-Null Count   Dtype         
---  ------   --------------   -----         
 0   userID   204240 non-null  int64         
 1   orderID  204240 non-null  int64         
 2   date     204240 non-null  datetime64[ns]
 3   bill     204238 non-null  float64       
dtypes: datetime64[ns](1), float64(1), int64(2)
memory usage: 7.8 MB

订单金额有缺失,缺失2条记录。

df.describe()
userIDorderIDbill
count2.042400e+052.042400e+05204238.000000
mean2.901064e+104.287966e+09963.079622
std1.399716e+101.527312e+082236.971821
min8.100000e+013.000305e+090.000000
25%1.900445e+104.317356e+0959.525000
50%3.727031e+104.334091e+09148.000000
75%3.923266e+104.348166e+09899.000000
max3.954614e+104.354235e+09174900.000000

通过以上结果可以得到以下结论:

  • 每个sheet的数据都能正常读取识别,没有错误。
  • 日期列已经自动识别成日期格式,省去了后期做转换的过程。
  • 订单金额的分布不均匀,由明显的极大值和极小值。极大值应该是客户一次性购买多个高价值商品,是有意义的。极小值0是使用优惠支付的金额,没有实际意义。数据处理中丢掉订单金额小于1的记录。
  • 存在缺失值,但数量不多只有2条,数据处理中丢掉含有缺失值的记录。

四、数据处理

1、去除重复值、缺失值

df = df.drop_duplicates()

df = df.dropna()

2、创建新特征

data = df[df['bill']>1]

data['year'] = [x.year for x in data['date']]

df_lastestdate = data.groupby(['year'],as_index=False)['date'].max()

df_all = pd.merge(data, df_lastestdate, how='left', on='year')

df_all['datediff'] = df_all[['date_x','date_y']].apply(lambda x: (x['date_y']-x['date_x']).days,axis=1)

df_all = df_all.drop(['date_y'], axis=1)

df_all.rename({'date_x':'date'}, axis=1, inplace=True)
C:\ProgramData\Anaconda3\lib\site-packages\ipykernel_launcher.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  This is separate from the ipykernel package so we can avoid doing imports until

3、按userID汇总

rfm_gb = df_all.groupby(['year','userID'],as_index=False).agg({'datediff':'min','date':'count','bill':'sum'})

rfm_gb.columns = ['year','userID','r','f','m']
rfm_gb.head()
yearuserIDrfm
020152671972105.0
12015282251129.7
2201528334015398.0
320153433001118.0
42015525373213.0

五、确定RFM划分区间

做RFM划分时,基本逻辑是分别对R,F,M做分箱或离散化操作,然后才能得到离散化的得分。

rfm_gb.describe()
yearuserIDrfm
count148591.0000001.485910e+05148591.000000148591.000000148591.000000
mean2016.7730752.811669e+10165.5240431.3650021323.741329
std1.1293171.477660e+10101.9884722.6269533753.906883
min2015.0000008.100000e+010.0000001.0000001.500000
25%2016.0000001.728262e+1079.0000001.00000069.000000
50%2017.0000003.689151e+10156.0000001.000000189.000000
75%2018.0000003.923337e+10255.0000001.0000001199.000000
max2018.0000003.954614e+10365.000000130.000000206251.800000

从数据描述可以看出,总数据一共有14万条,r和m的数据分布相对离散,表现在min、25%、50%、75%、max的数据没有特别集中;而f(购买频率)中,大部分用户的分布都趋近于1,表现在min、25%、50%、75%的分段值都是1,并且均值才为1.3.

我们对r、f、m分别做3个区间的离散化,这样出来的用户群体最多有27个。划分区间过多不利于用户群体的拆分,划分区间过小则可能导致每个特征上的用户区分不显著。

我们计划选择25%、75%作为区间划分的2个边界值。问题在于,r和m本身能较好的区分用户特征,而f则无法有效区分(大部分用户只有1个订单)。针对这个问题需要跟业务部门沟通了解进而确定划分边界值。由于行业属性(大家电)的原因,用户发生复购确实很少,1年购买1次是比较普遍,因此选择2和5作为边界值:选择2是因为一般的业务认为当年购买2次及以上就可以被定位为复购用户,5次是业务认为普通用户购买5次已经是非常高的次数,超过该次数就属于非常高价值用户群体,这2个边界值是基于业务经验获得的。

rbins = [rfm_gb['r'].quantile(0)-1,rfm_gb['r'].quantile(0.25),rfm_gb['r'].quantile(0.75),rfm_gb['r'].quantile(1)]

mbins = [rfm_gb['m'].quantile(0)-1,rfm_gb['m'].quantile(0.25),rfm_gb['m'].quantile(0.75),rfm_gb['m'].quantile(1)]

fbins = [rfm_gb['f'].quantile(0)-1,2,5,rfm_gb['f'].quantile(1)]

最小值边界为什么小于特征的最小值呢?
后续使用的pd.cut方法,它对于自定义边界实行的是左开右闭的原则,造成最左侧的值无法划分到任何区间,因此在定义最小值时,一定要将最小值的边界定义的比特征的最小值小。

六、计算RFM因子权重

在计算RFM组合得分时,可以直接将结果组合成一个新分组,或者加权求和得到一个新的RFM得分。使用加权求和需要确定一个权重值。

这个项目里有会员等级数据,可以基于会员等级来确定RFM3个特征的权重,思路是建立RFM和会员等级的分类模型,通过模型输出权重。

没有这种会员数据的则可以根据业务经验分配权重。

df_member.rename({'会员ID':'userID','会员等级':'class'},axis=1,inplace=True)

rfm = pd.merge(rfm_gb,df_member,how='inner',on='userID')
rfm.head()
yearuserIDrfmclass
020152671972105.01
12015282251129.75
22017282314212992.05
3201828219530027.05
4201528334015398.04
rfm.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 142292 entries, 0 to 142291
Data columns (total 6 columns):
 #   Column  Non-Null Count   Dtype  
---  ------  --------------   -----  
 0   year    142292 non-null  int64  
 1   userID  142292 non-null  int64  
 2   r       142292 non-null  int64  
 3   f       142292 non-null  int64  
 4   m       142292 non-null  float64
 5   class   142292 non-null  int64  
dtypes: float64(1), int64(5)
memory usage: 7.6 MB
clf = RandomForestClassifier().fit(rfm[['r','f','m']], rfm['class'])

weights = clf.feature_importances_
weights
array([0.4036885 , 0.00640852, 0.58990298])

从以上结果可知,在这RFM这3个特征中,用户等级首先侧重会员的价值贡献度(实际订单那的贡献),其次是新近程度,最后是频次。这种逻辑与很多公司的整体会员等级一致。

七、RFM计算过程

rfm_gb['r_score'] = pd.cut(rfm_gb['r'], bins=rbins, labels=[i for i in range(len(rbins)-1,0,-1)])

rfm_gb['f_score'] = pd.cut(rfm_gb['f'], bins=fbins, labels=[i+1 for i in range(len(fbins)-1)])

rfm_gb['m_score'] = pd.cut(rfm_gb['m'], bins=mbins, labels=[i+1 for i in range(len(mbins)-1)])
rfm_gb.head()
yearuserIDrfmr_scoref_scorem_score
020152671972105.0212
12015282251129.7211
2201528334015398.0113
320153433001118.0112
42015525373213.0322
rfm_gb = rfm_gb.apply(np.int32)
# 加权得分
rfm_gb['rfm_score'] = rfm_gb['r_score']*weights[0] + rfm_gb['f_score']*weights[1] + rfm_gb['m_score']*weights[1]
rfm_gb.head()
yearuserIDrfmr_scoref_scorem_scorerfm_score
0201526719721052120.826603
120152822511292110.820194
22015283340153981130.429323
3201534330011181120.422914
420155253732133221.236700
# R F M组合
rfm_gb['rfm_group'] = rfm_gb.apply(lambda row: str(int(row['r_score']))+str(int(row['f_score']))+str(int(row['m_score'])),axis=1)
rfm_gb.head()
yearuserIDrfmr_scoref_scorem_scorerfm_scorerfm_group
0201526719721052120.826603212
120152822511292110.820194211
22015283340153981130.429323113
3201534330011181120.422914112
420155253732133221.236700322

八、RFM图形展示

display_df = rfm_gb.groupby(['rfm_group','year'], as_index=False)['userID'].count()

display_df.rename({'userID':'number'},axis=1,inplace=True)

display_df2 = display_df.pivot_table(index='rfm_group',columns='year',values='number')
display_df2.plot.bar()

在这里插入图片描述

九、数据分析

1、基于图形的分析

重点人群分布:通过柱状图做简单分析,在左右分组中,212群体的用户是相对集中且变化最大的。通过图形可以发现,从2016年到2017年用户群体数量变化不大,但到2018年增长了一倍。因此,这个群体将作为重点分析群体。

重点分组分布:除了212群体,柱状图还显示了312、213、211、112群体在各个年份占很大重量,虽然规模不大,但合起来的总量超过212群体。因此,后期也要分析。

2、基于统计的分析

result_df = display_df.groupby('rfm_group')['number'].sum()

result_1 = result_df.sort_values(ascending=False)/result_df.sum()*100

result_2 = result_1.cumsum()

result = pd.concat([result_1,result_2,result_df],axis=1)

result.columns = ['ratio','cunsum_ratio','number']
result
ratiocunsum_rationumber
21224.79221524.79221536839
21112.80225637.59447119023
31212.55459650.14906718655
11211.33716061.48622716846
21311.01681872.50304516370
3116.24129378.7443389274
1116.13630784.8806469118
3135.61339590.4940418341
1135.07096795.5650077535
1231.30021396.8652211932
2330.70394697.5691661046
1220.68308398.2522491015
3330.32639998.578649485
1330.31765098.896299472
3220.27592599.172224410
2220.25169899.423922374
2230.24900699.672928370
3230.24631499.919241366
3320.02490199.94414237
3210.02288299.96702434
2210.01615299.98317524
2320.00874999.99192413
1210.00605799.9979819
1320.00134699.9993272
3310.000673100.0000001

从统计结果可以看出,前9个用户群体的累计占比接近96%,和柱状图显示一致,因此我们把分析重点放到这9个群体上。

3、RFM用户特征分析

第一类群体:占比超过10%,用户量大,必须采取批量的方式落地运营策略,不能主要依赖人工。

  • 212群体:可发展的一般性群体,购买新进度和订单金额处于中等层级,购买频率低。采用常规性礼品兑换赠送、活动签到免运费等手段提升消费状态。
  • 211群体:可发展的低价值群体,相比于212群体在订单金额表现略差,在212群体策略基础上,增加与订单相关的刺激措施,比如组合商品优惠券发送、积分购买商品等。
  • 312群体:有潜力的一般性群体,购买新进度高,对公司还有比较熟悉的接触渠道和认知;购买频率低,对网站的忠诚度一般;订单金额中等水平,华友提升的空间。可借助最近购买的商品,制定一些与上次购买相关的商品,通过向上销售提高购买频率和订单金额。
  • 112群体:可挽回的一般性群体:购买新进度低,距离上次购买时间较长,可能处于沉默、预流失、流失阶段;购买频率低,对网站忠诚度一般;订单金额处于中等层级,还有提升的空间。首先通过多种途径触达用户并挽回,比如邮件、短信、电话等,然后通过针对流失用户的专享优惠(优惠券之类)促进消费。增加接触频次和刺激力度,提高用户复购。
  • 213群体:可发展的高价值群体:购买频次低,指定不同的活动触达用户(比如节日活动、每周推新、高价值用户专享商品等),促使回访和购买。

第二类群体:占比1%~10%,用户数量适中,落地时可以借助人工。

  • 311群体:有潜力的一般性群体,与211群体类似,但是在新进度较好,使用211群体策略即可。在最近接触的渠道上增加广告和营销投入,再次将用户引入网站完成消费。
  • 111群体,各个维度都较差的群体,在其他群体策略都落地后再考虑这个群体。主要策略还是先通过多种方式挽回用户,然后为用户推送当前热销的商品或折扣力度大的商品。先在优惠券、优惠商品的刺激下完成消费,再考虑购买频次和订单金额的提升。
  • 313群体:有潜力的高价值群体,购买频次低,需要提升购买频次。除了在最近一次接触渠道上增加曝光外,与最近一次接触渠道相关访问渠道也考虑增加营销投入。213群体的策略也适用。
  • 113群体:可挽回的高价值群体,与112群体类似,除了112群体策略外,增加部分人工参与(线下访谈、电话沟通)挽回高价值用户。

第三类群体:占比很少,但非常重要。

  • 333群体:忠诚的高价值群体。用户数量少,但是各个维度表现都很好,可以倾斜更多资源在这个群体,设计VIP服务、专享服务、绿色通道等。
  • 233、223、133群体:一般性的高价值群体,重点在于提高新近购买度,促使其实现最近一次的消费,可通过电子邮件、短信、电话、微信等方式挽回用户。
  • 322、323、332群体:有潜力的普通群体,要提升新近购买度和订单金额,如个性化推荐、组合优惠券、打包商品销售等策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值