RFM简介
RFM是3个指标的缩写,最近一次消费时间间隔(Recency),消费频率(Frequency),消费金RFM是3个指标的缩写,最近一次消费时间间隔(Recency),消费频率(Frequency),消费金额(Monetary)。
- 消费时间间隔®,上一次消费离得越近,R的值越小,用户价值越高。
- 消费频率(F)越高,F的值越大,用户价值越高。
- 消费金额(M)越高,M的值越大,用户价值越高。
基于RFM的精细化用户管理
1.案例数据
案例数据是某企业从2015年到2018年共4年的用户订单抽样数据。其中记录数分别为30774、41278、50839、81349,有NA值,有异常值。
订单数据:
- 会员ID:每个会员的ID唯一,由纯数字组成。
- 订单号:订单ID,每个订单的ID唯一,由纯数字组成。
- 提交日期:订单日提交日期。
- 订单金额:订单金额,浮点型数据。
会员等级: - 会员ID:该ID可与前面的订单表中的会员ID关联。
- 会员等级:会员等级以数字区分,数字越大,级别越高。
数据在Excel中包含5个sheet,前4个sheet以年份为单位存储为单个sheet中,最后一张会员等级表为用户的等级表。
2.数据处理
包括缺失值,异常值处理,以及数据转换等。
#去除异常值与缺失值
for ind,each_data in enumerate(sheet_datas[:-1]):#enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
sheet_datas[ind] = each_data.dropna()# 丢弃缺失值记录
sheet_datas[ind] = each_data[each_data['订单金额'] > 1]# 丢弃订单金额<=1的记录
sheet_datas[ind]['max_year_date'] = each_data['提交日期'].max() # 增加一列最大日期值
#计算各自年份的最大日期与每个行的日期的差,得到日期间隔
data_merge['date_interval'] = data_merge['max_year_date'] - data_merge['提交日期']
#为每个记录行发生的年份
data_merge['year'] = data_merge['提交日期'].dt.year
汇总:
#按会员ID做汇总
rfm_gb = data_merge.groupby(['year','会员ID'], as_index=False).agg({'date_interval':'min',
'提交日期':'count',
'订单金额':'sum'})
3.分析过程
数据分布:
#查看数据分布
desc_pd = rfm_gb.iloc[:,2:].describe().T
print(desc_pd)
count mean std min 25% 50% 75% max
r 148591.0 165.524043 101.988472 0.0 79.0 156.0 255.0 365.0
f 148591.0 1.365002 2.626953 1.0 1.0 1.0 1.0 130.0
m 148591.0 1323.741329 3753.906883 1.5 69.0 189.0 1199.0 206251.8
汇总后的数据总共有14万条,r和m的数据分布相对较为离散,而对于f,大部分用户的分布都趋近于1。因此,r和m本身能较好的区分用户特征,但f则无法区分(大量的用户只有1个订单)。
区间边界:
# 定义区间边界
r_bins = [-1,79,255,365] # 注意起始边界小于最小值
f_bins = [0,2,5,130]
m_bins = [0,69,1199,206252]
RFM因子权重:
基于会员等级来确定RFM三者的权重,基本思路是,建立一个rfm三个维度与会员等级的分类模型,然后通过模型输出维度的权重。
# 匹配会员等级和rfm得分
rfm_merge = pd.merge(rfm_gb,sheet_datas[-1],on='会员ID',how='inner')#使用merge方法合并两个数据框,关联主键是会员ID,匹配方式是内部匹配
通过RF获得RFM因子得分:
clf = RandomForestClassifier()
clf = clf.fit(rfm_merge[['r','f','m']],rfm_merge['会员等级'])
weights = clf.feature_importances_ #返回'r','f','m'三部分权重
print('feature importance:',weights)
RFM分箱得分:
rfm_gb['r_score'] = pd.cut(rfm_gb['r'], r_bins, labels=[i for i in range(len(r_bins)-1,0,-1)])
rfm_gb['f_score'] = pd.cut(rfm_gb['f'], f_bins, labels=[i+1 for i in range(len(f_bins)-1)])
rfm_gb['m_score'] = pd.cut(rfm_gb['m'], m_bins, labels=[i+1 for i in range(len(m_bins)-1)])
总得分:
# 加权得分
rfm_gb = rfm_gb.apply(np.int32) # cate转数值
rfm_gb['rfm_score'] = rfm_gb['r_score'] * weights[0] + rfm_gb['f_score'] * weights[1] + rfm_gb['m_score'] * weights[2]