0
点赞
收藏
分享

微信扫一扫

第9关 电商客户价值细分 - RFM 模型

Java架构领域 2021-09-26 阅读 50

在数据分析第六关里,我们重点介绍了 RFM 模型。本节内容将结合 RFM 模型以及前面所学的重要知识点,对一个案例进行实战。

1. 案例实战 - 细分电商客户价值

1.1 案例背景

国内某一跨境电商平台主营食品等产品。从 2010 年到 2011 年间,为提高平台的营业额,进行了广告投放以及电子邮件、电话、短信等营销活动,但是收效甚微。

经过调查后,发现有很多客户抱怨公司员工打了太多电话,自己受到了骚扰。但是当员工降低信息推送频率时,也有客户投诉公司信息传递滞后,很多优惠活动没有通知到他们。

公司对营销活动进行复盘,发现关键问题在于:公司针对不同的用户群体使用了同样的销售策略,而这些销售策略的覆盖面特别窄,只能满足一小部分的用户。

找到问题后,公司想到了一个解决策略,就是基于 RFM 模型,对用户进行分类,然后根据不同用户群体的特性,使用更有针对性的营销策略。

4.2 明确目标

根据公司现有的问题,结合 RFM 模型流程,对接下来的分析工作做如下的目标拆解:

1)目标 1:获取含有 RFM 的用户数据;
2)目标 2:基于 RFM 的阈值,对用户进行分类。

经过公司内部沟通后,拿到了一份用户的商品销售数据,先一起来看看,并思考这份数据是否能满足我们的分析需求。

首先我们读取并查看【商品销售数据.xlsx】工作簿的数据。
(提示:由于该份数据量级较大,运行完该程序可能需要等待 1-2 分钟。)

# 读取并查看【商品销售数据.xlsx】工作簿的数据
df = pd.read_excel('./工作/商品销售数据.xlsx')
df

观察数据可以看出,一条订单数据包含了单个商品的销售信息,如发货日期、价格等数据。

一个订单内,用户可能同时购买了多种商品。所以,多条相同的订单号,是一个完整的单次购买记录。

同时,一个用户可以含有多条购买记录。

接着观察数据,看看是否能提取到 RFM 模型所需的目标数据。

1)如果想获取某用户的最近一次消费时间间隔(R),可以通过该用户的【用户 ID】查找订单最新的一次【发货日期】,计算与当前时间的时间差。

比如【用户 ID】为 17850 的用户,其最新一条消费订单的【发货日期】为 2010/2/12,假设今天是 2011/2/12 日,那么 R 值就是 365 天。

2)如果想获取某用户的消费频率(F),只需要查看该用户的【用户 ID】下,不重复的订单号数量。

还是以【用户 ID】为 17850 的用户为例,假设我们对“一段时间”的定义为 2010 年至2011年,如果该用户在 2010/1/12 和 2010/2/12 都进行了消费,那么 F 值就为 2 次。

3)如果想获取某用户的消费金额(M),只需要将该用户的所有消费额进行加和。

其中,用户的消费总额计算公式如下图所示:

比如【用户 ID】为 17850 的用户有两次消费记录,第一个订单购买了 6 个价格为 2.55 元的清蒸豆腐,以及 6 个价格为 3.39 元的五香熏蛋。则该订单的消费额为 6 x 2.55 + 6 x 3.39 = 35.64 元。

第二个订单只购买了 8 个价格为 2.75 元的佛跳墙,所以该订单的消费额为 8 x 2.75 = 22 元。则该用户的 M 值(消费总额)为 35.64 + 22 = 57.64 元。

可以看到,这份数据虽然没有包含具体的 RFM 值,但通过观察发现,数据只需进一步处理,就能将原数据转换成我们的目标数据。

1.3 数据处理

既然数据能满足分析需求,那我们可以根据拆分的目标进行 RFM 模型的构建:

目标1:获取含有 RFM 的用户数据

为了达到目标1,我们需要先对拿到的数据进行处理。数据处理可以分成两个步骤:

1)数据清洗:主要对数据的缺失值、重复值、异常值进行清洗;
2)数据整理:删除无关数据,提取与 RFM 模型相关的重要数据。

我们先对数据进行清洗。

1)数据清洗

关于数据清洗,我们已经学习了一套较为完整的方法。以下是数据清洗用到的相关方法。

请你根据所学的知识点,将读取【商品销售数据.xlsx】工作簿得到的数据进行清洗。

能够完成数据的清洗步骤吗?不妨看看我的数据清洗思路。

