前言
这是一个来自 Kaggle 的跨国数据集,包含英国某电商在线零售在 2010 年 12 月 1 日到 2011 年 12 月 9 日之间发生的交易数据。数据量庞大,很适合用机器学习中的 K-Means 等算法,根据客户在市场上的购买行为来做精细化分群。
本文的思路是:先做数据清洗与探索性分析摸清整体情况,再用 RFM 模型做人工分层,最后用 K-Means 聚类做无监督分群,两种方法相互印证。
数据来源
https://www.kaggle.com/yasserh/customer-segmentation-dataset
https://archive.ics.uci.edu/ml/datasets/online+retail
数据说明
该数据集共 540545 行,8 列,具体字段信息为:
| 字段 | 说明 |
|---|---|
| InvoiceNo | 发票号码,一个唯一分配给每笔交易的 6 位整数。若以字母「c」开头,表示取消 |
| StockCode | 商品编码 |
| Description | 产品(项目)名称 |
| Quantity | 数量 |
| InvoiceDate | 发票日期 |
| UnitPrice | 单价,以英镑为单位的每单位产品价格 |
| CustomerID | 客户 ID |
| Country | 国家 |
问题描述
-
数据的预处理、数据清洗,对数据集做探索性分析
-
基于客户的相似性进行细分,建立 RFM 人群画像与 K-Means 聚类模型
-
调参并比较各种分类算法的评估指标
导入第三方库
1
2
3
4
5
6
7
import pandas as pd
import numpy as np
from pyecharts.charts import *
import pyecharts.options as opts
import warnings
warnings.filterwarnings('ignore')
数据预处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## 数据读取
df = pd.read_excel('D:/**/Online Retail.xlsx')
## 缺失值处理
df.dropna(subset=['CustomerID'],inplace=True)
## 时间处理
df['InvoiceDate'] = df['InvoiceDate'].map(lambda x: str(x))
## 国家名称统一化
df.replace({'EIRE':'Ireland','USA':'United States','RSA':'South Africa','Czech Republic':'Czech','Channel Islands':'United Kingdom'},
inplace=True)
## 计算每单的价格
df['Amount'] = df['Quantity']*df['UnitPrice']
预处理后的数据预览
1
df.head(20)

数据探索性分析
1
2
3
4
5
6
7
8
9
## 订单交易状态
df['InvoiceNo'] = df['InvoiceNo'].astype(str)
df['Transaction status'] = df['InvoiceNo'].map(lambda x:'0' if x.startswith('C') else '1')
## 可视化——订单交易状态
label = ['交易成功','交易取消']
value = df['Transaction status'].value_counts().values.tolist()
## 代码较长,为节省篇幅部分已隐藏

