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

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

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)

得到以下结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值