电商用户消费数据RFM分析

1. 导入数据, 查看数据信息

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#import datetime as dt
import time

import warnings
warnings.filterwarnings("ignore")

plt.rcParams['font.family'] = 'Microsoft YaHei' # 设置中文编码的正常显示
plt.rcParams['axes.unicode_minus'] = False #设置负号的正常显示
plt.style.use('ggplot')
filepath = r'D:\临时\RFM 电商消费数据分析\order2021.csv'
df = pd.read_csv(filepath)
df.head()

订单数据

df.shape

(104557, 11)

df.columns

Index([‘订单顺序编号’, ‘订单号’, ‘用户名’, ‘商品编号’, ‘订单金额’, ‘付款金额’, ‘渠道编号’, ‘平台类型’, ‘下单时间’, ‘付款时间’, ‘是否退款’], dtype=‘object’)

df.info()  # 渠道编号有缺失数据

<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 104557 entries, 0 to 104556
Data columns (total 11 columns):
Column Non-Null Count Dtype
0 订单顺序编号 104557 non-null int64
1 订单号 104557 non-null object
2 用户名 104557 non-null object
3 商品编号 104557 non-null object
4 订单金额 104557 non-null float64
5 付款金额 104557 non-null float64
6 渠道编号 104549 non-null object
7 平台类型 104557 non-null object
8 下单时间 104557 non-null object
9 付款时间 104557 non-null object
10 是否退款 104557 non-null object
dtypes: float64(2), int64(1), object(8)
memory usage: 8.8+ MB

df.describe()

数据列描述性统计

2. 数据清洗

# 分组查看日期分布
df_group = df.groupby('下单时间').agg({'订单号':'count'})
df_group

按日期分组计数

  • 可以看到, 数据包含 2020年 和 2021年 数据, 这里只取 2021年 数据
df = df[df['下单时间']>'2021-01-01 00:00:00']
df.shape

(104296, 11)

  • 重复数据处理
df.duplicated().sum() 

没有重复要数据
0

  • 付款金额有负值, 查看一下情况
df[df['订单金额']<0]
df[df['付款金额']<0].付款金额.count()

6
有 6 笔订单付款金额为负值

  • 修正为负的付款金额, 实际付款金额=订单金额+付款金额
df['付款金额'] = np.where(df['付款金额']<0, df['付款金额']+df['订单金额'], df['付款金额'])
  • 空值处理
df.isnull().sum() 

渠道编号有 8 个为空

  • 用众数填充 缺失值
df['渠道编号'][df['渠道编号'].isnull()==True] = df['渠道编号'].dropna().mode().values
  • 把’是否退款’字段转换成 0, 1
df['是否退款'] = df['是否退款'].map(lambda x:1 if x=='是' else 0)
df.head()
  • 删除付款金额大于下单金额数据
df.drop(index=df[df['付款金额']>df['订单金额']].index, inplace=True)
  • 验证删除结果
df[df['付款金额']>df['订单金额']].count()

3. 数据分析

3.1 销售走势(按月份)
  • 添加月份列
df['month'] = pd.to_datetime(df['下单时间']).dt.month
df.head()
  • 绘图数据准备

  • x 轴显示值

x = ['{}月'.format(i) for i in df['month'].unique()]
  • 按月份统计订单数
order_count=df.groupby('month')['订单号'].count()
  • 按月份统计订单金额
order_sum = df.groupby('month')['订单金额'].sum()
  • 按月份统计付款金额
pay_sum = df.groupby('month')['付款金额'].sum()
  • 按月份统计不含退款金额的实际销售金额
real_pay_sum = df[df['是否退款']==0].groupby('month')['付款金额'].sum()
  • 合并成目标表
df_target =pd.DataFrame([order_count,order_sum, pay_sum, real_pay_sum]).T
df_target
  • 绘图
plt.figure(figsize=(10,4), dpi=100)

plt.subplot(111, facecolor='#F0F0F0')

plt.xlabel('月份', fontsize=10)
plt.ylabel('单位/万', fontsize=10)

plt.xticks(fontsize=10)
plt.yticks(fontsize=10)

plt.title('2021年各月份销售额走势', fontsize=14)
plt.grid(axis='x')