首先,使用 info() 方法查看数据的基本信息总结。

从打印得到的信息可以看到,只有【用户 ID】列存在缺失值。

可以只对【用户 ID】列进行缺失值的清洗,代码如下:

接着,我们使用 duplicated() 方法查找重复数据。

从显示的结果可以看到,存在两条重复数据。此时可以使用 drop_duplicates() 方法删除重复数据。

最后,使用 describe() 查看数据的描述性统计信息,检查数据极大极小值是否符合常识和业务要求。

观察数据的统计性信息可以看到,【数量】列出现了最小值 -80995,以及【价格】列出现了最小值 0。

按照常识来说,数量只有大于零才应该出现订单数据,不可能为负值。而价格为零有可能是因为赠送活动的促销价格。

所以,只有数量小于零的为异常数据。

我们只对数量小于零的异常数据进行清洗。

数据清洗已完成,接着需要对数据进行整理。

2)数据整理

基于我们的目标,在阅读下方的内容前,你可以先思考一下数据的整理流程和方法。

有大概的思路了吗?你也可以参考我的数据整理思路。

在前面的分析过程中我们已经知道,与 RFM 模型相关的数据如下:

我们可以提取数据中的【发货日期】列来计算 R 值。

而一个订单里面可能包含多个商品,一个用户可能有多个订单。

所以,我们可以通过【数量】和【价格】列算出单个商品的总额,再通过【订单列】对相同订单号的数据进行分组,计算每个订单的总额,最后将用户每个订单的总额进行加和,可以得到 M 值。

其中,计算用户不重复的订单数量可以得到 F 值。

基于这些信息,可以将数据整理的思路分为三步:

a. 新增一个【商品总额】列,用以计算每个商品的消费总额。

b. 将商品按订单号进行分组,合并商品总额,得到用户每一个订单的消费金额。然后我们只保留计算 RFM 所需的数据。

c. 计算 R(选取用户所有订单中时间差最小的值)、F(用户消费订单的总数量)、M(计算用户所有消费订单总额)。

思路整理好了,我们就可以结合前面所学的知识点,开始代码的编写。

第一步:新增【总金额】列,计算每个商品的消费总额

# 计算“总金额”
df['总金额'] = df['价格'] * df['数量']
df

计算完商品的消费总额后,可以对数据进行分组合并,并只保留 RFM 所需的数据。

第二步:将商品按订单号进行分组,合并商品总额

由于一个用户可能有多个订单,在对订单进行分组,合并商品总额时,也需要保留用户的 ID,以便后面计算用户的总消费额和消费频率。

提示:可以将订单号和用户 ID 组合为一个列表,再将该列表传入 groupby() 函数进行分组,同时对总金额进行加和,保留最近的发货日期(日期最大)

# 将商品数据转化为订单消费数据
group_df = df.groupby(['订单号', '用户 ID'], as_index=False).agg({'发货日期': 'max', '总金额': 'sum'})
group_df

代码中,我们使用 groupby() 函数将数据按【订单号】和【用户 ID】进行分组。

其中,函数中的参数 as_index 决定分组后的数据是否带行索引。默认情况下,该参数的值为 True ,即不含自带的行索引,若设置为 False,则包含自带的行索引。

这里将参数 as_index 设置为 False,目的是为了方便后面对数据的提取计算。

分完组后,再使用 agg() 方法提取【发货日期】列的最大值,以及【总金额】列的总和。

RFM 所需的数据已提取完。接下来,可以进行 R、F、M 值的计算。

第三步:计算 R、F、M 值

计算 R 值前,我们可以设定一个当前时间,比如 today = '2012-01-01 00:00:00',再将每个订单的发货时间与当前时间进行对比后,提取具体的天数差。

而发货时间与当前时间可以通过 to_datetime() 函数转化为日期格式后,再通过减法运算会返回一个带有时间差的 Series 对象。

但在实际情况下,我们只需要拿到天数差即可,无需精确到时分秒。

所以,可以调用 Series 对象的 dt.days 属性来提取天数信息。再新建【时间间隔】列来存储该天数信息。

至此,时间间隔也计算完毕。接下来,需要对 R、F、M 的值进行提取。

实现以下几个要求:
a. 根据【用户 ID】进行分组,分组后的数据包含自带的行索引;
b. 通过提取最小的时间间隔,得到用户的 R 值(筛选最小时间差);
c. 通过计算订单号的总数量,提取用户的 F 值(统计用户的订单总数);
d. 通过计算总金额的总和,提取用户的 M 值(汇总订单消费总额)。

