前言:
该案例由随机生成数据模拟半年时间内,对游戏用户充值金额情况进行用户价值分层
数据特征:
所有数据均为随机生成数据,一共有三个数据特征,分别是
r_datatime:充值时间,时间截格式,由radar库生成,时间范围为:2022-6-1至2022-12-30
r_uid:用户ID,字符串格式,由numpy库生成,以9开头生成1000个用户ID
r_price:充值金额,数值格式,由numpy库生成,随机抽取[10,60,180,300,680,1180,1980,3480,6480]中的一个充值面额
实践思路:
1.导入相关模块,生成随机数据
2.设置数据格式和调整显示方式
3.搭建RFM用户价值分层模式
4.按等距分箱的形式给用户打分
5.统计各层用户数量情况
案例详解:
导入相关模块,如果没有,则手动安装,安装方式: pip install 库名
import pandas as pd # pip install pandas
import radar # pip install radar
import numpy as np # pip install numpy
生成随机时间
时间选取了2022年下半年,可自行调整时间节点
r_datatime = []
for d in range(10000):d = str(radar.random_datetime("2022-6-1", "2022-12-30"))r_datatime.append(d)
生成随机金额
充值面额参考了王者荣耀的充值面额,可自行调整面额数值
# 生成随机金额
r_price = []
for p in range(10000):p = np.random.choice([10, 60, 180, 300, 680, 1180, 1980, 3480, 6480])r_price.append(p)
生成1000个用户(以9开头)
数据总行数为10000条,可根据需求自行调整用户个数
r_uid = []
for u in range(10000):u = str(np.random.randint(999999000, 1000000000))r_uid.append(u)
合并数据
注:每行数据均表示为2022-6-1至2022-12-30期间,1000个用户中的一个用户充值了随机面额
data = pd.DataFrame(data={"uid": r_uid, "price": r_price, "date": r_datatime})
设置数据格式和调整显示方式
pd.set_option('expand_frame_repr', False) # 当列太多时显示不清楚
pd.set_option('display.unicode.east_asian_width', True) # 设置输出右对齐
data['date'] = data['date'].astype('datetime64[ns]')
data['date'] = pd.to_datetime(data['date']).dt.floor('d') # 调整时间格式,只保留日期
注意:生成用户ID时,已设置调整为字符串格式,而randint是随机生成指定范围内的整数,只有时间需要另外调整格式
搭建RFM用户价值分层模式
RFM = data.groupby('uid', as_index=False).agg(last_date=('date', 'max'),F=('date', 'count'),M=('price', 'sum'))
RFM['R'] = (pd.to_datetime('2022-12-31') - RFM['last_date']).dt.days
RFM.drop(columns=['uid', 'last_date'], inplace=True)
按等距分箱的形式给用户打分
以下面参数为例,因为10000条数据中有1000个用户的付费情况,因此单个用户的最后付费时间R有可能拉的很长。通过统计总数据的充值均数,平均用户充值额度为1600左右,因此把F区间设置在25以下,50为假设区间(报错就往上调整)M值参考了王者荣耀的贵族阶级分层,略微调整了下,各位可自行根据数据分布设置合理区间(主要是懒得去琢磨了)。
RFM['R_score'] = pd.cut(RFM['R'],right=False,bins=[1, 7,14,30,90,200],labels=[5, 4, 3, 2, 1]).astype('int')
RFM['F_score'] = pd.cut(RFM['F'],right=False,bins=[0,4,8,10,12,50],labels=range(1, 6)).astype('int')
RFM['M_score'] = pd.cut(RFM['M'],right=False,bins=[1,500,2000,10000,40000,100000],labels=range(1, 6)).astype('int')
注意:
bins为划分范围,受用户数量、时间范围以及充值面额的影响,
因此,在调整过程中,注意适当调整bins的划分区间
用户分数统计后,根据用户评分情况设立标签
# 按平均值划分高低
RFM['R_level'] = (RFM['R_score'] >= RFM['R_score'].mean()) * 1
RFM['F_level'] = (RFM['F_score'] >= RFM['F_score'].mean()) * 1
RFM['M_level'] = (RFM['M_score'] >= RFM['M_score'].mean()) * 1
RFM['用户类别'] = RFM['R_level'].astype('str').str.cat([RFM['F_level'].astype('str'), RFM['M_level'].astype('str')])
RFM['用户类别'] = RFM['用户类别'].replace(['111', '110', '101', '100', '011', '010', '001', '000'],['重要价值客户', '一般价值客户', '重要发展客户', '一般发展客户', '重要保持客户', '一般保持客户', '重要挽留客户', '一般挽留客户'])
注:标签的评分定义可自行调整,作者是直接按平均数来划分
统计各层用户数量情况
最后,统计每个层次的用户数量,根据分布情况分析用户近半年的付费意愿
data = RFM.groupby('用户类别').agg(num=('F', 'count')).sort_values(by='num', ascending=False).reset_index()
完整代码:
# !/usr/bin/python3.7
# -*- coding:utf-8 -*-
# @author:inganxu
# CSDN:inganxu.blog.csdn.net
# @Date:2022年10月25日import pandas as pd
import radar
import numpy as np# 生成随机时间
r_datatime = []
for d in range(10000):d = str(radar.random_datetime("2022-6-1", "2022-12-30"))r_datatime.append(d)# 生成随机金额
r_price = []
for p in range(10000):p = np.random.choice([10, 60, 180, 300, 680, 1180, 1980, 3480, 6480])r_price.append(p)# 生成1000个用户
r_uid = []
for u in range(10000):u = str(np.random.randint(999999000, 1000000000))r_uid.append(u)data = pd.DataFrame(data={"uid": r_uid, "price": r_price, "date": r_datatime})
# 调整格式
pd.set_option('expand_frame_repr', False) # 当列太多时显示不清楚
pd.set_option('display.unicode.east_asian_width', True) # 设置输出右对齐
data['date'] = data['date'].astype('datetime64[ns]')
data['date'] = pd.to_datetime(data['date']).dt.floor('d') # 调整时间格式,只保留日期# RFM用户价值分层模型
RFM = data.groupby('uid', as_index=False).agg(last_date=('date', 'max'),F=('date', 'count'),M=('price', 'sum'))
RFM['R'] = (pd.to_datetime('2022-12-31') - RFM['last_date']).dt.days
RFM.drop(columns=['uid', 'last_date'], inplace=True)
print(RFM)
print('\n')
print('-' * 100)
print('\n')# 按等距分箱的形式计分
RFM['R_score'] = pd.cut(RFM['R'],right=False,bins=[1, 7,14,30,90,200],labels=[5, 4, 3, 2, 1]).astype('int')
RFM['F_score'] = pd.cut(RFM['F'],right=False,bins=[0,4,8,10,12,50],labels=range(1, 6)).astype('int')
RFM['M_score'] = pd.cut(RFM['M'],right=False,bins=[1,500,2000,10000,40000,100000],labels=range(1, 6)).astype('int')
# 按平均值划分高低
RFM['R_level'] = (RFM['R_score'] >= RFM['R_score'].mean()) * 1
RFM['F_level'] = (RFM['F_score'] >= RFM['F_score'].mean()) * 1
RFM['M_level'] = (RFM['M_score'] >= RFM['M_score'].mean()) * 1
RFM['用户类别'] = RFM['R_level'].astype('str').str.cat([RFM['F_level'].astype('str'), RFM['M_level'].astype('str')])
RFM['用户类别'] = RFM['用户类别'].replace(['111', '110', '101', '100', '011', '010', '001', '000'],['重要价值客户', '一般价值客户', '重要发展客户', '一般发展客户', '重要保持客户', '一般保持客户', '重要挽留客户', '一般挽留客户'])
print(RFM)
print('\n')
print('-' * 100)
print('\n')
# 统计各类别数量
data = RFM.groupby('用户类别').agg(num=('F', 'count')).sort_values(by='num', ascending=False).reset_index()
print(data)
结语:
该案例主要是为搭建RFM用户价值模型提供代码思路
数据分析方法-RFM用户价值分层模型_inganxu的博客-CSDN博客_rfm分类法优缺点