机器学习实战案例用户RFM模型分层(八)

news2025/1/12 20:47:58

每个产品和公司都需要做用户的精细化运营,它是实现用户价值最大化和企业效益最优化的利器。通过将用户进行分层:如高价值用户、潜在价值用户、新用户、流失用户等,针对不同群体制定个性化的营销策略和客户服务,进而促进业务的增长和盈利。

RFM模型是用户分层最常用的模型之一。其他常见的用户分析模型还有:用户生命周期模型、行为分析模型、人口统计学模型等

  • 用户生命周期模型:将用户分为不同阶段,如获取、活跃、留存、流失等。是促活的重要模型。
  • 行为分析模型:基于用户行为和偏好的分类方法,将用户根据特定的行为和偏好进行分类,如购买偏好、浏览偏好、搜索偏好等
  • 人口统计学模型:基于用户基本信息和特征的分类方法,将用户根据性别、年龄、职业、地域等用户的基础属性进行分类用户标签。

RFM模型是一种基于用户购买行为的分析模型,R(Recency)表示用户上一次交易的间隔时间,F(Frequency)表示用户的消费频率,M(Monetary)表示消费金额。通过RFM值对用户进行分类和评估,以确定不同用户群体的价值和行为特征,从而优化营销策略和客户服务。

在这里插入图片描述

下面我们开始实战,实战之前,回顾一下六步法!

在这里插入图片描述

1、数据收集

这里是从测试商家导出的已完成的订单,使用的是测试数据,在数据准确性方面是不靠谱的,但是不影响我们实战练手!

依据RFM模型,我们需要关注的数据是:企业名称,订单时间,订单总金额

在这里插入图片描述

2、数据预处理

再来回顾一下数据预处理的套路!

在这里插入图片描述

2.1、数据可视化

Pandas 是数据预处理阶段的利器。他可以读入数据,清洗数据。

matplotlib 是数据可视化的利器。我们先观察一下,月订单数量的走势图。

import Pandas as pd
"""
1.数据可视化
"""
# 读入数据
orders_pd = pd.read_excel('用户订单.xlsx')

# 转化日期格式
orders_pd['订单时间'] = pd.to_datetime(orders_pd['订单时间'])
# 每个月的订单数量
df_orders = orders_pd.set_index('订单时间')['订单编号'].resample('M').nunique()

# 画布
pd.DataFrame(df_orders.values).plot(grid=True, figsize=(12, 6), legend=False)

# 设定X轴显示年月
plt.xticks(
    range(len(df_orders.index)),
    [x.strftime('%Y.%m') for x in df_orders.index],
    rotation=45)

# 绘图
plt.show()

在这里插入图片描述

可以看到,自2022年10月份以后,订单数量严重的下跌!可能是活动减少了!

2.2、数据清洗

统计空值(NaN)数据

"""
2.数据清洗
"""

# 统计NaN数据
nan_sum = orders_pd.isna().sum()
print(nan_sum)

运行结果:
在这里插入图片描述
统计NaN结果看到表格中有一些空值数据的,而我们关注的是企业名称、订单时间、订单总金额字段,他们都是只有1个数据是空值的,我们需要清理掉这些空值数据。

# 删除指定列的缺失值
orders_pd.dropna(subset=['订单时间', '订单编号', '企业名称', '订单总金额'])

对于数量、金额等类型的数据,我们还常常会使用 describe 方法来查看这些字段的统计信息是否有脏数据。

# 统计订单数据
describe = orders_pd['订单总金额'].describe() 
print(describe)

输出结果:(按照顺序依次是总数、均值、标准差、最小值、25% 分位数、中位数、75% 分位数和最大值)

在这里插入图片描述

describe 统计结果中可以看到,订单总金额 这个Excel列,最小值是 -12131,说明Excel中是有异常数据的,针对这种数据,我们需要清理掉,使用 DataFrame 过滤功能。

# 在 DataFrame 对象中,通过 loc 通过行、列的名称来访问数据
orders_pd = orders_pd.loc[orders_pd['订单总金额'] > 0]

清理后的订单金额数据正常了!

在这里插入图片描述

2.3特征工程 - 求RFM值

特征工程就是基于业务特性,从众多的特征中发现对标签有明显作用的特征,而摒弃掉无用的特征,降低特征的维度,提升机器学习模型的性能。

