前面的博客中已经有使用在线零售业务数据进行数据分析,但是在这一篇,我们以不同的角度重新对这些数据进行分析。
国外的在线零售业务的交易数据,数据下载地址
现在以表格的形式解释一下里面的字段:
字段 | 说明 |
---|---|
InvoiceNo | 订单编号,含有6个整数,退货订单编号开头有字母C |
StockCode | 产品编号,由5个整数构成 |
Description | 产品描述 |
Quantity | 产品数量,有负号表示退货 |
InvoiceDate | 订单日期和时间 |
UnitPrice | 单位 英镑 单位产品的价格 |
CustomerID | 客户编号,由5位数字组成 |
Country | 国家的名称 每个客户所在的国家/地区的名称 |
首先说一下思路:
1、清洗数据,去除掉退单的数据和异常值
2、按照RFM模型公式,计算各个模块的数值
3、 通过数据的划分,将模型的三个模块按照重要性进行划分。
4、 通过自定义函数,将模型进行整理
5、 通过柱状图和饼状图对模型所划分的区域进行展示。
下面来看代码,里面有详细代码注释:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import plotly as py
import plotly.graph_objects as go
import seaborn as sns
sns.set_style('darkgrid')
data = pd.read_csv('data/data.csv')
# print(data.head(10))
#进行数据清洗
# print(data.info())
#从输出信息上来看,CustomerID 发现大量缺失,Description发现少量缺失
#去除掉重复值的值
data = data.drop_duplicates()
#通过描述信息查看是否出现异常值
print(data.describe())
#通过结果发现,UnitPrice出现负值,我们只需要正值 并且 退货数据必须剔除掉
data=data[(data['UnitPrice']>0)&(data['Quantity']>0)]
#接下来将缺失的CustomerID归为一类 代号U
data['CustomerID'].fillna('U',inplace=True)
#统计最近一次消费时间【-----
#时间格式转化成datatime 这里我们暂时不需要具体的时间,所以只留下年月日
data['Data'] = [i[0] for i in data['InvoiceDate'].str.split(' ')]
data['InvoiceDate'] = pd.to_datetime(data['Data'],errors='coerce')
#增加三列 分别记录年、月、日
data['Year'] = data['InvoiceDate'].dt.year
data['Month'] = data['InvoiceDate'].dt.month
data['Day'] = data['InvoiceDate'].dt.day
#我们以所有订单的最新日期为参考时间
Customerdata =data['InvoiceDate'].max()- data.groupby('CustomerID')['InvoiceDate'].max()
R_Customer = Customerdata.dt.days
# print(Customerdata.describe())#统计均值 标准差 最大最小值
plt.hist(R_Customer,bins=30)
plt.title("统计最近一次消费时间")
# plt.show()
#---】
#统计消费的频次 也就是每个客户购买的订单数
F_Custumer = data.groupby('CustomerID')['InvoiceNo'].nunique()
#统计消费的金额
data['Amount'] = data['UnitPrice']*data['Quantity']
M_Custumer = data.groupby('CustomerID')['Amount'].sum()
#好了 我们需要统计的都统计完了 接下来就进行分组和数据可视化
R_bins = [0,30,90,180,360,720]
F_bins = [1,2,5,10,20,5000]
M_bins = [0,500,2000,5000,10000,200000]
R_score = pd.cut(R_Customer,R_bins,labels=[5,4,3,2,1],right=False)#right=False 所划分区间是左闭右开
F_score = pd.cut(F_Custumer,F_bins,labels=[1,2,3,4,5],right=False)
M_score = pd.cut(M_Custumer,M_bins,labels=[1,2,3,4,5],right=False)
rfm = pd.concat([R_score,F_score,M_score],axis=1)
#从结果中看到,列名默认是采用原数据自带的列名 这里我们做一下修改
rfm.rename(columns={'InvoiceDate':'R_score','InvoiceNo':'F_score','Amount':'M_score'},inplace=True)
rfm = rfm.astype(float)#z转换数据类型,方便之后进行计算
print(rfm.describe())# 通过查看平均值来对用户进行分级
#R_scpre-mean():3.82
#F_score-mean():2.02
#M_score-mean():1.88
rfm['R_score'] = np.where(rfm['R_score']>3.82,'高','低')
rfm['F_score'] = np.where(rfm['F_score']>2.02,'高','低')
rfm['M_score'] = np.where(rfm['M_score']>1.88,'高','低')
#将这三个拼接到一块
rfm['All'] = rfm['R_score'].str[:]+rfm['F_score'].str[:]+rfm['M_score'].str[:]
rfm['All'] = rfm['All'].str.strip()
def CheckClass(x):
if(x=='高高高'):
return '重要价值客户'
elif x=='高低高':
return '重要发展客户'
elif x=='高高低':
return '一般价值用户'
elif x=='高低低':
return '一般发展客户'
elif x=='低高高':
return '重要保持客户'
elif x=='低高低':
return '重要发展客户'
elif x=='低低高':
return '重要挽留客户'
elif x=='低低低':
return '一般挽留客户'
rfm['用户等级'] = rfm['All'].apply(CheckClass)
#用户等级数量可视化-
Bar = go.Bar(x=rfm['用户等级'].value_counts().index,y=rfm['用户等级'].value_counts(),opacity=0.5,marker=dict(color='orange'))
layout = go.Layout(title = "不同用户等级柱状图")
fig = go.Figure(data=[Bar],layout=layout)
py.offline.plot(fig,filename='CustomerNumber.html')
#将用户等级可视化-饼状图
Pie = go.Pie(labels=rfm['用户等级'].value_counts().index,values=rfm['用户等级'].value_counts())
layout = go.Layout(title = "不同用户等级")
fig = go.Figure(data=[Pie],layout=layout)
py.offline.plot(fig,filename='CustomerClass.html')
本次实践主要是简单描述用户画像,对用户进行分层。从图表中我们可以看到,重要价值客户和重要发展客户占比最多,对于前者,由于其购买时间间隔比较长,可以采取优惠卷或者相应打折力度,增加这种用户的回购频率;对于后者客户,除了购买时间间隔长之外,还存在购买频率比较低的问题,对于这客户,同样可以策划相应的活动。此数据还可以从另外角度分析,比如 按月份进行订单量统计,并对比去年同期数据,查看是否出现大的波动等等。