欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python每日一记171>>>python实现RFM模型

程序员文章站 2024-01-21 12:41:16
...

之前有一篇文章写了RFM,但是并不是很准确,也有点繁琐,后来对此代码进行了修改,更加有意义。
除了RFM指标之外,还结合了自身公司的进行进行合理的分类,并且为每一个会员加上了高频消费专柜,这样也算是一个完整的会员标签了。
接下来先介绍会员的分类方案:
一、分析原因与初步想法
就目前而言,我们的会员分类主要的方法是按卡别、年龄、区域、性别。这些分类能对我们了解会员现状起到一定的作用,但存在缺陷。与卡别有直接相关性的其实是销售金额,体现为会员的消费能力层次,但是500—5000—30000的消费级别只是生硬的分类,虽然28定律指引我们需要关注会员的消费能力,但是作为会员管理,我们或许也应该多关注会员的消费频次等体现会员消费粘性的指标,毕竟开发一个新会员并维护的成本要远远高于留住一个老会员。
如果说我们要更好的进行分类,更好的维护会员,且想要数据有直接作用,那么有三个因素是或许是有效的:
1、 最近一次消费时间间隔,体现顾客的记忆强度,两者负相关;
2、 消费频次,体现会员消费粘性,两者正相关;
3、 消费金额,体现会员消费实力,两者正相关;
这也就是我们熟知的RFM模型。
二、RFM模型及在本公司可行性分析
2.1 RFM模型系统介绍
具体见以下图片:
Python每日一记171>>>python实现RFM模型
根据上图,我们最终的目的是考虑应用场景。
1、 R因素(最近一次消费时间间隔)
主要决定接触频率,刺激力度,上次消费时间间隔越长,越偏向于休眠会员,需要降低信息推送频率,且需要大力度刺激。上次消费时间间隔越短,可较高频率接触会员。
Python每日一记171>>>python实现RFM模型
2、 F因素(消费频次)
主要决定活动方案之活动类型,消费频率越高,越偏向于忠实会员,需要推送中大型活动/品牌活动/新品推荐/会员权益等。消费频率越低,需要推送促销信息。
Python每日一记171>>>python实现RFM模型
3、M因素(消费金额)
主要决定活动方案之活动类型与活动门槛,消费金额越高,越偏向于强消费实力,需推送大型活动,且门槛可以提高。消费金额低,需要推送促销信息,且门槛需要降低。
Python每日一记171>>>python实现RFM模型
2.2 RFM模型在本公司可行性分析
1、数据来源层面
数据需要信息部提供excel数据,再进行处理。
2、指标计算方面
因目前信息部提供的数据可带交易时间,因此可进行计算。
3、指标选择及策略方面
Python每日一记171>>>python实现RFM模型
三、建模实验
对2019/1/1-2019/9/15会员数据进行建模,以2019/9/19为时间基准。
先分别计算R、F、M值,再对每个值进行编码,这里各个指标分为三类,编码1、2、3,如上图,注意R越大,值越小。编码后,进行综合编码,这里采用连接法,如R、F、M值分别为1、2、3,则综合编码为123,直接连接。接下来对综合编码再次编码,直接用于会员分类和营销策略,为了方便,直接以中文描述的形式编码分类,而不采用数字或者字母。具体如下图
Python每日一记171>>>python实现RFM模型
接下来直接上代码了:

import pandas as pd
import numpy as np
import time
s=time.time()
# import matplotlib.pyplot as plt
# from mpl_toolkits.mplot3d import Axes3D
data_2015=pd.read_excel('Z:\\会员管理课\ywj严文杰\\带时间消费明细-持续更新\\15年消费明细.xlsx')
data_2016=pd.read_excel('Z:\\会员管理课\ywj严文杰\\带时间消费明细-持续更新\\16年消费明细.xlsx')
data_2017=pd.read_excel('Z:\\会员管理课\ywj严文杰\\带时间消费明细-持续更新\\17年消费明细.xlsx')
data_2018=pd.read_excel('Z:\\会员管理课\ywj严文杰\\带时间消费明细-持续更新\\18年消费明细.xlsx')
data_2019=pd.read_excel('Z:\\会员管理课\ywj严文杰\\带时间消费明细-持续更新\\19年-1001.xlsx')
data=pd.concat([data_2015,data_2016,data_2017,data_2018,data_2019],axis=0)

#先拿一年的数据测试
# data=data_2019
# 之前是时间格式,要让卡号对应日期,一个卡号可对应对多个日期,且这个日期转化后是object类,要pd.to_datetime()转化为时间格式
data['日期'] = pd.to_datetime(list(map(lambda x: x.date(), data.loc[:, '交易时间'])))