求用户的RFM值,严格意义上来讲并不算是特征工程,我们只是把表格中的数据加工成对应的RFM特征值。

RFM值如何获得呢?

  1. R值:用户上一次交易的间隔时间,通过订单时间可以求得。
  2. F值:用户的消费频率,根据下单次数可以求得。
  3. M值:用户的消费金额,根据订单总金额可以求得。

构建以用户(企业名称)为主键的表格

"""
3.求RFM值
"""

# 1.构建以企业名称为主键的表格
user = pd.DataFrame(orders_pd['企业名称'].unique())
print(user)

可以看到一共有149个用户下单。
在这里插入图片描述

下面我们开始分别求RFM值:
1)求R值:用户上一次交易的间隔时间

# 2.求R值

# 转化日期格式
orders_pd['订单时间'] = pd.to_datetime(orders_pd['订单时间'])
# 构建消费日期信息
user_recent_buy = orders_pd.groupby('企业名称').订单时间.max().reset_index()
# 设定字段名
user_recent_buy.columns = ['企业名称', '最近日期']
# 计算最新日期与上次消费日期的天数
user_recent_buy['R值'] = (user_recent_buy['最近日期'].max() - user_recent_buy['最近日期']).dt.days
# 把上次消费距最新日期的天数(R值)合并至df_user结构
user = pd.merge(user, user_recent_buy[['企业名称', 'R值']], on='企业名称')
print(user)

在这里插入图片描述

在 149 个用户中,大哥大已经915天没有消费了,这个用户已经流失了。

2)求F值:用户的消费频率,通过 count() 计算订单总数获得。

# 3.求F值

# 计算每个用户消费次数
df_frequency = orders_pd.groupby('企业名称').订单时间.count().reset_index()
df_frequency.columns = ['企业名称', 'F值']
# 把F值合并到user表
user = pd.merge(user, df_frequency, on='企业名称')
print(user)

输出结果:

在这里插入图片描述

企业名称:0716企业名称992 用户消费了92次,而大哥大只消费了1次。

3)求M值:用户的消费金额,通过 sum()计算用户的累计订单金额。

# 4.求M值

# sum 函数计算总金额
user_total_money = orders_pd.groupby('企业名称').订单总金额.sum().reset_index()
user_total_money.columns = ['企业名称', 'M值']
# 把M值合并到user表
user = pd.merge(user, user_total_money, on='企业名称')
print(user)

输出结果:

在这里插入图片描述

用户:0716企业名称992 虽然消费了92次,但是订单金额只有6.76;大哥大虽然只消费了1次,但是消费金额1211元。

3、选择算法

请注意这个问题,这个案例到底属于哪类问题呢?监督学习?无监督学习?

这个问题是一个无监督学习类问题。别看RFM值我们已经计算得出来了!我们的数据集是没有标签的,在数据集中并没有标注出哪个用户价值高,哪个用户价值低,所以这属于无监督学习问题。并且是无监督学习中的聚类问题(我们要按照用户的高低价值,对用户进行分类)。

无监督学习算法又分为聚类算法和降维算法,那这里我们选择聚类算法中的K-Means算法

在这里插入图片描述

K-Means算法介绍

K-Means算法是一种基于距离的聚类方法,其原理是将数据集划分为K个簇。使得每个簇内的数据点距离簇中心最近,而不同簇之间的数据点距离簇中心最远。

K-Means算法原理图如下:3个簇表示有3个聚类,K = 3。每个簇内的数据点距离质心最近。

在这里插入图片描述

具体实现过程如下:

  1. 随机选择K个初始簇中心。
  2. 计算每个数据点到K个簇中心的距离,并将每个数据点划分到距离最近的簇。
  3. 对于每个簇,重新计算簇中心。
  4. 重复步骤2和3,直到簇中心不再发生变化或达到最大迭代次数。

K值是最重要的参数,那么K值该如何确定呢?

由于RFM模型是比较成熟的用户分析模型了!通常通过三维坐标系来对用户进行分层。共计分为8种类型,那在K-Means聚类算法中,就是分为8个簇也就是8种不同的用户群体。

在这里插入图片描述

对三维坐标进行拆解,得到如下表格形式的用户分层规则数据。

在这里插入图片描述

4、通过K-Means算法聚类

当K值确定好以后,我们就可以通过K-Means算法对用户RFM进行聚类了。聚类分为三步:创建K-Means模型、拟合模型、聚类。