结论
英国为订单数量最多的国家
在全球订单分布区域中,零售订单主要分布在以英国为中心辐射的欧洲地区,此外北美、南美以及澳大利亚均有国家地区涉及下单。
存在少量取消订单或退货
在所有订单中,成功交易的订单占比达到 97.81%,有 2.19% 的订单为取消订单或退货。
2011 年 11 月是订单高峰月
2011 年 8 月到 2011 年 11 月订单数量上升明显。
热门商品
最受欢迎的商品 Top 1:WHITE HANGING HEART T-LIGHT HOLDER。
基于 RFM 模型的客户分群
RFM 从三个维度刻画客户价值:R(Recency,最近一次消费距今天数)、F(Frequency,消费频率)、M(Monetary,消费总金额)。下面先把三个指标分箱打分,再按均值划分「高/低」,从而拼出客户类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## 计算每位顾客的消费总金额
df_total=pd.DataFrame(df.groupby('CustomerID')['Amount'].sum()).reset_index()
df_total.columns = ['CustomerID','Total_Amount']
df_total['Total_Amount'] = df_total['Total_Amount'].map(lambda x:round(x,2))
## 提取各订单消费年月日与时间
df['InvoiceDate_ymd'] = df['InvoiceDate'].map(lambda x:x.split(' ')[0])
df['InvoiceDate_hms'] = df['InvoiceDate'].map(lambda x:x.split(' ')[1])
## RFM 级别划分 Step1
## 若数值越小,表示级别越高
df_rfm['R_level'] = pd.cut(df_rfm['R'],bins=[0,65,130,195,260,325,390],labels=[1,2,3,4,5,6],right=False)
df_rfm['F_level'] = pd.cut(df_rfm['F'],bins=[0,10,20,50,100,175,250],labels=[6,5,4,3,2,1],right=False)
df_rfm['M_level'] = pd.cut(df_rfm['M'],bins=[0,28,280,2800,28000,145000,285000],labels=[6,5,4,3,2,1],right=False)
## RFM 级别划分 Step2
df_rfm['R_level'] = df_rfm['R_level'].map(lambda x:'高' if x < df_rfm['R_level'].astype(int).mean() else '低')
df_rfm['F_level'] = df_rfm['F_level'].map(lambda x:'高' if x < df_rfm['F_level'].astype(int).mean() else '低')
df_rfm['M_level'] = df_rfm['M_level'].map(lambda x:'高' if x < df_rfm['M_level'].astype(int).mean() else '低')
## 代码较长,为节省篇幅部分已隐藏

结论
通过 RFM 模型人工对客户类型进行划分,占比最大的是重点深耕客户(53.6%),其次是重点挽留客户(15.33%),占比最少的是重点唤回客户(0.09%)。
基于 K-Means 的聚类分析
RFM 是靠人工设定阈值来分层,接下来用 K-Means 做一次无监督聚类,看数据本身会自然分成几群。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
K = range(1, 10)
meandistortions = []
for k in K:
kmeans = KMeans(n_clusters=k)
kmeans.fit(data_scaled)
meandistortions.append(sum(np.min(cdist(data_scaled, kmeans.cluster_centers_, 'euclidean'), axis=1))/data_scaled.shape[0])
plt.plot(K, meandistortions, marker='o')
plt.xlabel('K')
plt.ylabel('Average distortion degree')
plt.title('Use the Elbow Method to select the best K value')
plt.show()
# 代码较长,为节省篇幅部分已隐藏

k 定义
当 K=4 时,平均畸变程度变化趋于平缓,此时改变 K 值对聚类效果影响不大,故确定聚类簇数为 4。
聚类结果可视化
1
2
3
4
5
6
7
8
Kmeans = KMeans(n_clusters=4,max_iter=50)
Kmeans.fit(data_scaled)
cluster_labels_k = Kmeans.labels_
df_rfm = df_rfm.reset_index()
cluster_labels = pd.DataFrame(cluster_labels_k, columns=['clusters'])
res = pd.concat((df_rfm, cluster_labels), axis=1)
## 代码较长,为节省篇幅部分已隐藏

结论
第一类客户
该类客户上一次购物距今间隔较长,购物频率为 0,且购物总金额较少,为典型的流失客户。
第二类客户
该类客户上一次购物距今间隔为 0,购物频率很高,且花费总金额很大,为典型的高价值客户。
第三类客户
该类客户与第 1 类客户有很多相似的地方,不同之处在于该类客户仍有购物次数,但不高,为典型的重要挽回客户。
第四类客户
该类客户上一次购物距今间隔较短,购物频率较低,且花费总金额为 0,可能为新客户。
总结
从探索性分析到 RFM 分层,再到 K-Means 聚类,两条路径给出的结论是一致的:这家电商的客户里,高价值 / 重点深耕客户贡献了绝大部分消费额,但数量上占比有限,大量客户处于流失或低频状态。对运营而言,这意味着资源应重点投向维系高价值客户、唤回流失客户,并针对新客户设计转化路径——这正是精细化分群的意义所在。