RFM模型了解和数据实践以及dataframe用sql语句查询

RFM模型了解和数据实践以及dataframe用sql语句查询

  • RFM模型基础知识
  • 数据处理实践
    • 读取文件
    • 先求R的值
    • 同理求F
    • 计算M并转透视表
    • 合并并且分类
  • 利用sqlite3来查询(也就是sql语句查询)
  • 使用sqlalchemy来查询
    • 添加数据到数据库
    • 查询

RFM模型基础知识

  • R(Recency):客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,反之则表示客户交易发生的日期越近。
  • F(Frequency):客户在最近一段时间内交易的次数。F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃。
  • M(Monetary):客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,反之则表示客户价值越低。
    RFM模型了解和数据实践以及dataframe用sql语句查询_第1张图片

数据处理实践

  • 博客会上传一个csv文件里面是用户的交易信息,包含了订单id,用户id,时间,价格,商品类别等,编码是gbk。
  • 文件比较大所以输出只截取前几个
  • 本文是处理这个文件并得出rfm模型(并且都使用jupyter notebook),如果是pycharm输出时加上print即可

读取文件

import pandas as pd
import numpy as np

data = pd.read_csv('RFM_TRAD_FLOW.csv', encoding='gbk')
data

输出(只截了前五个,也可以使用head()方法截取)

	transID	cumid	time	amount	type_label	type
0	9407	10001	14JUN09:17:58:34	199.0	正常	Normal
1	9625	10001	16JUN09:15:09:13	369.0	正常	Normal
2	11837	10001	01JUL09:14:50:36	369.0	正常	Normal
3	26629	10001	14DEC09:18:05:32	359.0	正常	Normal
4	30850	10001	12APR10:13:02:20	399.0	正常	Normal
...

先求R的值

R也就是最近购买的时间,把时间转成时间戳即可

import time
# 转成时间戳
data['time'] = data['time'].map(lambda x:time.mktime(time.strptime(x, '%d%b%y:%H:%M:%S')))
# 分组求出最近时间,也就是时间戳最大的
group_obj = data.groupby(['cumid', 'type_label'])
R = group_obj[['time']].max()
R

输出(截取前几个):

		time
cumid	type_label	
10001	正常	1.284699e+09
特价	1.255316e+09
赠送	1.284197e+09
退货	1.278766e+09
10002	正常	1.276953e+09
赠送	1.278129e+09
退货	1.252047e+09
...

转透视表

  • 转透视表以用户id为行索引,商品类别为列索引
  • 会发现有很多NaN数据,这时候要进行数据清理
# 转透视表
r_trans = pd.pivot_table(R,index='cumid',columns='type_label',values='time')
# 处理NaN值,只有这两列有空值
r_trans[['特价','退货']] = r_trans[['特价','退货']].apply(lambda x:x.replace(np.nan,min(x)),axis=0)
# 添加一列为三个值最大的也就是最近的时间,这里不查找退货的
r_trans['r_max'] = r_trans[['正常', '特价','赠送']].apply(lambda x:max(x),axis=1)
r_trans

输出,这样就得到了最近的购买时间也就是R值

type_label	正常	特价	赠送	退货	r_max
cumid					
10001	1.284699e+09	1.255316e+09	1.284197e+09	1.278766e+09	1.284699e+09
10002	1.276953e+09	1.250297e+09	1.278129e+09	1.252047e+09	1.278129e+09
10003	1.282983e+09	1.262435e+09	1.280805e+09	1.275806e+09	1.282983e+09
10004	1.279534e+09	1.254833e+09	1.283057e+09	1.275571e+09	1.283057e+09
10005	1.277448e+09	1.250297e+09	1.282127e+09	1.270728e+09	1.282127e+09
10006	1.278652e+09	1.254053e+09	1.277637e+09	1.252659e+09	1.278652e+09
10007	1.285138e+09	1.250408e+09	1.279959e+09	1.272427e+09	1.285138e+09
...

同理求F

# 直接取某客户某商品有多少订单号就行了
F = group_obj[['transID']].count()
# 转透视表
f_trans = pd.pivot_table(F,index='cumid',columns='type_label',values='transID')
# NaN值转成0
f_trans.fillna(0, inplace=True)
# 退货的值是正的,计算时要为负数
f_trans['退货'] = f_trans['退货'].map(lambda x:-x)
# 计算的结果添加一列
f_trans['f_total'] = f_trans.apply(lambda x:sum(x), axis=1)
f_trans

输出结果:

type_label	正常	特价	赠送	退货	f_total
cumid					
10001	15.0	2.0	8.0	-2.0	23.0
10002	12.0	0.0	5.0	-1.0	16.0
10003	15.0	1.0	8.0	-1.0	23.0
10004	15.0	2.0	12.0	-1.0	28.0
10005	8.0	0.0	5.0	-1.0	12.0
...

计算M并转透视表

# M就是总价,这里不限时间
M = group_obj[['amount']].sum()
# 转透视表
m_trans = pd.pivot_table(M,index='cumid',columns='type_label',values='amount')
# 还是填充为0
m_trans[['特价','退货']] = f_trans[['特价','退货']].fillna(0)
# 增加一列总价
m_trans['m_total'] =m_trans.apply(lambda x:sum(x),axis=1)
m_trans

输出:


type_label	正常	特价	赠送	退货	m_total
cumid					
10001	3608.00	2.0	0.0	-2.0	3608.00
10002	1894.00	0.0	0.0	-1.0	1893.00
10003	3503.00	1.0	0.0	-1.0	3503.00
10004	2979.00	2.0	0.0	-1.0	2980.00
10005	2368.00	0.0	0.0	-1.0	2367.00
...