plt.plot(x, df_target['订单金额']/10000, linewidth='1', marker='o', color='#008668', label='订单金额(万)')
plt.plot(x, df_target['付款金额']/10000, linewidth='1', marker='o', color='#ff5338', label='付款金额(万)')
plt.plot(x, real_pay_sum/10000, linewidth='1', marker='o', color='#fe8c00', label='实际付款金额(万)')


plt.legend(loc='best', fontsize=6)

2021年各月份销售额走势

3.2 各渠道来源用户占比
  • 按渠道统计用户数
channel = df.groupby('渠道编号', as_index=False)['用户名'].count()
  • ** 按用户数排名**
channel.sort_values(by='用户名', inplace=True)
channel

各渠道用户数

  • 绘图
plt.figure(figsize=(13,5),dpi=100)
plt.pie(
    channel['用户名'],
    labels=channel['渠道编号'],
    autopct='%1.1f%%',
    pctdistance=0.9,
    radius=1.3,
    startangle=70,
    labeldistance=1.03
)

plt.legend(loc='upper right', fontsize=8, bbox_to_anchor=(1.4, 0.9), borderaxespad=0.3)
plt.title('各渠道来源用户占比',loc='right',pad=20, fontsize=12)

各渠道来源用户比

3.3 各平台订单支付用户占比
  • 数据准备
platform = df.groupby('平台类型',as_index=False)['用户名'].count()
platform.sort_values(by='用户名', inplace=True)
platform

各平台支付用户数

  • 绘图
plt.figure(figsize=(13,5),dpi=100)
plt.pie(
    platform['用户名'],
    labels=platform['平台类型'],
    autopct='%1.1f%%',
    pctdistance=0.9,
    radius=1.3,
    startangle=70,
    labeldistance=1.03
)

plt.legend(loc='upper right', fontsize=8, bbox_to_anchor=(1.4,0.9), borderaxespad=0.3)
plt.title('各平台支付用户占比',loc='right', pad=20, fontsize=12)

和平台支付用户比

3.4 用户取消订单情况
  • 数据准备
cancel = df['是否退款'].value_counts()
cancel

0 88779
1 13493

  • 绘图
plt.figure(figsize=(10,5))
cancel.plot(kind='bar')
plt.title('用户取消订单情况(1为取消订单)',size=20)
plt.ylabel('订单数(万)',size=15)
plt.yticks(np.arange(0,10,1))
plt.grid(axis='y',alpha=0.5)
plt.show()

用户取消订单情况

3.5 客户复购率
  • 数据准备
    • 复购率:在某时间窗口内重复消费用户(消费两次及以上的用户)在总消费用户中占比
    • 根据复购率的定义,我们把时间窗口选择为月,用数据透视表的方式统计每个用户在每月的订单数
  • 全时期复购率
df_buy_all = df.groupby('用户名').订单号.count()
df_rebuy_all = df_buy_all[df_buy_all.values>=2].count()/df_buy_all.count()
df_rebuy_all

各月份复购率

df_buy_mon = df.pivot_table(index='用户名', columns='month', values='下单时间', aggfunc='count')
df_buy_mon

计算各月份总消费用户数

df_buy_mon_count = df_buy_mon.count()
df_buy_mon_count

计算各月消费两次以上用户数

df_rebuy_mon = df_buy_mon[df_buy_mon>=2].count()
df_rebuy_mon

复购率

rebuy_rate_mon = df_rebuy_mon/df_buy_mon_count
rebuy_rate_mon
  • 绘图
plt.figure(figsize=(10,4), dpi=100)

plt.subplot(111, facecolor='#F0F0F0')

plt.xlabel('月份', fontsize=10)
plt.ylabel('复购率', fontsize=10)

plt.xticks(fontsize=10)
plt.yticks(fontsize=10)

plt.title('2021年各月复购率', fontsize=14)
plt.grid(axis='x')

# x 轴显示值
x = ['{}月'.format(i) for i in range(1,13,1)]

plt.plot(x, rebuy_rate_mon,linewidth='1', marker='o')

2021年各月复购率

3.6 回购率
  • 回购率:是某一个时间窗口内消费的用户,在下一个时间窗口仍旧消费的占比。
  • 选择月做为时间窗口
  • 数据准备
  • 创建一个值全为0,索引为月份的序列
repur_count = pd.Series(0, index=rebuy_rate_mon.index)
  • 统计在某一个月下单并且在下一个月继续下单的用户数量
