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也就是最近购买的时间,把时间转成时间戳即可
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
...
转透视表
# 转透视表
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 = 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 = 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’),下面开始查询
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)
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中
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))