电商平台零售数据分析

本次目标主要是利用RFM模型对用户进行分类。通过对比分析不同用户群体在时间、地区等维度下的交易量、交易金额等,总结分析结果并提出优化建议。

R(Recently):最近一次的消费时间

F(Frequency):消费频率(单位时间的消费次数)

M(Money):消费金额(单位时间的消费金额)

本次数据来源于在线零售业务的交易数据,以下是礼品数据的相关字段:

InvoiceNO:订单编号,每笔交易有六个整数,退货订单编号开头有字母“C”

StockCode:产品编号,由五个整数组成

Description:产品描述

Quantity:产品数量,正号表示成功出售,负号表示退货

InVoiceDate:订单日期和时间

UnitPrice:单价(英镑),单位产品的价格

CustomerID:客户编号,每个客户编号由五位整数组成

Country:国家的名称,每个客户所在的国家/地区的名称

一、读取数据

#忽视警告信息
import warnings
warnings.filterwarnings('ignore')
import pandas as pd 
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# import os
# os.chdir('')
# 更改文件存放目录

关于seaborn库的使用

import plotly as py # 用来与plotly服务器通信
import plotly.graph_objs as go # 用来生成图形对象
pyplot=py.offline.iplot
py.offline.init_notebook_mode()
# 初始化jupyter notebook中的绘图模式

关于plotly库的使用 

#读取数据
df=pd.read_csv('E:\Kaggle\data.csv',encoding='utf-8')
df.shape
df.info()

二、 数据清洗

df.apply(lambda x: sum(x.isnull())/len(x),axis=0)
# 每一列缺失值的占比情况

 

可见客户编号CustomerID缺失值占比较多 

df.head()

df.drop(['Description'],axis=1,inplace=True)
# 产品描述我们可以进行删除,因为其对数据分析无意义
df['CustomerID']=df['CustomerID'].fillna('U')
# 将缺失的CustomerID填充为"U"
df['amount']=df['Quantity']*df['UnitPrice']
# 订单的交易总额,数量*单价
df['date']=[x.split(' ')[0] for x in df['InvoiceDate']]
df['time']=[x.split(' ')[1] for x in df['InvoiceDate']]
df[['date','time']]
# 将InvoiceDate的日期和时间分为两列
# PLAN B:
# df['Date'] = pd.to_datetime(df['InvoiceDate']).dt.date
# df['Time'] = pd.to_datetime(df['InvoiceDate']).dt.time
# df['Date'] = pd.to_datetime(df['Date'])
# 删除InvoiceDate列,分割年、月、日

df.drop(['InvoiceDate'],axis=1,inplace=True)
df['year']=[x.split('/')[2] for x in df['date']]
df['month']=[x.split('/')[0] for x in df['date']]
df['day']=[x.split('/')[1] for x in df['date']]
df[['year','month','day']].head()
df['date']=pd.to_datetime(df['date'])
df['date']
df=df.drop_duplicates()
# 删除重复值
df.describe()
# 对单价进行异常分析
df2=df.loc[df['UnitPrice'] <=0]
df2.head()
df2.shape[0]/df.shape[0]
# 异常值里边单价的分类情况
df2['UnitPrice'].groupby(df2['UnitPrice']).count()
df['month'].groupby(df['month']).count()
df2['UnitPrice']


 三、数据分析

(1)退货率

df1=df.loc[df['Quantity'] <=0]
df1.columns
# 每个月的退货情况
tt=pd.pivot_table(df1,index=['year'],columns=['month'],values=['amount'],aggfunc={'amount':np.sum},margins=False)
# 销售的正常数据
df2=df[(df['Quantity'] >0) & (df['UnitPrice'] >0)]
# 每个月的营业额
pp=pd.pivot_table(df2,index=['year'],columns=['month'],values=['amount'],aggfunc={'amount':np.sum},margins=False)

# 2011年每月的退货率
np.abs(tt/pp)
# 2011年月平均退货率
np.abs(tt / pp).loc['2011'].mean()

 (2)用户分级

# 计算R、F、M
# 客户最近一次的消费时间
R_value=df2.groupby('CustomerID')['date'].max()
df2['date'].max()
# 用户最近消费时间和目标时间的距离
R_value=(df2['date'].max() -R_value).dt.days
# nunique()用于统计同一列中不同值的个数
F_value=df2.groupby('CustomerID')['InvoiceNo'].nunique()
# 消费总金额
M_value=df2.groupby('CustomerID')['amount'].sum()

import seaborn as sns
sns.set(style='darkgrid')
plt.hist(R_value,bins=30)
plt.show()
# 根据得到的图形可知异常值严重
plt.hist(M_value,bins=30)
plt.show()