合并并且分类

# 合并三个表,取计算完的值即可
RFM = pd.concat([r_trans['r_max'],f_trans['f_total'],m_trans['m_total']],axis=1)
# cut分成3个等级,labels是展示的分数或者等级
RFM['r_score' ]= pd.cut(RFM.r_max,3,labels=[0,1,2])
RFM['f_score' ]= pd.cut(RFM.f_total,3,labels=[0,1,2])
RFM['m_score'] = pd.cut(RFM.m_total,3,labels=[0,1,2])
RFM

输出结果为:

r_max	f_total	m_total	r_score	f_score	m_score
cumid						
10001	1.284699e+09	23.0	3608.00	2	1	1
10002	1.278129e+09	16.0	1893.00	0	0	0
10003	1.282983e+09	23.0	3503.00	2	1	1
10004	1.283057e+09	28.0	2980.00	2	2	1
10005	1.282127e+09	12.0	2367.00	1	0	0
10006	1.278652e+09	11.0	2532.00	0	0	0
10007	1.285138e+09	24.0	4021.00	2	1	1
10008	1.285149e+09	29.0	4209.00	2	2	1
...

这时候需要再进行处理,按照文章刚开始的图划分客户等级

def rfm_label(r,f,m):
    # 对三列筛选,按图片所示
    if r==2 and f==2 and m==2:
        return '重要价值客户'
    elif r==2 and f<2 and m==2:
        return '重要发展客户'
    elif r<2 and f==2 and m==2:
        return '重要保持客户'
    elif r<2 and f<2 and m==2:
        return '重要挽留客户'
    elif r==2 and f==2 and m<2:
        return '一般价值客户'
    elif r<2 and f==2 and m<2:
        return '一般保持客户'
    elif r<2 and f<2 and m<2:
        return '一般挽留客户'
    else:
        return '一般发展客户'

# 添加一列客户标签
RFM['客户标签'] = RFM[['r_score','f_score','m_score']].apply(lambda x:rfm_label(x[0],x[1],x[2]), axis=1)
RFM

输出:

	r_max	f_total	m_total	r_score	f_score	m_score	客户标签
cumid							
10001	1.284699e+09	23.0	3608.00	2	1	1	一般发展客户
10002	1.278129e+09	16.0	1893.00	0	0	0	一般挽留客户
10003	1.282983e+09	23.0	3503.00	2	1	1	一般发展客户
10004	1.283057e+09	28.0	2980.00	2	2	1	一般价值客户
10005	1.282127e+09	12.0	2367.00	1	0	0	一般挽留客户
10006	1.278652e+09	11.0	2532.00	0	0	0	一般挽留客户
10007	1.285138e+09	24.0	4021.00	2	1	1	一般发展客户
...

处理完数据之后我们可以把这个数据写入文件RFM.to_csv(‘rfm.csv’),下面开始查询

利用sqlite3来查询(也就是sql语句查询)

  • 先在内存中创建一个数据库,名字固定不可改
  • 然后将dataframe对象注册成sql表,然后用sql语句查询即可
import pandas as pd
import sqlite3
# 先读取之前保持的文件
rfm = pd.read_csv('rfm.csv')
# 使用特定名称在内存中创建一个数据库
con = sqlite3.connect(':memory:')
print(con)  # 这是个对象
# 将dataframe对象注册成可sql查询的表
rfm.to_sql('rfm', con)  # 第一个参数是表名
# 按价值排序
data = pd.read_sql_query("SELECT * FROM rfm ORDER BY m_score DESC ", con)
# 查找重要客户
data_imp = pd.read_sql_query("SELECT * FROM rfm WHERE 客户标签='重要价值客户' ", con)
print(data_imp)

使用sqlalchemy来查询

添加数据到数据库

import pandas as pd

 - List item

from sqlalchemy import create_engine

# 将数据写入mysql的数据库,但需要先通过sqlalchemy.create_engine建立连接,且字符编码设置为utf8,否则有些latin字符不能处理
yconnect = create_engine('mysql+pymysql://root:password@localhost:3306/databasename?charset=utf8')
pd.io.sql.to_sql(thedataframe,'tablename', yconnect, schema='databasename', if_exists='append')

to_sql中

  • 第一个参数thedataframe是需要导入的pd dataframe,
  • 第二个参数tablename是将导入的数据库中的表名
  • 第三个参数yconnect是启动数据库的接口,pd 1.9以后的版本,除了sqllite,均需要通过sqlalchemy来设置
  • 第四个参数databasename是将导入的数据库名字
  • 第五个参数if_exists='append’的意思是,如果表tablename存在,则将数据添加到这个表的后面

sqlalchemy.create_engine是数据库引擎

参数 说明
mysql 是要用的数据库
pymysql 是需要用的接口程序
root 是数据库账户
password 是数据库密码
localhost 是数据库所在服务器的地址,这里是本机
3306 是mysql占用的端口
elonuse 是数据库的名字
charset=utf8 是设置数据库的编码方式,这样可以防止latin字符不识别而报错

也可以直接使用dataframe对象的方法

# 读取文件并生成dataframe对象
rfm = pd.read_csv('rfm.csv')
# 创建连接
conn = create_engine('mysql+pymysql://root:mysql@localhost:3306/lianxi?charset=utf8')
# 添加进数据库
rfm.to_sql('rfm1', conn, schema='lianxi', if_exists='append')

查询

查询方式和上面一样

print(pd.read_sql_query("SELECT * FROM rfm WHERE 客户标签='重要价值客户' ", conn))

你可能感兴趣的:(数据分析)