最后,为了方便我们更直观地看出 RFM 各对应哪一列,可以把数据的列名依次修改为:用户 ID、时间间隔、总次数和总金额。

至此,我们已经整理好含有 RFM 的用户数据,那就可以进行下一环节的数据分析。

1.4 数据分析

目标2:基于 RFM 的阈值,对用户进行分类

为了达到目标2,对用户进行分类之前,我们还需要明确用户划分的步骤:

首先是计算 RFM 的阈值。前面也提到,计算阈值的方式有很多,那应该怎么挑选呢?

1)计算 RFM 的阈值

根据实际业务的需求出发,在和电商运营人员商讨中发现,如果直接通过平均值或中位数进行阈值的划分不够客观,这是因为不同的客户对于电话推送优惠活动的反应不同。

在服务资源有限的情况下,他们也希望能够对用户人群进行调整。

因此,我们需要选择更加灵活的阈值计算方式:分区域评分,计算平均值。

这种方式计算阈值的流程为:划分区间 —— 标记分数 —— 计算平均值。

划分区间可以有以下两种方法:

a.确认关键的节点进行划分。比如小学考试中满分 100 分,达到 60 分就算及格;

b.根据实际经验进行划分。比如一般的用户消费水平在 1w,消费超过 10w 是高净值人群。

就像在第6关举出的例子中,我将 RFM 值分成 5 个区间,统一评分单位,每个区间对应一个等级,数值所代表的价值越高,等级越高。

当然了,在实际业务上,你完全可以按照自己的需求划分得更加细致,如 10 个区间。就像你在举哑铃,哑铃重量控制在哪个范围,可根据自身的身体情况把握。具体根据数据的情况选定区间。

本节案例课先以划分 5 个区间的方式进行讲解。

先来看看案例的 R 值是怎么划分区间的。

我们需要将数据先进行排序,绘制出 R 值的折线图,就能看得出不同时间间隔的分布情况,再以此来划分区间。实现代码如下:

我们知道,R 值越小,最近一次购买的时间间隔就越短,用户再次购买的可能性越高,分值应该越高。相反,R值越高,分值应该越低。

上图表示不同 R 值所对应的用户数,其中 y 轴代表每个用户的 ID,x 轴代表每个用户对应的 R 值。

图中可以看到,曲线大约以 400 天为界限,400 之前的呈曲线分布,400 后的几乎呈直线分布。

而大于 400 天的数据,即最近一次购买时间都超过一年,用户再次购买商品的可能性很低,可将他们整体分成一类。小于 400 天的数据可均匀地以 100 为单位,进行区间划分。

那么我可以定义如下的函数来为不同区间的用户进行 R 值的打分。

再为数据新建一个【R评分】列,将【时间间隔】列的数据依次评分后写入到【R评分】列。

def caculate_r(r):
    """
    定义函数按照区间划分 R 值
    """
    if r <= 100:
        return 5
    elif r <= 200:
        return 4
    elif r <= 300:
        return 3
    elif r <= 400:
        return 2
    else:
        return 1


# 新建一个【R评分】列,将【时间间隔】列的数据依次评分后写入到【R评分】列
rfm_df['R评分'] = rfm_df['时间间隔'].agg(caculate_r)
rfm_df

这样,我们已经对 R 值进行区间划分,以及 R 值的打分。

同理,F 值和 M 值进行区间划分与打分交给你来完成。

我的答案:

# 定义函数按照区间划分 F 值
def caculate_f(f):
    if f <= 5:
        return 1
    elif f <= 10:
        return 2
    elif f <= 15:
        return 3
    elif f <= 20:
        return 4
    else:
        return 5

# 新建一个【F评分】列,将【总次数】列的数据依次评分后写入到【F评分】列
rfm_df['F评分'] = rfm_df['总次数'].agg(caculate_f)
rfm_df
# 定义函数按照区间划分 M 值
def caculate_m(m):
    if m <= 2000:
        return 1
    elif m <= 4000:
        return 2
    elif m <= 6000:
        return 3
    elif m <= 8000:
        return 4
    else:
        return 5


# 新建一个【M评分】列,将【总金额】列的数据依次评分后写入到【M评分】列
rfm_df['M评分'] = rfm_df['总金额'].agg(caculate_m)
rfm_df

到这里,我们已经完成 R、F、M 各值的分数标记。再通过下方的代码计算 R、F、M 各值的平均值就能得到各值的阈值了。