在这里插入图片描述

1、创建K-Means模型,K = 8

# 创建了一个 K-Means 聚类模型。
# K = 8
kmeans_R = KMeans(n_clusters=8)
kmeans_F = KMeans(n_clusters=8)
kmeans_M = KMeans(n_clusters=8)

2、fit 拟合模型

# 拟合模型
kmeans_R.fit(user[['R值']])
kmeans_F.fit(user[['F值']])
kmeans_M.fit(user[['M值']])

3、predict 聚类

# 通过聚类模型求出R值的层级
user['R值层级'] = kmeans_R.predict(user[['R值']])
user['F值层级'] = kmeans_F.predict(user[['F值']])
user['M值层级'] = kmeans_M.predict(user[['M值']])

观察一下聚类后的数据情况

1)统计R值的层级

#R值层级分组统计信息
user.groupby('R值层级')['R值'].describe() 

输出如下:可以看到按照期望分成了8个簇,但是这里有一个问题,就些数据是没有任何顺序的!这是聚类这种算法本身的问题。聚类只是把相邻数据分成一个簇,但是它并不知道簇是什么含义,更不知道如何排序。

在这里插入图片描述

很关键的一步:聚类的结果,需要我们人为地给这些用户组贴标签,看看哪一组价值高,哪一组价值低。

这里我们定义一个排序的方法 order_cluster

定义一个order_cluster函数为聚类排序

def order_cluster(cluster_name, target_name , df ,ascending=False):
    # 新的聚类名称
    new_cluster_name = 'new_' + cluster_name
    # 按聚类结果分组,创建df_new对象
    user_new = df.groupby(cluster_name)[target_name].mean().reset_index()
    # 排序
    user_new = user_new.sort_values(by=target_name,ascending=ascending).reset_index(drop=True)
    # 创建索引字段
    user_new['index'] = user_new.index
    # 基于聚类名称把user_new还原为df对象,并添加索引字段
    user_new = pd.merge(df,user_new[[cluster_name,'index']], on=cluster_name)
    # 删除聚类名称
    user_new = user_new.drop([cluster_name],axis=1)
    # 将索引字段重命名为聚类名称字段
    user_new = user_new.rename(columns={"index":cluster_name})
    # 返回排序后的user_new对象
    return user_new

对R值层级的簇进行排序

# 调用簇排序函数
user = order_cluster('R值层级', 'R值', user, False)
# 根据用户码排序
user = user.sort_values(by='企业名称', ascending=True).reset_index(drop=True)

统计排序后的R值层级的信息

# R值层级分组统计信息
user.groupby('R值层级')['R值'].describe() 

统计R值层级输出结果如下:此时输出了8个簇,从 07簇平均值依次减少的,表示用户距离上一次消费间隔时间逐渐变小,因此R值层级,从07价值依次是升高的。

在这里插入图片描述

2)同样方案统计F值数据

user = order_cluster('F值层级', 'F值', user, True)
print(user.groupby('F值层级')['F值'].describe())

在这里插入图片描述

3)同样方案统计M值数据

user = order_cluster('M值层级', 'M值', user, True)
print(user.groupby('M值层级')['M值'].describe())

在这里插入图片描述

至此,用户的RFM值全部计算出来了,以及RFM层级都已经通过聚类算法计算出来了。

在这里插入图片描述

根据用户的指标,我们将 RFM值分为高低

在这里插入图片描述

根据RFM模型将用户分为8个不同的群体

在这里插入图片描述

对聚类后的数据,按照8个群体为用户贴标签

#在df_user对象中添加总体价值这个字段
user.loc[(user['R值层级']>=4) & (user['F值层级']>=5) & (user['M值层级']>=2), '用户群体'] = '重要价值客户'
user.loc[(user['R值层级']>=4) & (user['F值层级']<5) & (user['M值层级']>=2), '用户群体'] = '重要发展客户'
user.loc[(user['R值层级']<4) & (user['F值层级']>=5) & (user['M值层级']>=2), '用户群体'] = '重要保持客户'
user.loc[(user['R值层级']<4) & (user['F值层级']<5) & (user['M值层级']>=2), '用户群体'] = '重要挽留客户'
user.loc[(user['R值层级']>=4) & (user['F值层级']>=5) & (user['M值层级']<2), '用户群体'] = '一般价值客户'
user.loc[(user['R值层级']>=4) & (user['F值层级']<5) & (user['M值层级']<2), '用户群体'] = '一般发展客户'
user.loc[(user['R值层级']<4) & (user['F值层级']>=5) & (user['M值层级']<2), '用户群体'] = '一般保留客户'
user.loc[(user['R值层级']<4) & (user['F值层级']<5) & (user['M值层级']<2), '用户群体'] = '一般挽留客户'