# 绘制金额小于2000
plt.hist(M_value[M_value<2000],bins=30)
plt.show()

F_value.describe()

# 最大值是1428,中位数是2,可知异常值严重
count    4339.000000
mean        4.600138
std        22.943499
min         1.000000
25%         1.000000
50%         2.000000
75%         5.000000
max      1428.000000
Name: InvoiceNo, dtype: float64
# 消费频率小于20的
plt.hist(F_value[F_value<20],bins=30)
plt.show()

 

# 设置分段指标
R_bins=[0,30,90,180,360,720]
F_bins=[1,2,5,10,20,5000]#F代表消费频次,边界一定要高于最高值
M_bins=[0,500,2000,5000,10000,200000]
# 设置权重,R,值越小目标时间越近,所占权重越大,F值越小频率越高,M值越小金额越大
R_score=pd.cut(R_value,R_bins,labels=[5,4,3,2,1],right=False)
M_score=pd.cut(M_value,M_bins,labels=[1,2,3,4,5],right=False)
F_score=pd.cut(F_value,F_bins,labels=[1,2,3,4,5],right=False)
# axis=1,横向合并;纵向合并 axis=0
rfm=pd.concat([R_score,F_score,M_score],axis=1)
# 重命名
rfm.rename(columns={'date':'R_score','InvoiceNo':'F_score','amount':'M_score'},inplace=True)
rfm.info()
# 转换类型方便计算
for i in ['R_score','F_score','M_score']:
    rfm[i] = rfm[i].astype(float)
rfm.describe()
# 根据平均值设置分级
rfm['R']=np.where(rfm['R_score'] >3.82,'高','低')
rfm['F']=np.where(rfm['F_score'] >2.03,'高','低')
rfm['M']=np.where(rfm['M_score'] >1.89,'高','低')

# rfm.describe()
	R_score	F_score	M_score
count	4339.000000	4339.000000	4336.000000
mean	3.821618	2.028117	1.885609
std	1.174880	0.997989	0.951810
min	1.000000	1.000000	1.000000
25%	3.000000	1.000000	1.000000
50%	4.000000	2.000000	2.000000
75%	5.000000	3.000000	2.000000
max	5.000000	5.000000	5.000000
# 进行汇总
rfm['value']=rfm['R'].str[:]+rfm['F'].str[:]+rfm['M'].str[:]
# 去除空格处理
rfm['value']=rfm['value'].str.strip()
# 用户分级函数
def trans_value(x):
    if x =='高高高':
        return '重要价值客户'
    elif x =='高低高':
        return '重要发展客户'
    elif x =='低高高':
        return '重要保持客户'
    elif x =='低低高':
        return '重要挽留客户'
    elif x =='高高低':
        return '一般价值客户'
    elif x =='高低低':
        return '一般发展客户'
    elif x =='低高低':
        return '一般保持客户'
    else:
        return '一般挽留客户'
rfm['用户等级']=rfm['value'].apply(trans_value)
rfm
rfm['用户等级'].value_counts()
trace_basic=[go.Bar(x=rfm['用户等级'].value_counts().index,
            y=rfm['用户等级'].value_counts().values,
            marker=dict(color='orange'),opacity=0.50)]

layout=go.Layout(title='用户等级情况',xaxis=dict(title='用户重要度'))

figure_basic=go.Figure(data=trace_basic,layout=layout)
pyplot(figure_basic)

 

# 用户等级比例
trace=[go.Pie(labels=rfm['用户等级'].value_counts().index,
            values=rfm['用户等级'].value_counts().values,
            textfont=dict(size=12,color='white'))]
layout=go.Layout(title='用户等级比例')
figure_basic=go.Figure(data=trace,layout=layout)
pyplot(figure_basic)

总结

重要价值客户和重要发展客户占据较高比例。可以提高重要发展客户的购买频率,适时进行商品推送等。

1.生命周期:

平均生命周期为130天,生命周期的分布呈两极分化的状态。消费两次及以上的客户平均生命周期是203天,远高于总体均值103天。建议更加重视客户初次消费的体验感,可以考虑通过网站内服务评价、客服电询等方式获知新客对于购买流程中不满意之处,针对性地加以改进;并且花更多的精力引导其进行再次消费,如发放有时限的优惠券等。

2.挽留情况:

客户群体的采购并非高频行为,但留存下来的老客户忠诚度极高。而仅有首次购买行为的客户占总客户的37.5%,如能提高这部分群体的留存率,将会带来很高的收益。

3.购买周期:

大部分留存客户的购买周期集中在15-70天,建议可以每隔30天左右对客户进行些优惠活动的信息推送。

猜你喜欢

转载自blog.csdn.net/weixin_43717681/article/details/109116397