#循环运行函数
# 参数包括开始日期,结束日期,基准日期
def fun2(stime,etime,jizhuntime):
    data1=data
    data1 = data1.loc[:, ['卡号', '日期', '销售金额']].groupby(by=['卡号', '日期'], as_index=False).agg({'销售金额': np.sum})
    data1 = data1[['卡号', '日期', '销售金额']]
    # 删除金额小于0的,属于异常值
    data1 = data1.loc[data1['销售金额'] > 0, :]

    # 截取某个时间段的数据,data1就是元数据
    data1=data1.loc[(data1['日期']>=pd.to_datetime(stime))&((data1['日期']<=pd.to_datetime(etime)))]
    # 分别求相对于基准日期的间隔,消费天数,消费金额
    result=data1.groupby(by='卡号',as_index=False).agg({'日期':[lambda x:(pd.to_datetime(jizhuntime)-max(x)),len],'销售金额':np.sum})
    result.index.name = '索引'
    # 更改列名
    result.columns = ['卡号','R', 'F', 'M']
    # 提取出天数的数字
    result['R']= result['R'].dt.days
    # 分组分类,R越低得分越高
    # 分3组,好,一般,差。更加清晰,策略更好配置
    result['R_score']=pd.cut(result['R'],bins=[0,90,180,float('inf')],labels=['3','2','1'])
    result['F_score'] = pd.cut(result['F'], bins=[0,2, 5, float('inf')], labels=['1', '2', '3'])
    # 求会员客单价,以此分类M
    kd=result['M'].sum()/result['M'].count()
    result['M_score'] = pd.cut(result['M'], bins=[0, kd, 2*kd,float('inf')], labels=['1', '2', '3'])
    result['sum_score']=result['R_score'].str.cat(result['F_score']).str.cat(result['M_score'])
    # 转化为数字格式
    result.loc[:,'R_score':'sum_score']=result.loc[:,'R_score':'sum_score'].astype(int)
    # 以综合打分为基准,进行分类-策略
    data_score= pd.read_excel('C:\\Users\\02180085\\Desktop\\回店会员特征\\分类标准.xlsx',dtype={'sum_score':int})
    result1=pd.merge(result,data_score,how='left',on='sum_score')

    # 求消费频次排名1、2、3的品牌
    p=data.loc[(data['日期']>=pd.to_datetime(stime))&(data['日期']<=pd.to_datetime(etime)),['卡号','销售金额','专柜']].\
        groupby(by=['卡号','专柜'],as_index=False).agg({'销售金额':len})#卡号--专柜--专柜计数
    p.columns = ['卡号', '专柜', '笔数']
    # print(p)
    # 返回消费频次最高的品牌
    def fun_p1(d1):
        # 按笔数降序排列
        d1=d1.sort_values(by=['笔数'],ascending=False)
        return d1.iloc[0,1]
    # 返回第二的品牌,有些没有第二个品牌
    def fun_p2(d1):
        # 按笔数降序排列
        d1=d1.sort_values(by=['笔数'],ascending=False)
        if d1.shape[0]>=2:
            return d1.iloc[1, 1]
        else:
            return d1.iloc[0, 1]

    # 返回第三的品牌,有些没有第三个品牌
    def fun_p3(d1):
        # 按笔数降序排列
        d1=d1.sort_values(by=['笔数'],ascending=False)
        if d1.shape[0]>=3:
            return d1.iloc[2, 1]
        elif d1.shape[0]>=2:
            return d1.iloc[1, 1]
        else:
            return d1.iloc[0, 1]
    p1=p[['卡号', '专柜', '笔数']].groupby(by=['卡号']).apply(fun_p1)#卡号--专柜--专柜计数
    p1=pd.DataFrame(p1)
    p1.index.name='索引'
    p1['卡号']=p1.index.tolist()
    p1.columns=['消费频次第一专柜','卡号']
    print(p1)
    p2=p[['卡号', '专柜', '笔数']].groupby(by=['卡号']).apply(fun_p2)#卡号--专柜--专柜计数
    p2=pd.DataFrame(p2)
    p2.index.name='索引'
    p2['卡号']=p2.index.tolist()
    p2.columns=['消费频次第二专柜','卡号']
    print(p2)

    p3=p[['卡号', '专柜', '笔数']].groupby(by=['卡号']).apply(fun_p3)#卡号--专柜--专柜计数
    p3=pd.DataFrame(p3)
    p3.index.name='索引'
    p3['卡号']=p3.index.tolist()
    p3.columns=['消费频次第三专柜','卡号']
    print(p3)

    # 消费频次三个表与分类表result1  merge
    result1=pd.merge(result1,p1,on='卡号',how='left')
    result1 = pd.merge(result1, p2, on='卡号', how='left')
    result1 = pd.merge(result1, p3, on='卡号', how='left')

    # 匹配电话,为后期消息推送使用
    data_phone=data[['卡号','手机号码']].drop_duplicates(subset=['手机号码'])
    print(data_phone)
    result1=pd.merge(result1, data_phone, on='卡号', how='left')

    result1.to_excel('C:\\Users\\02180085\\Desktop\\回店会员特征\\ecco全馆.xlsx',index=False)
    print(result1)
    return result1

out=fun2('2015-1-1', '2019-10-1', '2019/10/2')
out.to_excel('C:\\Users\\02180085\\Desktop\\回店会员特征\\ecco全馆.xlsx',index=False)

得到以下结果:
Python每日一记171>>>python实现RFM模型

上一篇: 如何在Python中实现RFM分析

下一篇: