RFM用户分析模型简介
RFM用户分析模型简单来讲,R就是Recency,,M是Monetary,具体来说:
_Recency:最近一次消费,即上一次交易距今多少天,反映的是用户是否流失;
_Frequency:消费频率,一段时间内用户的消费频率,反映的是用户的消费活跃度;
_Monetary:消费金额,一段时间内用户消费总金额,反映的是用户价值。
根据这三个维度我们可以把用户分为8种:
用户类型 | 最近一次消费 | 消费频率 | 消费金额 | 说明 |
---|---|---|---|---|
重要价值用户 | 高 | 高 | 高 | 三项指标都很高,优质客户,重点关注 |
重要唤回客户 | 低 | 高 | 高 | 消费频率和消费金额都很高,但最近无消费,需要唤回 |
重要深耕客户 | 高 | 低 | 高 | 消费金额高,最近有消费,但消费频率低,需要深耕 |
重要挽留客户 | 低 | 低 | 高 | 消费金额高,但消费频率低,最近无消费,需要挽留 |
潜力客户 | 高 | 高 | 低 | 消费金额低,消费频率高,最近也有消费,需要挖掘 |
新客户 | 高 | 低 | 低 | 最近有消费,属于新客户,有推广价值 |
一般维持客户 | 低 | 高 | 低 | 消费频率高但消费金额低,一般维持即可 |
流失客户 | 低 | 低 | 低 | 三项指标都低,属于流失客户 |
对 RFM 用户分析模型来说,只要数据中有用户名、订单日期和订单金额等数据,就可以满足数据分析的基本需求了。
案例分析
读取数据表:
import pandas as pd
#从网络链接读取数据表
df=pd.read_csv('https://media-zip1.baydn.com/storage_media_zip/srfeae/bf6dc7d814c520c60e5e632d281f14a4.ba163c25251bd44b74bde1bb4af7abdc.csv')
#print(df)
调用df.info()查看数据表信息如下:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1692 entries, 0 to 1691
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 订单日期 1692 non-null object
1 用户名 1692 non-null object
2 订单金额 1692 non-null int64
dtypes: int64(1), object(2)
memory usage: 39.8+ KB
None
使用df.head(5)可以查看数据表前五行记录:
订单日期 用户名 订单金额
0 2019-01-01 杜汇 71
1 2019-01-01 钟群 157
2 2019-01-01 贺媚 163
3 2019-01-01 许菲 38
4 2019-01-01 罗姿 302
调用df.describe()让我们对订单金额大小有大致的概念,以便后续的数据处理:
订单金额
count 1692.000000
mean 433.797281
std 895.133325
min 1.000000
25% 36.000000
50% 148.000000
75% 478.000000
max 14052.000000
整体来看,数据比较完整,不需要特别的清洗,我们只需要将订单日期转换给日期格式,以便计算最近一次消费的日期:
df['订单日期'] = pd.to_datetime(df['订单日期'])
计算RFM值
然后我们就可以调用agg()方法来一次性计算RFM的值了:
df_rfm = df.groupby('用户名').agg({
'订单日期': lambda x: (pd.to_datetime('2019-12-31') - x.max()).days, # 计算 R
'用户名': lambda x: len(x), # 计算 F
'订单金额': lambda x: x.sum() # 计算 M
})
agg() 方法是 pandas 中的聚合方法,可以针对多列同时进行操作。它的用法有很多,这里只介绍参数是字典的用法。我们给 agg()方法传入一个字典,字典的键是要进行操作的列名,值为一个函数。函数的参数是每一列中的数据,函数的返回值将替换原来的值。你可以将agg()方法理解为同时针对多列进行不同操作的 apply() 方法。
表格中是 2019 年的订单数据,不包含 2020 年的数据,因此在计算 R(最近一次消费)时应该用 2019-12-31 减去用户的最近一次订单日期。日期越往后越大,因此调用max()方法可以找到该用户最近一次订单日期,最终得到的天数就是 R 的值。
因为时间跨度一样,都是一年。因此F(消费频率)可以直接用每个用户的订单数量表示。 按用户名分组后,用户名的个数就是该用户的订单数,因此通过 len() 函数可以直接得到 F 的值。
最后的 M(消费金额)也很简单,分组后直接调用sum()方法求和即可得到每个用户这一年的消费金额。
然后我们再使用rename()方法来更新以下列名:
df_rfm.rename(columns={'订单日期': 'R', '用户名': 'F', '订单金额': 'M'}, inplace=True)
这样就可以得到FRM的值形成的表格,打印出来看看:
R F M
用户名
丁元 57 1 1873
丁发 180 1 4151
丁和 25 3 1109
丁妹 37 2 2271
丁学 41 5 2291
.. ... .. ...
龙茜 131 1 267
龚以 162 1 467
龚妹 126 3 243
龚波 2 5 558
龚邦 244 1 6
FRM值打分
先用.describe()看一下FRM值的分布情况:
R F M
count 693.000000 693.000000 693.000000
mean 87.341991 2.441558 1059.141414
std 81.506870 1.317338 1464.025139
min 0.000000 1.000000 1.000000
25% 28.000000 1.000000 204.000000
50% 57.000000 2.000000 606.000000
75% 118.000000 3.000000 1334.000000
max 362.000000 9.000000 14203.000000
根据数据表中的25分位、50分位和75分位来进行分值的划分,以 R 为例,将分为 0 到 29、29 到 58、58 到 119 和 119 到 363 四个区间,分别给予4,3,2,1的分值,同理,F值可以分为0到1,1到2,2到3,3到10四个区间,分别赋分值1,2,3,4的分值,M可以分为0到204,204到606,606到1334,1334到14203等四个区间,分别赋值1,2,3,4的分值。 利用apply()函数,我们分别给R、F和M值打分:
#给R值打分
def r_score(x):
if x <= 29:
return 4
elif x <= 58:
return 3
elif x <= 119:
return 2
else:
return 1
df_rfm['r_score'] = df_rfm['R'].apply(r_score)
#给F值打分
def f_score(x):
if x<=1:
return 1
elif x<=2:
return 2
elif x<=3:
return 3
else:
return 4
df_rfm[f_score]=df_rfm['F'].apply(f_score)
#给M值打分
def m_score(x):
if x<=204:
return 1
elif x<=606:
return 2
elif x<=1334:
return 3
else:
return 4
df_rfm[m_score]=df_rfm['M'].apply(m_score)
现在把打分表打印出来看看:
R F M r_score f_score m_score
用户名
丁元 57 1 1873 3 1 4
丁发 180 1 4151 1 1 4
丁和 25 3 1109 4 3 3
丁妹 37 2 2271 3 2 4
丁学 41 5 2291 3 4 4
.. ... .. ... ... ... ...
龙茜 131 1 267 1 1 2
龚以 162 1 467 1 1 2
龚妹 126 3 243 1 3 2
龚波 2 5 558 4 4 2
龚邦 244 1 6 1 1 1
[693 rows x 6 columns]
简化RFM结果
按照RFM的分值对客户分类过于复杂,因此我们对RFM结果做进一步简化,将大于平均值定义为“高”,小于平均值定义为“低”:
df_rfm['R高低'] = df_rfm['r_score'].apply(lambda x: '高' if x > df_rfm['r_score'].mean() else '低')
df_rfm['F高低'] = df_rfm['f_score'].apply(lambda x: '高' if x > df_rfm['f_score'].mean() else '低')
df_rfm['M高低'] = df_rfm['m_score'].apply(lambda x: '高' if x > df_rfm['m_score'].mean() else '低')
为了方便打标签,我们先将 R 高低、F 高低 和 M 高低 加起来,也就是拼接成 高低高 这种字符串:
df_rfm['RFM'] = df_rfm['R高低'] + df_rfm['F高低'] + df_rfm['M高低']
最终得到表格:
R F M r_score f_score m_score R高低 F高低 M高低 RFM
用户名
丁元 57 1 1873 3 1 4 高 低 高 高低高
丁发 180 1 4151 1 1 4 低 低 高 低低高
丁和 25 3 1109 4 3 3 高 高 高 高高高
丁妹 37 2 2271 3 2 4 高 低 高 高低高
丁学 41 5 2291 3 4 4 高 高 高 高高高
.. ... .. ... ... ... ... .. .. .. ...
龙茜 131 1 267 1 1 2 低 低 低 低低低
龚以 162 1 467 1 1 2 低 低 低 低低低
龚妹 126 3 243 1 3 2 低 高 低 低高低
龚波 2 5 558 4 4 2 高 高 低 高高低
龚邦 244 1 6 1 1 1 低 低 低 低低低
我们直接分析 RFM 这列的字符串排列就能知道该用户是哪种类型的,加上类型标签的代码如下:
def rfm_type(x):
if x == '高高高':
return '重要价值用户'
elif x == '低高高':
return '重要唤回用户'
elif x == '高低高':
return '重要深耕用户'
elif x == '低低高':
return '重要挽留用户'
elif x == '高高低':
return '潜力用户'
elif x == '高低低':
return '新用户'
elif x == '低高低':
return '一般维持用户'
elif x == '低低低':
return '流失用户'
df_rfm['用户类型'] = df_rfm['RFM'].apply(rfm_type)
这样我们整个RFM用户分析模型就建立起来了,结果如下:
R F M r_score f_score m_score R高低 F高低 M高低 RFM 用户类型
用户名
丁元 57 1 1873 3 1 4 高 低 高 高低高 重要深耕用户
丁发 180 1 4151 1 1 4 低 低 高 低低高 重要挽留用户
丁和 25 3 1109 4 3 3 高 高 高 高高高 重要价值用户
丁妹 37 2 2271 3 2 4 高 低 高 高低高 重要深耕用户
丁学 41 5 2291 3 4 4 高 高 高 高高高 重要价值用户
.. ... .. ... ... ... ... .. .. .. ... ...
龙茜 131 1 267 1 1 2 低 低 低 低低低 流失用户
龚以 162 1 467 1 1 2 低 低 低 低低低 流失用户
龚妹 126 3 243 1 3 2 低 高 低 低高低 一般维持用户
龚波 2 5 558 4 4 2 高 高 低 高高低 潜力用户
龚邦 244 1 6 1 1 1 低 低 低 低低低 流失用户
[693 rows x 11 columns]
RFM 模型结果分析
先用df_rfm['用户类型'].value_counts()来统计各类客户的人数:
流失用户 164
重要价值用户 138
新用户 86
重要挽留用户 75
重要深耕用户 75
重要唤回用户 57
潜力用户 56
一般维持用户 42
Name: 用户类型, dtype: int64
利用reset_index() 方法将 Series 变成了 DataFrame,我们给表格在加一列,计算出每种类型的用户的占比分别是多少。
df_count = df_rfm['用户类型'].value_counts().reset_index()
df_count.rename(columns={'index': '用户类型', '用户类型': '人数'}, inplace=True)
df_count['占比'] = df_count['人数'] / df_count['人数'].sum() # 人数/总人数
这样可以得到更直观的模型结果:
用户类型 人数 占比
0 流失用户 164 0.236652
1 重要价值用户 138 0.199134
2 新用户 86 0.124098
3 重要挽留用户 75 0.108225
4 重要深耕用户 75 0.108225
5 重要唤回用户 57 0.082251
6 潜力用户 56 0.080808
7 一般维持用户 42 0.060606
利用数据可视化方法更直观的展示我们的模型结果:
df_count.plot(kind='bar', x='用户类型', y=['人数'])
plt.show() # 需要提前 import matplotlib.pyplot as plt
可以获得如下图示:

可以很直观的看到,流失用户量非常大。原因可能是某些环节用户体验不好导致用户不满意,我们需要重点关注这部分用户,制定减少用户流失的方案。同时,新用户的占比也很多,要想办法将这些用户转为重要价值用户。