输出一下用户分群体后的User表

在这里插入图片描述

通过 describe函数汇总一下各个用户群体及数量

在这里插入图片描述

可以看到这个商家的经营状况不好,大部分用户都流失了!需要考虑为不同用户群体制定运营策略,以提升客户价值和营收水平。

本案例中,我们使用K-Means聚类算法依据RFM模型实现了对用户的分层。除此之外,K-Means算法常见的应用场景还有文本聚类、风险监测等。

  1. 文本聚类:根据文档内容或主题对文档进行聚类,用以帮助文本挖掘和信息检索等领域对文本进行有效分类和分析,识别潜在的主题和信息,提高文本处理和分析的效率和精度。
  2. 风险监测:在金融风控场景中,通过对用户交易行为做聚类分析。根据每个群体的特征识别潜在的欺诈行为,并及时采取措施防范风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/629163.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java|golang】2465. 不同的平均值数目

给你一个下标从 0 开始长度为 偶数 的整数数组 nums 。 只要 nums 不是 空数组&#xff0c;你就重复执行以下步骤&#xff1a; 找到 nums 中的最小值&#xff0c;并删除它。 找到 nums 中的最大值&#xff0c;并删除它。 计算删除两数的平均值。 两数 a 和 b 的 平均值 为 (a…

(转载)基于蚁群算法的二维路径规划(matlab实现)

1 理论基础 1.1 路径规划算法 路径规划算法是指在有障碍物的工作环境中寻找一条从起点到终点的、无碰撞地绕过所有障碍物的运动路径。路径规划算法较多&#xff0c;大体上可分为全局路径规划算法和局部路径规划算法两类。其中&#xff0c;全局路径规划方法包括位形空间法、广…

Android进阶之路 - 字体自适应

开发中有很多场景需要进行自适应适配&#xff0c;但是关于这种字体自适应&#xff0c;我也是为数不多的几次使用&#xff0c;同时也简单分析了下源码&#xff0c;希望我们都有收获 很多时候控件的宽度是有限的&#xff0c;而要实现比较好看的UI效果&#xff0c;常见的处理方式应…

深度学习的低秩优化:在紧凑架构和快速训练之间取得平衡(上)

论文出处&#xff1a;[2303.13635] Low Rank Optimization for Efficient Deep Learning: Making A Balance between Compact Architecture and Fast Training (arxiv.org) 由于篇幅有限&#xff0c;本篇博客仅引出问题的背景、各种张量分解方法及其分解FC/Conv层的方法&#x…

js算法基础01 --- 数组对象去重

