[Python]RFM用户分类模型, 加matplotlib可视化数据--在线教育行业分析案例连载1
文章目录
前言
该文章为连载的第一篇:RFM用户分类模型
某家在线教育机构拥有自己开发的教育产品VLE,该教育机构提供了他们四个学期里,开展的七门课的数据,接下来我会根据这些数据,为该教育机构做一系列的数据分析,包括用户的RFM模型、用户分群特征、用户成绩分析等等。
该教育机构部分数据库结构如下
如下这一篇文章为:用户的RFM模型
先简单介绍一下RFM模型:
RFM模型是衡量客户价值和客户创利能力的重要工具和手段。
该机械模型通过一个客户的
- 近期购买行为(R:Recency)、
- 购买的总体频率(F:Frequency)
- 花了多少钱(M:Monetary)
3项指标来描述该客户的价值状况。
该案例是在线教育产品,并且这里只提供用户一学期购买课程的消费注册使用情况,所以RFM会调正为:
- 近期产品使用行为(R:Recency)、
- 产品使用频率(F:Frequency)
- 花了多少钱(M:Monetary)
这个案例中计算用户RFM模型会用到:
- studentRegistration 学生注册信息表 (记为regi)
- studentVle 学生产品交互行为表 (记为vle)
- courses 课程表 (记为courses)
其中:
- code_presentation为学期
- code_module为课程
- 其他字面意思比较好理解
一、导入库
import pandas as pd
import numpy as np
import datetime
import time
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['Arial Unicode MS']
matplotlib.rcParams['axes.unicode_minus']=False
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn
from sklearn.preprocessing import LabelEncoder
np.set_printoptions(suppress=True)
pd.set_option('display.float_format', lambda x: '%.4f' % x)
二、构造价格数据
因为这里没有关于价格的数据,我们需要对每门课构造一个价格
构造价格的依据:
- 假设AAA是最简单的课程课程难度随着AAA、BBB、CCC递增,价格会越来越贵
- 假设课程价格的基准是10*时间长度,同时价格根据难度增加,BBB为11乘时间长度,CCC为12,以此类推
- 同时物价膨胀学校每年也会调整增10%的学费
实现代码如下(示例):
presentation=sorted(courses["code_presentation"].unique().tolist())
#presentation 为['2013B', '2013J', '2014B', '2014J']
module=sorted(courses["code_module"].unique().tolist())
#module 为['AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF', 'GGG']
这里需要注意的是,不是每一学期都会开展这七门课
#基准价格
x=10
module_price={}
for m in module:
module_price[m]=x+module.index(m)
#module_price 为{'AAA': 10, 'BBB': 11, 'CCC': 12, 'DDD': 13, 'EEE': 14, 'FFF': 15, 'GGG': 16}
#增加价格列,并用每门课基准价格乘时间长度
courses["price"]=courses["code_module"].map(module_price)
courses["price"]=courses["module_presentation_length"]*courses["price"]
#从第二学期开始,价格上升10%
for pre in presentation[1:]:
courses.loc[(courses["code_presentation"]==pre),"price"]*=(1.1)**(presentation.index(pre))
courses.sort_values(by=["code_presentation","code_module"]).head(10)
三、分别计算RFM信息
这里我们只选取最新的一个学期2014J计算
1、聚合所需要的信息
代码如下(示例):
#聚合【学生注册信息表】和【学生vle交互信息表】,筛选出这一学期的
#用how="outer"的原因是部分学生注册了但没有使用VLE
regi_vle_this_pre=pd.merge(regi[regi["code_presentation"]=="2014J"],vle[vle["code_presentation"]=="2014J"],on=["code_module","code_presentation","id_student"],how="left")
#并对注册但没有使用过产品的用户,点击数调整成0
regi_vle_this_pre["sum_click"]=regi_vle_this_pre["sum_click"].fillna(0)
regi_vle_this_pre[regi_vle_this_pre["sum_click"].isna()]
#再聚合【课程表】
df=pd.merge(regi_vle_this_pre,courses[courses["code_presentation"]=="2014J"][["code_module","price"]],on="code_module")
2、计算每个学生的购买课程总价
这学期有10670学生,大部分学生都只买了一门课,有586人买了两门课,2人买了3门课,具体计算先忽略。
amount=pd.crosstab(df["id_student"],df["code_module"],values=df["price"],aggfunc="mean").fillna(0).reset_index()
amount["total_amount"]=amount["AAA"]+amount["BBB"]+amount["CCC"]+amount["DDD"]+amount["EEE"]+amount["FFF"]+amount["GGG"]
amount.sort_values(by="total_amount",ascending=False)
#将总价也聚合到上面的表里
df=pd.merge(df,amount[["id_student","total_amount"]],on="id_student")
3、计算RFM各指标
对各项指标,去查看一个描述统计值,并用箱线图查看异常值是否较多,再定义怎么去界定RFM高低的界限。
3.1 R
df.groupby("id_student").agg({"date":"max"}).describe(percentiles=[.25,.5,.75,.8])
date_list=[x for x in df.groupby("id_student").agg({"date":"max"})["date"].values.tolist() if str(x)!="nan" ]
#去掉nan值
plt.boxplot(x=date_list)
plt.show()
date这里最大是开课后有269天,最小的是开课前25天,这里假设每门课的开课时间一致,现在就是开课后269天,我们拿到的数据都是更新的。
这里去定义7天内使用过的才算近期使用,即269-7=262以上为R近用户
3.2 F
df.groupby(["id_student"]).agg({"date":pd.Series.nunique}).describe(percentiles=[.25,.5,.75,.8])
plt.boxplot(df.groupby(["id_student"]).agg({"date":pd.Series.nunique})["date"].values)
plt.show()
中位数和平均数相差加大,呈左偏态分布
大多数用户使用次数较低,但有少部分用户使用次数异常高,拉高平均值
这里暂时取中位数值作为F的临界点,即42天。
3.3 M
df.groupby(["id_student"]).agg({"total_amount":"mean"}).describe(percentiles=[.25,.5,.75,.8])
plt.boxplot(df.groupby(["id_student"]).agg({"total_amount":"mean"})["total_amount"].values)
plt.show()
平均数比中位数略高,有部分偏高异常值,原因是
- 学生报名情况:这学期有10670学生,大部分学生都只买了一门课,有586人买了两门课,2人买了3门课
- 课程价格情况:
这里定义M高用户为选择课程价格为大于4500的用户
3.5 计算每个用户的RFM
回顾一下定义RFM各指标为高的界限:
- 前7天内有在使用产品为R高
- 在这学期中,使用产品超过42天为F高
- 购买价格课程大于4500为M高
df["cnt_use_day"]=df["date"]
rfm_df=df.groupby("id_student").agg({"date":"max","cnt_use_day":pd.Series.nunique,"total_amount":"mean","date_unregistration":"max"}).reset_index()
rfm_df["r"]=rfm_df["date"].apply(lambda x:1 if x>=262 else 0)
rfm_df["f"]=rfm_df["cnt_use_day"].apply(lambda x:1 if x>=42 else 0)
rfm_df["m"]=rfm_df["total_amount"].apply(lambda x:1 if x>=4500 else 0)
rfm_df["user_label"]=np.nan
RFM的标签分层(按RFM顺序):
(1,1,1)重要价值用户
(0,1,1)重要唤回客户
(1,0,1)重要深耕客户
(0,0,1)重要挽回客户
(1,1,0)潜力客户
(1,0,0)新客户
(0,1,0)一般维持客户
(0,0,0)流失客户
rfm_df.loc[(rfm_df["r"]==1)&(rfm_df["f"]==1)&(rfm_df["m"]==1),"user_label"]="重要价值用户"
rfm_df.loc[(rfm_df["r"]==0)&(rfm_df["f"]==1)&(rfm_df["m"]==1),"user_label"]="重要唤回用户"
rfm_df.loc[(rfm_df["r"]==1)&(rfm_df["f"]==0)&(rfm_df["m"]==1),"user_label"]="重要深耕用户"
rfm_df.loc[(rfm_df["r"]==0)&(rfm_df["f"]==0)&(rfm_df["m"]==1),"user_label"]="重要挽回客户"
rfm_df.loc[(rfm_df["r"]==1)&(rfm_df["f"]==1)&(rfm_df["m"]==0),"user_label"]="潜在用户"
rfm_df.loc[(rfm_df["r"]==1)&(rfm_df["f"]==0)&(rfm_df["m"]==0),"user_label"]="新用户"
rfm_df.loc[(rfm_df["r"]==0)&(rfm_df["f"]==1)&(rfm_df["m"]==0),"user_label"]="一般维持客户"
rfm_df.loc[(rfm_df["r"]==0)&(rfm_df["f"]==0)&(rfm_df["m"]==0),"user_label"]="流失用户"
rfm_df["user_label"].value_counts()
结果如下:
可视化:
plt.figure(figsize=(5,5))
cmap = plt.get_cmap("tab20c")
outer_colors = cmap(np.arange(8)*1)
#print(outer_colors)
data = rfm_df["user_label"].value_counts().sort_index().values.tolist()
label=rfm_df["user_label"].value_counts().sort_index().index.tolist()
#突出重要价值用户
plt.pie(data,pctdistance=0.7,autopct='%.1f%%',explode=(0,0,0,0,0.3,0,0,0),labels=label,colors=outer_colors)
plt.axis('equal')
plt.tight_layout()
plt.show()
同时这里我们有用户注册后注销的信息(date_unregistration),我们也可以看注销账号的用户里的用户分类:
rfm_df[rfm_df["date_unregistration"]>0]["user_label"].value_counts()
总结
从以上RFM信息看出,流失用户、一般维持用户占比较大,需要结合其他信息,做好精细化运营,促进学生使用产品,提升用户粘性。
同时在注销账号的用户中可以看到,注销用户较多,大约占25%,并且不少为R低F低M高的重要挽回用户,需要重点找到原因。
当我们拥有用户RFM标签,我们可以:
- 结合courses【课程表】去看是否有哪一门课的课程对用户吸引较大,能让用户持续使用产品
- 结合studentInfo【学生信息表】去重要价值用户有什么样的共性,比如重要价值用户中,多数学生为非贫困地区用户,某个年龄段的高频使用用户较多
- 结合studentAssessments【学生平时成绩表】去看流失用户、重要挽回用户有什么样的特征,是否他们的成绩较差而选择放弃使用,是否需要调正课程难度,评分标准
上一篇: 秒杀系统--动静分离
下一篇: PHP区间分页_PHP教程