第三章:用python实现常用的用户分层模型(RFM模型)
本文可以学习到以下内容:
- RFM 模型的原理及代码实现
- 使用 pandas 中的 read_sql 读取 sqlite 中的数据
- 使用 dropna 删除含有缺失数据的行
- 使用 to_datetime、map 方法计算距离用户上次消费所过去的天数
- 使用 groupby+agg 方法统计消费频次、消费总金额
- 使用 merge 方法合并 datafram 数据
- 使用 quantile 方法计算用户消费数据的分位数
- 使用 cut 方法将消费数据划分不同的区间,并打上不同的标签
- 使用 value_counts 方法统计各个用户标签的数据量及占比
- 使用 pyecharts 绘制环形图
项目背景
运营部的同学需要对客户进行分类管理,需要数据部门提供一个方案进行参考。
小凡提出用RFM模型可以快速方便的将用户进行区分,模型的含义:
Recent:用户最近一次购买商品距今的时长
Frequency:用户在一段时间购买商品的次数
Mount:用户在一段时间内消费的金额
将这三个维度的数据划分不同的区间,每个区间对应相应的分数,最后根据总分将用户划分不同的标签,方便管理。
众人听后,一致通过该方案,并任命小凡为该项目的负责人。
读取数据
小凡常用的数据分析工具:
import os
import datetime
import numpy as np
import pandas as pd
from sqlalchemy import create_engine
数据放在上一级的目录下名为 data.db 的文件
# 数据库地址:数据库放在上一级目录下
db_path = os.path.join(os.path.dirname(os.getcwd()), "data.db")
engine_path = "sqlite:///" + db_path
# 创建数据库引擎
engine = create_engine(engine_path)
# sql 语句
sql = """
select * from business
"""
# read_sql 获取数据
df = pd.read_sql(sql,engine)
# 随机展示 5
df.sample(5)

user_id:用户唯一id字段
create_time:订单创建时间
order_id:订单id
amount:订单金额
df.info()

可以看到create_time数据量为76048,amount的数据量为76043,说明数据中存在缺失,而且缺失数据占比不大,所以,使用 dropna 方法将含有缺失的数据删除。
# create_time和amount有缺失值,去掉缺失值
df2 = df.copy()
# dropna() 默认只要该行有 nan 值就删除
df2 = df2.dropna()
df2.info()

# 查看数据量
len(df2.user_id.unique())
# 55540
删除后的数据有76041条,有55540名客户。
数据分析
分析 Recent
数据中的 create_time 为订单创建时间,可以用 to_datetime 方法计算出时间差
同一个用户又有多次购买记录,用 groupby 和 agg 的方法统计出最小的时间差
now_ = pd.to_datetime(datetime.datetime.now())
# 添加时间差数据
df2["recent"] = df2["create_time"].map(lambda x:(now_-pd.to_datetime(x)).days)
df2.sample(5)

# 用户最近一次购买商品的时间
recent_df = df2.groupby(by="user_id",as_index=False).agg({"recent":"min"})
分析 Frequency
根据 user_id 将用户分组,对 order_id 计数计算出用户的购买频率
frequency_df = df2.groupby(by="user_id",as_index=False).agg({"order_id":"count"})
frequency_df.sort_values(by="order_id",ascending=False).head()

分析 Mount
根据 user_id 将用户分组,对 amount 求和计算出用户的消费金额
mount_df = df2.groupby(by="user_id",as_index=False).agg({"amount":"sum"})
mount_df.sort_values(by="amount",ascending=False).head()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e87f8pc8-1641883628124)(./图片/6.png)]
RFM模型
将分析完成的数据根据 user_id 合并到一起方便分析
# 根据 user_id 合并数据
rfm_df = recent_df.merge(
frequency_df,on="user_id",how="left"
).merge(
mount_df,on="user_id",how="left"
)
rfm_df2 = rfm_df.copy()
rfm_df2.head()

