前言:
💞💞大家好,我是书生♡,本阶段和大家一起分享和探索大数据技术RFM客户价值度模型,本篇文章主要讲述了:RFM客户价值度模型等等。欢迎大家一起探索讨论!!!
💞💞代码是你的画笔,创新是你的画布,用它们绘出属于你的精彩世界,不断挑战,无限可能!
个人主页⭐: 书生♡
gitee主页🙋♂:闲客
专栏主页💞:大数据开发
博客领域💥:大数据开发,java编程,前端,算法,Python
写作风格💞:超前知识点,干货,思路讲解,通俗易懂
支持博主💖:关注⭐,点赞、收藏⭐、留言💬
目录
- 1. 客户价值度模型介绍
- 2. RFM模型基本流程
- 3. RFM模型的划分区间的方法
- 4. RFM计算案例
- 4.1 案例背景
- 4.2 案例数据
- 4.3 数据计算
- 4.3.1 数据查看
- 4.3.2 数据预处理
1. 客户价值度模型介绍
- 客户价值度用来评估用户的价值情况,是区分客户价值的重要模型和参考依据,也是衡量不同营销效果的关键指标之一。
- 价值度模型一般基于交易行为产生,衡量的是有实体转化价值的行为。常用的价值度模型是RFM
- RFM模型是根据客户
- 最近一次购买时间R(Recency)
- 购买频率F(Frequency)
- 购买金额M(Monetary)计算得出RFM得分
- 通过这3个维度来评估客户的订单活跃价值,常用来做客户分群或价值区分
- RFM模型基于一个固定时间点来做模型分析,不同时间计算的的RFM结果可能不一样
R | F | M | 用户类别 |
---|---|---|---|
高 | 高 | 高 | 重要价值用户 |
高 | 低 | 高 | 重要发展用户 |
低 | 高 | 高 | 重要保持用户 |
低 | 低 | 高 | 重要挽留用户 |
高 | 高 | 低 | 一般价值用户 |
高 | 低 | 低 | 一般发展用户 |
低 | 高 | 低 | 一般保持用户 |
低 | 低 | 低 | 一般挽留用户 |
2. RFM模型基本流程
- 设置要做计算时的截止时间节点(例如2024-08-01),用来做基于该时间的数据选取和计算。
- 在客户数据库中,以今天为时间界限向前推固定周期(例如1年),得到包含每个客户的客户ID、订单时间、订单金额的原始数据集。一个客户可能会产生多条订单记录。
- 数据预计算。从订单时间中找到各个客户距离截止时间节点最近的订单时间作为最近购买时间;以会员ID为维度统计每个用户的订单数量作为购买频率;将用户多个订单的订单金额求和得到总订单金额。由此得到R、F、M三个原始数据量。
- R、F、M分区。对于F和M变量来讲,值越大代表购买频率越高、订单金额越高;但对R来讲,值越小代表离截止时间节点越近,因此值越好。对R、F、M分别使用五分位法做数据分区(三分位也可以,分位数越多划分得越详细)。需要注意的是,对于R来讲需要倒过来划分,离截止时间越近的值划分越大。这样就得到每个用户的R、F、M三个变量的分位数值。
- 将3个值组合或相加得到总的RFM得分。对于RFM总得分的计算有两种方式,一种是直接将3个值拼接到一起,例如RFM得分为312、333、132;另一种是直接将3个值相加求得一个新的汇总值,例如RFM得分为6、9、6。
- R就是距离自定义的时间点最近一次购买的时间间隔、间隔越小得分越高
- F就是自定义的时间范围内购买频率、次数越多得分越高
- M就是自定义的时间范围内购买总金额,总额越大得分越高
- RFM的区间和其对应的得分由我们自定义
3. RFM模型的划分区间的方法
RFM(Recency, Frequency, Monetary Value)模型是一种用于衡量客户价值的方法,通过分析最近一次购买时间(Recency)、购买频率(Frequency)和消费金额(Monetary Value)来评估客户的忠诚度和价值。确定RFM划分区间的常见方法包括以下几种:
-
等距分箱法:
- 方法:将每个指标分成若干等距区间。
- 优点:简单易行,便于理解和解释。
- 缺点:可能忽略数据分布的不均匀性。
-
等频分箱法:
- 方法:将每个指标分成若干等频区间,使得每个区间内包含大致相同数量的记录。
- 优点:更好地反映数据的实际分布。
- 缺点:区间边界可能不直观。
-
K-Means聚类:
- 方法:使用K-Means算法将客户分为不同的群组。
- 优点:能够捕捉客户行为的复杂模式。
- 缺点:需要确定聚类的数量,并且结果可能随初始化的不同而变化。
-
百分位数分箱法:
- 方法:将数据分成几个百分位数区间,如五分位数(Quintiles)或十分位数(Deciles)。
- 优点:能够反映数据分布的不均匀性。
- 缺点:区间边界可能不易解释。
-
基于业务逻辑的方法:
- 方法:根据业务经验和逻辑设定区间。
- 优点:更符合业务实际情况。
- 缺点:需要深入了解业务背景。
-
动态区间划分:
- 方法:根据数据的分布动态调整区间边界。
- 优点:适应性强,能够随着数据的变化自动调整。
- 缺点:实现起来较为复杂。
划分区间:
- 根据所选方法划分区间,例如:
- 等距分箱法:将R、F、M指标按等距离分成5个或10个区间。
- 等频分箱法:将每个指标分成包含相同数量记录的区间。
- 百分位数分箱法:将数据分成五分位数或十分位数。
示例
假设我们选择了等距分箱法,并将每个指标分为5个等级:
-
Recency ®:最近一次购买距离今天的时间(天数)。
- R1: 最近10天内购买的客户。
- R2: 11~20天内购买的客户。
- R3: 21~30天内购买的客户。
- R4: 31~40天内购买的客户。
- R5: 超过40天前购买的客户。
-
Frequency (F):购买次数。
- F1: 1~5次购买。
- F2: 6~10次购买。
- F3: 11~15次购买。
- F4: 16~20次购买。
- F5: 超过20次购买。
-
Monetary Value (M):总消费金额。
- M1: 1~100元。
- M2: 101~200元。
- M3: 201~300元。
- M4: 301~400元。
- M5: 超过400元。
应用案例
假设某个客户在最近10天内购买了10次,总消费金额为500元,则该客户的RFM得分为:
- R: R1 (最近10天内购买)
- F: F5 (超过20次购买)
- M: M5 (超过400元)
4. RFM计算案例
4.1 案例背景
- 用户价值细分是了解用户价值度的重要途径,针对交易数据分析的常用模型是RFM模型
- 业务对RFM的结果要求
- 对用户做分组
- 将每个组的用户特征概括和总结出来,便于后续精细化运营不同的客户群体,且根据不同群体做定制化或差异性的营销和关怀
- 规划目标将RFM的3个维度分别做3个区间的离散化
- 用户群体最大有3×3×3=27个
- 划分区间过多则不利于用户群体的拆分
- 区间过少则可能导致每个特征上的用户区分不显著
- 交付结果
- 给业务部门做运营的分析结果要导出为Excel文件,用于做后续分析和二次加工使用
- RFM的结果还会供其他模型的建模使用,RFM本身的结果可以作为新的局部性特征,因此数据的输出需要有本地文件和写数据库两种方式
- 数据说明
- 案例的数据集为“销售表”
- 选择近4年订单数据,从不同的年份对比不同时间下各个分组的绝对值变化情况,方便了解会员的波动
- 程序输出RFM得分数据写入本地文件sales_rfm_score.xlsx和MySQL数据库sales_rfm_score表中
4.2 案例数据
- 案例数据是某企业从2015年到2018年共4年的用户订单抽样数据,数据来源于销售系统
- 数据在Excel中包含5个sheet,前4个sheet以年份为单位存储为单个sheet中,最后一张会员等级表为用户的等级表
- 前4张表的数据概要如下。
- 特征变量数:4
- 数据记录数:
30774/41278/50839/81349
- 是否有NA值:有
- 是否有异常值:有
- 具体数据特征如下(前4张表的数据字段说明):
- 会员ID:每个会员的ID唯一,由纯数字组成,整型
- 提交日期:订单日提交日期
- 订单号:订单ID,每个订单的ID唯一,由纯数字组成,整型
- 订单金额:订单金额,浮点型数据
- 会员等级表中是所有会员的会员ID对应会员等级的情况,包括以下两个字段
- 会员ID:该ID可与前面的订单表中的会员ID关联
- 会员等级:会员等级以数字区分,数字越大,级别越高
4.3 数据计算
4.3.1 数据查看
- 加载数据
因为数据是存储在一个Excel中的不同页,因此要指定读取哪些页的数据
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import os
import warnings
sheet_names = ['2015','2016','2017','2018','会员等级']
list_data = []
for i in sheet_names:data= pd.read_excel('../data/sales.xlsx', sheet_name=i)list_data.append(data)list_data
# sheet_datas -> [df1, df2, df3, df4, df5]
# 前4个df是每年订单数据的df, 第5个是会员等级的df
- 我们在加载好数据之后,一定要先查看数据的缺失情况,查看那个列中有多少缺失值
查看缺失值
# 查看缺失值
list_data[0].isnull().any()
# 查看缺失值
list_data[0].isnull().any(axis=1).sum()
查看数据基本情况
# 统计包含缺失值的行数
# any(axis=1): 判断每行是否包含缺失值
list_data[1].isnull().any(axis=1).sum()
for each_name, each_data in zip(sheet_names, list_data): print('[data summary for ============={}===============]'.format(each_name))print('Overview:','\n',each_data.head(4))# 展示数据前4条print('DESC:','\n',each_data.describe())# 数据描述性信息# any(axis=1):每行是否有缺失值, 返回True或Falseprint('NA records',each_data.isnull().any(axis=1).sum()) # 包含缺失值条目数 print('Dtypes',each_data.dtypes) # 数据类型
结果说明
- 每个sheet中的数据都能正常读取,无任何错误
- 日期列(提交日期)已经被自动识别为日期格式,后期不必转换
- 订单金额的分布是不均匀的,里面有明显的极值
- 例如2016年的数据中,最大值为174900,最小值仅为0.1
- 极大极小值相差过大,数据会受极值影响
- 订单金额中的最小值包括0、0.1这样的金额,可能为非正常订单,与业务方沟通后确认
- 最大值的订单金额有效,通常是客户一次性购买多个大型商品
- 而订单金额为0.1元这类使用优惠券支付的订单,没有实际意义
- 除此0、0.1这样的金额之外,所有低于1元的订单均有这个问题,因此需要在后续处理中去掉
- 有的表中存在缺失值记录,但数量不多,选择丢弃或填充均可
4.3.2 数据预处理
- 汇总四年的数据
# 汇总四年的数据
data = pd.concat(list_data[:4])
data.info()
- 删除包含缺失值的行数据
# 删除包含缺失值的行数据
data.dropna(inplace=True)
data.info()
- 保留订单金额大于1的行数据
# 保留订单金额大于1的行数据
data = data[data['订单金额']>1]
data.info()
- 添加新的一列 列名 为 年
# 提取提交日期的年份保存到year新列中
data['year'] = data['提交日期'].dt.year
data
- 新增一列为 ,订单的最大日期,也就是最后一次购买的时间
# 对year新列分组, 提取每组中提交日期列的最大值, 保存到max_year_date新列中
# max_year_date: 4年订单数据集中的节点日期(当前时间)
data['max_data_year'] = data.groupby(data['year'])['提交日期'].transform('max')
data
- 添加间隔日期列 (当前时间与 每个用户最后一次购买时间)
# 添加间隔日期列
data['diff_days'] = (data['max_data_year'] -data['提交日期'])
data['diff_days'] = data['diff_days'].dt.days
data
- 计算RFM的原始值
# 统计每年每个用户的R/F/M原始值 -> 对年份和用户分组, 对相关列进行聚合操作
# R: 最近一次订单与当前时间的间隔天数 min()
# F: 订单数量 count()
# M: 订单总金额 sum()
#%%
rfm_data = data.groupby(by=['year','会员ID'],as_index=False).agg({'diff_days':'min','提交日期':'count','订单金额':'sum'})
rfm_data
- 修改列的名称
rfm_data.columns = ['year','会员ID','R','F','M']
rfm_data
- 区间划分
首先查看RFM的每一个值的最小值,中位值,最大值等等
# 使用分位数套路进行划分
rfm_data[['R','F','M']].describe().T
根据业务和数据的区间范围,划分区间
# (最小值, 1/4分位值] (1/4分位值,3/4分位值] (3/4分位值, 最大值]
# r区间划分
r_bins = [-1, 79, 255, 365]
# m区间划分
m_bins = [1,69,1199,206251]
# f区间划分: 业务是大家电消费, 一年购买一次, 需要和业务沟通
f_bins = [0, 2, 5, 130]
rfm_data['R_level'] = pd.cut(rfm_data['R'], bins=r_bins, labels=['3','2','1'])
rfm_data['F_level'] = pd.cut(rfm_data['F'], bins=f_bins, labels=['1','2','3'])
rfm_data['M_level'] = pd.cut(rfm_data['M'], bins=m_bins, labels=['1','2','3'])
rfm_data
- RFM组合-用户分群
将我们每一个值合并在一起,在和规则进行判断,判断属于哪个价值的用户
# 字符串拼接操作
# 分类类型转换成字符串类型
rfm_data['R_level'] = rfm_data['R_level'].astype(np.str)
rfm_data['F_level'] = rfm_data['F_level'].astype(np.str)
rfm_data['M_level'] = rfm_data['M_level'].astype(np.str)
rfm_data['rfm_group'] = rfm_data['R_level'] + rfm_data['F_level'] + rfm_data['M_level']
rfm_data.head()
- 绘制3D柱状图
display_data = rfm_data.groupby(by=['rfm_group','year'],as_index=False)['会员ID'].count()
display_data.columns = ['rfm_group','year','number']
display_data
# 导入绘制3D柱状图的库
from pyecharts.charts import Bar3D
from pyecharts import options as opts
# 以下绘制3D柱状图代码不需要写出来,能看懂就可以
# 颜色池
range_color = ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf','#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
# 获取数量的最大值
range_max = int(display_data['number'].max())
c = (Bar3D()#设置了一个3D柱形图对象.add("不同年份不同价值会员的数量",#图例[d.tolist() for d in display_data.values],#数据xaxis3d_opts=opts.Axis3DOpts(type_="category", name='分组名称'),#x轴数据类型,名称,rfm_groupyaxis3d_opts=opts.Axis3DOpts(type_="category", name='年份'),#y轴数据类型,名称,yearzaxis3d_opts=opts.Axis3DOpts(type_="value", name='会员数量'),#z轴数据类型,名称,number).set_global_opts( # 全局设置visualmap_opts=opts.VisualMapOpts(max_=range_max, range_color=range_color), #设置颜色,及不同取值对应的颜色title_opts=opts.TitleOpts(title="RFM分组结果"),#设置标题).render('./不同价值会员的柱状图.html')
)