# 计算 R评分、F评分、M评分的平均数
r_avg = rfm_df['R评分'].mean()
f_avg = rfm_df['F评分'].mean()
m_avg = rfm_df['M评分'].mean()

print(r_avg, f_avg, m_avg)

得到 R、F、M 各值的阈值以后,将要为 R、F、M 各值进行高低值的标记。

2)标记 RFM 的高低值

这一步可以将获得的阈值与 RFM 分数进行比较,高于阈值记为“高”,低于阈值记为“低”。

那该如何给 RFM 各值标记 “高” 或 “低” 呢?

这里,我们可以利用 R、F、M 的分数与阈值对比后得到的返回值。比如我们拿 R 值的分数与阈值进行对比:

从返回的结果可以看到,每个分数与阈值对比可以得到一个布尔值,并且返回的是 Series 对象。

所以利用R、F、M 的分数与阈值对比得到布尔结果:

然后我们利用 replace()方法替换布尔结果,“高”替换掉 True,“低”替换掉 False

现在,R、F、M 的高低值也标记完毕。

接下来,需要将 RFM 的评分进行拼接,与用户分类规则表进行对比,可以得出用户属于哪种类别。

3)标记用户类型

先定义如下的字典来为不同的组合匹配对应的用户分类名称。

transform_label = {
    '高高高': '重要价值用户',
    '高低高': '重要发展用户',
    '低高高': '重要保持用户',
    '低低高': '重要挽留用户',
    '高高低': '一般价值用户',
    '高低低': '一般发展用户',
    '低高低': '一般保持用户',
    '低低低': '一般挽留用户'
}

然后再次使用 replace() 方法对数据进行批量替换。

# 拼接R评分、F评分、M评分
rfm_score = rfm_df['R评分'] + rfm_df['F评分'] + rfm_df['M评分']
# 新建一个【客户类型】列,将RFM评分替换成具体的客户类型
rfm_df['客户类型'] = rfm_score.replace(transform_label)
rfm_df

从显示的内容可以看到,我们已经为数据标记上用户类型。

为得知公司各类用户的分布,需要计算各类用户的数量。按【客户类型】分组,统计用户(用户 ID)的数量。

显示的数据虽然可以看到八大用户类型的频数分布,但数据的呈现不够直观,还需要进一步对用户类型的具体占比和分布进行可视化展现。

1.5 数据展现

查看不同类型用户的数量分布,我们可以采取柱状图。将用户类型作为 x 轴,用户类型对应的数量作为 y 轴,可以很直观地看到各类型用户的分布情况。

plt.figure(figsize=(14, 8))
x = customer.index
y = customer.values
plt.bar(x, y, width=0.6, alpha=0.8)
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
plt.xlabel('客户类型', fontsize=18)
plt.ylabel('人数', fontsize=18)
plt.title('不同客户的数量分布', fontsize=30)

想查看不同类型用户的数据占比,可以采取饼图。将用户类型作为标签,用户类型对应的数量作为数据计算占比,可以很直观地看到各类型用户的占比情况。

plt.figure(figsize=(14, 10))
plt.pie(customer, labels=customer.index, autopct='%0.1f%%')
plt.title('不同客户的占比情况', fontsize=16)

从显示的柱状图和饼图可以发现,一般发展用户和一般挽留用户的人数偏多。

对于一般发展用户较多的情况,问题可能在于一般发展用户后续的复购转化不足。可以多通过短信、平台网站等渠道,在一般发展用户首购后的一段时间内可以领取复购券等策略,将这类用户转化为更高价值的用户类型。

对于一般挽留用户较多的情况,问题可能在于平台的产品竞争力或者服务不足。可以多对比竞品公司的产品,对自身的产品进行提升。同时,可以采取赠送优惠券的策略,并收集用户对平台产品以及服务的评价。

具体情况还需要对这两类用户进行深入分析。

至此,我们的案例已经学习完毕,让我们再来回顾这个案例。

某电商平台由于没有做好用户的分类,对所有用户都使用同样的销售策略,导致平台收到各种各样的投诉问题。

为解决这个问题,公司采取使用 RFM 模型对用户进行分类,再根据不同用户的特性,提供有针对性的营销策略。

根据 RFM 模型分析各个用户的最小时间间隔、消费频率、消费金额,再根据用户分类规则表对比后得知,公司的一般发展用户以及一般挽留用户占比较多,需要深入分析这两类用户,并制定有针对性的策略,如复购券赠送、平台问卷调查等。

案例回顾完毕。

举报

相关推荐

0 条评论