分位数分层
np.linespace 获取(0,1)之间的等分点
quantile 根据划分好的等分点,计算出对应的原始数据
mount_labels = [1,2,3,4,5]
m_bins = rfm_df2["amount"].quantile(q=np.linspace(0,1,num=6),interpolation='nearest')
recent_labels = [5,4,3,2,1]
r_bins = rfm_df2["recent"].quantile(q=np.linspace(0,1,num=6),interpolation='nearest')
rfm_df2["R"] = pd.cut(rfm_df2["recent"],bins=r_bins,labels=recent_labels,include_lowest=True)
rfm_df2["M"] = pd.cut(rfm_df2["amount"],bins=m_bins,labels=mount_labels,include_lowest=True)
rfm_df2.head()

自定义分层
客户的购买频率集中在1次,使用分位数效果不佳,用自定义的区间来划分
frequency_bins = [1,3,5,12]
frequency_labels = [1,2,3]
rfm_df2["F"] = pd.cut(
rfm_df2["order_id"]
,bins=frequency_bins
,labels=frequency_labels
,include_lowest=True
)
rfm_df2.sample(5)

定义客户标签
定义一个总分 RFM,其中各权益的占比为 R:F:M=3:2:2
使用 cut 客户划分为 5 个不同的等级
使用 value_counts 统计各标签的数量
rfm_df2 = rfm_df2.astype(int)
rfm_df2["RFM"] = rfm_df2["R"]*3+rfm_df2["F"]*2+rfm_df2["M"]*5
rfm_bins =rfm_df2["RFM"].quantile(q=np.linspace(0,1,num=6),interpolation='nearest').unique()
rfm_labels = ['流失客户','一般维持客户','重要挽留客户','重要唤回客户','重要价值客户']
rfm_df2["客户标签"] = pd.cut(
rfm_df2["RFM"],
bins=rfm_bins,
labels=rfm_labels,
include_lowest=True,
duplicates="drop"
)
rfm_df2["客户标签"].value_counts()

数据可视化
用 pyecharts 可视化绘制饼图
from pyecharts import options as opts
from pyecharts.charts import Pie
from pyecharts.faker import Faker
i = rfm_df2["客户标签"].value_counts().index.tolist()
v = rfm_df2["客户标签"].value_counts().values.tolist()
c = (
Pie()
.add(
"",
[list(z) for z in zip(i, v)],
radius=["30%", "75%"],
)
.set_global_opts(
title_opts=opts.TitleOpts(title="客户分层占比"),
legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%"),
)
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
)
c.render_notebook()