for i in range(1,12):
    repur_count[i+1]=df_buy_mon.iloc[:,i][(df_buy_mon.iloc[:,i]>0)&(df_buy_mon.iloc[:,i-1]>0)].count()

repur_rate = repur_count/df_buy_mon_count
repur_rate

各月回购率

  • 绘图
plt.figure(figsize=(10, 4), dpi=100)

plt.subplot(111, facecolor='#F0F0F0')

plt.xlabel('月份', fontsize=10)
plt.ylabel('回购率', fontsize=10)

plt.xticks(fontsize=10)
plt.yticks(fontsize=10)

plt.title('2021年各月份回购率', fontsize=14)
plt.grid(axis='x')

# x轴显示值
x = ['{}月'.format(i) for i in range(1,13,1)]

plt.plot(x, repur_rate, linewidth='1', marker='o')

2021年各月份回购率

3.7 RFM 模型
  • 复制表
df_1 = df.copy()
  • 删除被取消了的订单
df_1.drop(index=df[df['是否退款']==1].index, inplace=True)
  • 将用户名设为索引
df_1.set_index('用户名', inplace=True)
  • 为每笔订单后记为 1, 作为消费频率标记
df_1['F'] = 1
  • 建立数据透视表, 求和得到每个用户的购买频率 ‘F’
df_rfm = df_1.pivot_table(
    index=['用户名'],
    values=['订单金额','下单时间', 'F'],
    aggfunc={'订单金额':'sum', '下单时间':'max', 'F':'sum'}        
    )
    ```

* **把消费总金额作为'M'**
```py
df_rfm.rename(columns={'订单金额':'M'}, inplace=True)
  • 近度’R’
df_rfm['R'] = (pd.to_datetime(df_rfm['下单时间'].max()) - pd.to_datetime(df_rfm['下单时间'])).dt.days
  • 调整一下列的顺序, 上步删除’下单时间’可省略
df_rfm = df_rfm[['R', 'F', 'M']]
rfm = pd.DataFrame(df_rfm, dtype=int)
  • 小于平均值赋值 0, 大于平均值赋值 1
for i in range(0, len(rfm.columns)):
    rfm.iloc[:,i][rfm.iloc[:,i]<rfm.iloc[:,i].mean()]=0
    rfm.iloc[:,i][rfm.iloc[:,i]>rfm.iloc[:,i].mean()]=1
  • 连接 R-F-M
rfm['RFM']='0'
for i in range(0,len(rfm.index)):
    rfm['RFM'][i]=str(rfm.iloc[i,0])+str(rfm.iloc[i,1])+str(rfm.iloc[i,2])
  • 建立 RFM 值和客户分类的对应关系
labels = pd.DataFrame({'RFM':['111','101','011','001','110','100','010','000'],'用户标签':['重要价值客户','重要发展客户','重要保持客户','重要挽留客户','一般价值客户','一般发展客户','一般保持客户','一般挽留客户']})
  • merge 查询和客户的分类
rfm =rfm.merge(labels,on='RFM',how='left')
target = rfm.groupby('用户标签', as_index=False).RFM.count()
  • 按客户分类分组, 记数
target.rename(columns={'RFM':'客户数量'}, inplace=True)
target

![各类型用户数量](https://upload-images.jianshu.io/upload_images/4753063-8d87d5a125ab718c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


* 绘图
```py
plt.figure(figsize=(10,6), dpi=100)

plt.subplot(111, facecolor='#F0F0F0')

plt.xlabel('客户类型', fontsize=10)
plt.ylabel('人数', fontsize=10)

plt.xticks(rotation=0, fontsize=10)
plt.yticks(fontsize=10)

plt.title('不同类型用户人数', fontsize=14)
plt.grid(axis='x')

# x 轴显示值
#x = ['{}月'.format(i)for i in range(1,13,1)]
rects = plt.bar(target['用户标签'],target['客户数量'],width=0.6,color='#fe8c00')

# 数据标签
count=0

Sum = target['客户数量'].sum()

for rect in rects:
    height = rect.get_height()
    rect_x = rect.get_x()

    plt.text(rect.get_x() + rect.get_width()/2, height+500, str(height), ha='center', fontsize=8)
    #plt.text(rect.get_x() + rect.get_width()/2, height+100, str('{:2f}'.format(target['客户数量'].values[count]/Sum*100))+'%', ha='center', fontsize=8)

不同类型用户数量

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值