菜狗子的自我救赎01 01- 数组对象去重reduce原生js 利用newObj 和 newArr利用空数组 和 标识flag多条件去重 假设 不知拿id 做对比 还有id2 id 3利用双指针 splice 01- 数组对象去重 把下面数组对象去重 let arr [{ id: 1, name: 周瑜 },{ id: 3, name: 王昭君 },{ id: 2, na…

手动管理采购订单周期的挑战以及如何应对

在过去的几十年里&#xff0c;采购实践有了显著的进步。精明的采购领导正在寻求额外的周期时间的提升。这一点至关重要&#xff0c;因为减少周期时间可以大大提升周转时间&#xff0c;降低你的采购职能的整体成本。它也使采购团队能够将较多的时间用于战略活动。 但是&#xf…

【八大排序(一)】排序还只会用冒泡?进来给我学!

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:八大排序专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习排序知识   &#x1f51d;&#x1f51d; 插入,希尔排序 1. 前言&#x1f6a9;2. 插…

【Protobuf】Protobuf快速使用 Java版、Python版

【Protobuf】Protobuf快速使用 Java版、Python版 Protobuf介绍 快速使用(Java版) 创建 .proto文件&#xff0c;定义数据结构 安装Protobuf编译器(二选一) 使用IDEA编译(二选一) 使用编译后的文件 快速使用(Python版) 创建 .proto文件&#xff0c;定义数据结构 安装Prot…

【Spring源码解读三】IoC容器之AnnotationConfigApplication的refresh()刷新方法其二

invokeBeanFactoryPostProcessors() PriorityOrdered接口 Ordered接口 invokeBeanDefinitionRegistryPostProcessors() registerBeanPostProcessors() getBeanNamesForType() initMessageSource() initApplicationEventMulticaster() onRefresh() registerListeners()…

听我一句劝,别去外包,干了三年,真废了....

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

找不到xinput1_3.dll怎么办?xinput1_3.dll丢失的四个修复方法

在我们打开游戏的或者软件的时候&#xff0c;电脑提示“找不到xinput1_3.dll&#xff0c;无法继续执行此代码”怎么办&#xff1f;相信困扰着不少小伙伴&#xff0c;我再在打开吃鸡的时候&#xff0c;然后花了一上午的时候时间研究&#xff0c;现在终于知道xinput1_3.dll文件是…

Windows10系统开启 Telnet客户端 功能

1、应用场景 在实际工作中&#xff0c;经常有查看机器端口连通性的场景&#xff08;主要为了确认某台机器上的服务是否正常&#xff0c;比如&#xff1a;查看的端口 9091&#xff09; telnet 192.168.166.159 9091如下状态说明telnet 端口是通的 Ctrl ] ,退出Telnet连接&a…

探究Vue源码:mustache模板引擎(2) mustache使用方法

mustache是最早的模板引擎 比vue的诞生还要早很多 而他的语法 就是基于 {{ }} 这样的双花括号 mustache属于通用性的应用 他既可以在浏览器中直接用 也可以在npm中使用 这里 我们为了方便 就直接去拿在浏览器中使用的包了 没必要再自己搭个环境 大家可以下载我上传的资源 vue源…

职场老油条表示真干不过,部门新来的00后测试员已把我卷崩溃,想离职了...

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&#x…

Linux学习之vim正常模式和插入模式

使用vim新建或者打开一个文件后&#xff0c;首先进入的就是正常模式&#xff0c;从正常模式按不同的按键能够进入其他三种模式。 在正常模式下&#xff0c;按i&#xff0c;I&#xff08;大写的i键&#xff09;&#xff0c;a&#xff0c;A&#xff0c;o&#xff08;小写的o&…

【3DsMAX】从零开始建房(6)

目录 1. 制作广告牌 2. 制作屋顶小船船身 1. 制作广告牌 先创建一个长方体 转换为可编辑多边形&#xff0c;选中面&#xff0c;插入 挤出 添加两个圆柱体作为支架 用轮廓工具收一下面 选中这三个物体打组 统一材质 设置线条颜色为黑色 2. 制作屋顶小船船身 先添加一个球体&…

顺序表刷题(1~3)

目录 移除元素 删除有序数组重复项 合并有序数组 移除元素 方法一&#xff1a; 如果找到一个删除一个这样的时间复杂度为O(n^2)&#xff08;最坏删除所有数据&#xff09;删除后还要挪动数据。我们可以将符合条件的数组元素放入一个临时数组中&#xff0c;这种方法的时间复杂…

什么是数据结构

一、什么是数据结构 1、数据结构的定义 数据&#xff1a;从计算机的角度来看&#xff0c;数据是所有能被输入到计算机中且能被计算机处理的符号的集合。它是计算机操作的对象的总称&#xff0c;也是计算机处理信息的某种特定的符号表示形式&#xff08;二进制码的抽象表示&am…

【高级篇】服务异步通信

服务异步通信-高级篇 消息队列在使用过程中&#xff0c;面临着很多实际问题需要思考&#xff1a; 1.消息可靠性 消息从发送&#xff0c;到消费者接收&#xff0c;会经理多个过程&#xff1a; 其中的每一步都可能导致消息丢失&#xff0c;常见的丢失原因包括&#xff1a; 发送…

030 JavaWeb Html CSS

目录 JavaWeb概述1.访问web的原理2.C/S软件和B/S软件区别3.静态网站和动态网站 HTMLHTML的概述Table表格详细用法见W3CSchool.chm合并单元格课程表 img标签table和img标签组合使用a标签表单表单Get提交和post提交 div和span CSS1.CSS概述2.CSS语法3.CSS三种写法行内样式内部样式…