结论
RFM模型不需要任何算法的支撑,除python外,excel、sql等工具都可以实现。核心思想就是将三个指标划分出不同的区间,根据区间的不同获取相应的权重。
小凡完成该模型后,将输出的结果保存为 Excel 发给运营部,为业务人员对客户采用不同的营销方式提供了参考。
源码地址
链接:https://pan.baidu.com/s/1JGZjJsABkWA52OFPaLMP2g?pwd=jle6
提取码:jle6
第三章:用python实现常用的用户分层模型(RFM模型)的更多相关文章
- 第三章:Python高级编程-深入类和对象
第三章:Python高级编程-深入类和对象 Python3高级核心技术97讲 笔记 3.1 鸭子类型和多态 """ 当看到一直鸟走起来像鸭子.游泳起来像鸭子.叫起来像鸭子 ...
- 第三章:Python基础の函数和文件操作实战
本課主題 Set 集合和操作实战 函数介紹和操作实战 参数的深入介绍和操作实战 format 函数操作实战 lambda 表达式介绍 文件操作函数介紹和操作实战 本周作业 Set 集合和操作实战 Se ...
- 2018-06-20 中文代码示例视频演示Python入门教程第三章 简介Python
知乎原链 Python 3.6.5官方入门教程中示例代码汉化后演示 对应在线文档: 3. An Informal Introduction to Python 不知如何合集, 请指教. 中文代码示例P ...
- 《Interest Rate Risk Modeling》阅读笔记——第三章:拟合期限结构
目录 第三章:拟合期限结构 思维导图 扩展 第三章:拟合期限结构 思维导图 扩展 NS 模型的变种
- python学习心得第三章
python学习心得第三章 1.三元运算 变量=值1 if 条件 else 值2 由图如果条件成立则赋值1给变量,如果条件不成立则赋值2给变量. 2.数据类型 集合:set() class set(o ...
- 跟着高淇学Python——第一到第三章总结
2019/10/26 第一章:Python介绍 Python是一种解释型,面向对象的语言.特点是: 可读性强 简洁,简洁 面向对象 免费开源 可移植性和跨平台性 丰富的库 可扩展性 应用范围:1.人工 ...
- Python黑帽编程3.0 第三章 网络接口层攻击基础知识
3.0 第三章 网络接口层攻击基础知识 首先还是要提醒各位同学,在学习本章之前,请认真的学习TCP/IP体系结构的相关知识,本系列教程在这方面只会浅尝辄止. 本节简单概述下OSI七层模型和TCP/IP ...
- 《python核心编》程课后习题——第三章
核心编程课后习题——第三章 3-1 由于Python是动态的,解释性的语言,对象的类型和内存都是运行时确定的,所以无需再使用之前对变量名和变量类型进行申明 3-2原因同上,Python的类型检查是在运 ...
- python学习笔记——第三章 串
第三章 字符串学习 1.字符串不灵活, 它不能被分割符值 >>> format = "hello, %s. %s enough for ya?" >> ...
- 简学Python第三章__函数式编程、递归、内置函数
#cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...
随机推荐
- 基于DFA算法实现的敏感词过滤
本文转自浅析敏感词过滤算法(C++),自己也在其基础上根据自己的情况做了一点修改. https://blog.csdn.net/u012755940/article/details/51689401? ...
- C#中定时任务被阻塞问题
目录 解决一个C#中定时任务被阻塞问题 1.摘要 2.C#中定时任务的最简方法 3.定时任务阻塞现象 4.阻塞现象原因分析 5.问题解决 1.摘要 本文会介绍一个C#中最简单定时任务的使用方法,以及会 ...
- Python170道面试题
1. 谈谈对 Python 和其他语言的区别 答:Python 是一门语法简洁优美,功能强大无比,应用领域非常广泛,具有强大完备的第三方库,他是一门强类型的可移植.可扩展,可嵌入的解释型编程语言,属于 ...
- Quartz 2D实现文字镂空效果
什么是镂空效果,下图就是一个镂空效果的文字: 从图可知,文字是透明的,可以看到下面的图片内容,而UILabel其它部分是白色背景. 使用Quartz 2D绘制镂空效果,大体思路如下: 实现一个UILa ...
- js获取对象数组中指定属性值的新数据
例: let arr = [ {name: "name1", age: "1",type:"1"}, {name: "name2& ...
- 浏览器是如何区分http和https协议的
浏览器的默认解析 我们在浏览器的地址栏中输入一个域名 taobao.com(不要按回车), 然后将地址栏进行复制,粘贴到文本文件后,发现是 http://taobao.com/. 这是浏览器的默认解析 ...
- vscode中使用powershell显示分支名
https://blog.csdn.net/weixin_43932597/article/details/125000557 windows powershell(或windows terminal ...
- new与delete只能被重载为成员函数;而<<等只能被重载为非成员函数
链接:https://www.nowcoder.com/questionTerminal/5760864337084de6891a9944f41e60f4来源:牛客网 应用程序可以将重载的new/de ...
- redis分布锁
1.redis分布式锁应用的场景? 1)防止缓存穿透:热点数据过期,大量线程访问mysql 2) 防止秒杀超卖:库存数量同步给redis后,对redis数据进行扣减 3)双写一致性:缓存的数据,被修 ...
- PyQt5弹框定时关闭(python)
PyQt5使用QMessageBox,可以设置在几秒后关闭 (作者使用的python3) info_box = QMessageBox()# 因为没使用这种方式 QMessageBox.inform ...