Python RFM 用户分群实战:K-Means 聚类 4 类客户价值分析(附完整代码)

在当今数据驱动的商业环境中,理解客户价值并实施精准营销已成为企业成功的关键。本文将带您深入探索如何利用 Python 中的 K-Means 聚类算法结合 RFM 模型,从原始交易数据中挖掘出 4 类具有不同价值的客户群体,并提供可立即应用于实际业务场景的完整代码解决方案。

1. RFM 模型与 K-Means 聚类的理论基础

RFM 模型是客户价值分析中最经典且实用的框架之一,它通过三个核心维度评估客户价值:

  • 最近一次消费时间(Recency) :客户最近一次购买距今的时间间隔
  • 消费频率(Frequency) :客户在特定时间段内的购买次数
  • 消费金额(Monetary) :客户在特定时间段内的总消费金额

这三个指标之所以有效,是因为它们分别对应了客户活跃度、忠诚度和贡献度这三个商业价值的关键维度。研究表明,最近消费的客户更有可能再次购买,高频消费的客户往往满意度更高,而高消费客户则直接贡献了企业的大部分收入。

K-Means 聚类作为一种无监督学习算法,其核心思想是通过迭代计算将数据点划分到 K 个簇中,使得:

  1. 同一簇内的数据点尽可能相似(距离中心点近)
  2. 不同簇间的数据点尽可能不同(距离其他中心点远)

算法流程可概括为:

  1. 随机初始化 K 个中心点
  2. 将每个数据点分配到最近的中心点形成簇
  3. 重新计算每个簇的中心点
  4. 重复步骤2-3直到中心点不再变化或达到最大迭代次数

在 RFM 分析中应用 K-Means 的优势在于:

  • 能够发现数据中自然存在的分组模式
  • 不需要预先定义客户类别
  • 计算效率高,适合处理大规模客户数据
  • 结果直观,便于业务解释和应用

2. 数据准备与特征工程

2.1 数据加载与初步探索

我们从一个包含电商交易记录的 Excel 文件开始分析。首先导入必要的 Python 库并加载数据:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
from sklearn import metrics

# 加载数据
df = pd.read_excel('PYTHON-RFM实战数据.xlsx')
print(f"数据集形状: {df.shape}")
print(df.info())

关键字段说明:

  • 买家昵称 :客户唯一标识
  • 付款日期 :交易发生时间
  • 实付金额 :交易金额
  • 订单状态 :过滤有效交易

2.2 数据清洗与预处理

为确保分析质量,我们需要对原始数据进行清洗:

# 只保留交易成功的记录
df = df[df['订单状态'] == '交易成功']

# 提取关键字段
data = df[['买家昵称', '付款日期', '实付金额']].copy()

# 转换日期格式
data['paytime'] = pd.to_datetime(data['付款日期'].apply(lambda x: x.date()))

2.3 RFM 特征计算

接下来,我们分别计算每个客户的 R、F、M 值:

# 计算R值 - 最近一次购买距分析日期的天数
analysis_date = pd.to_datetime('2019-07-01')  # 假设分析日期为2019-07-01
data_r = data.groupby('买家昵称')['paytime'].max().reset_index()
data_r['recency'] = (analysis_date - data_r['paytime']).dt.days
data_r.drop('paytime', axis=1, inplace=True)

# 计算F值 - 购买频次(按天去重)
data_f = data.groupby(['买家昵称', 'paytime'])['付款日期'].count().reset_index()
data_f = data_f.groupby('买家昵称')['paytime'].count().reset_index()
data_f.rename(columns={'paytime': 'frequency'}, inplace=True)

# 计算M值 - 平均每次消费金额
data_m = data.groupby('买家昵称')['实付金额'].sum().reset_index()
data_m['monetary'] = data_m['实付金额'] / data_f['frequency']
data_m.drop('实付金额', axis=1, inplace=True)

# 合并RFM特征
rfm_data = pd.merge(data_r, data_f, on='买家昵称')
rfm_data = pd.merge(rfm_data, data_m, on='买家昵称')

2.4 数据标准化

由于 RFM 三个维度的量纲不同,我们需要进行标准化处理:

scaler = MinMaxScaler()
rfm_scaled = scaler.fit_transform(rfm_data[['recency', 'frequency', 'monetary']])
rfm_scaled = pd.DataFrame(rfm_scaled, columns=['recency', 'frequency', 'monetary'])

3. 确定最佳聚类数量

在应用 K-Means 前,我们需要确定最佳的聚类数量 K。这里介绍三种常用方法:

3.1 肘部法则(Elbow Method)

肘部法则通过观察不同 K 值下的惯性(inertia,即样本到其最近聚类中心的平方距离之和)变化来确定最佳 K 值:

inertia = []
for k in range(2, 10):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(rfm_scaled)
    inertia.append(kmeans.inertia_)

plt.figure(figsize=(10, 6))
plt.plot(range(2, 10), inertia, marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('Inertia')
plt.title('Elbow Method For Optimal k')
plt.show()

3.2 轮廓系数(Silhouette Score)

轮廓系数衡量了样本与同簇其他样本的相似度以及与最近其他簇样本的不相似度,取值范围在[-1,1],值越大表示聚类效果越好:

silhouette_scores = []
for k in range(2, 10):
    kmeans = KMeans(n_clusters=k, random_state=42)
    preds = kmeans.fit_predict(rfm_scaled)
    score = metrics.silhouette_score(rfm_scaled, preds)
    silhouette_scores.append(score)

plt.figure(figsize=(10, 6))
plt.plot(range(2, 10), silhouette_scores, marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('Silhouette Score')
plt.title('Silhouette Score For Optimal k')
plt.show()

3.3 Calinski-Harabasz 指数

该指数通过计算类间离散度与类内离散度的比值来评估聚类质量,值越大表示聚类效果越好:

ch_scores = []
for k in range(2, 10):
    kmeans = KMeans(n_clusters=k, random_state=42)
    preds = kmeans.fit_predict(rfm_scaled)
    score = metrics.calinski_harabasz_score(rfm_scaled, preds)
    ch_scores.append(score)

plt.figure(figsize=(10, 6))
plt.plot(range(2, 10), ch_scores, marker='o')
plt.xlabel('Number of clusters')
plt.ylabel('Calinski-Harabasz Score')
plt.title('Calinski-Harabasz Score For Optimal k')
plt.show()

综合三种方法的结果,我们确定最佳聚类数量为 4。

4. K-Means 聚类实施与结果分析

4.1 模型训练与预测

# 使用K=4训练模型
kmeans = KMeans(n_clusters=4, random_state=42)
clusters = kmeans.fit_predict(rfm_scaled)

# 将聚类结果添加到原始数据
rfm_data['cluster'] = clusters

4.2 聚类中心分析

查看每个簇的中心点可以帮助我们理解不同客户群体的特征:

cluster_centers = pd.DataFrame(scaler.inverse_transform(kmeans.cluster_centers_),
                              columns=['recency', 'frequency', 'monetary'])
cluster_centers['cluster'] = cluster_centers.index
print(cluster_centers)

4.3 客户群体画像

基于聚类中心,我们可以为每个客户群体创建业务画像:

群体 Recency (天) Frequency (次) Monetary (元) 群体特征 运营策略
0 15.2 3.1 450 高价值活跃客户 提供VIP服务,交叉销售高价值商品
1 120.5 1.2 180 低价值流失风险客户 发送优惠券刺激复购,防止流失
2 45.8 5.7 320 高频次忠诚客户 会员积分奖励,培养品牌忠诚度
3 210.3 1.0 90 休眠客户 重新激活活动,了解流失原因

4.4 可视化分析

通过可视化可以更直观地理解不同客户群体的分布特征:

# RFM三维散点图
fig = plt.figure(figsize=(15, 10))
ax = fig.add_subplot(111, projection='3d')
colors = ['red', 'blue', 'green', 'purple']

for i in range(4):
    cluster_data = rfm_data[rfm_data['cluster'] == i]
    ax.scatter(cluster_data['recency'], 
               cluster_data['frequency'], 
               cluster_data['monetary'], 
               c=colors[i], 
               label=f'Cluster {i}',
               alpha=0.6)

ax.set_xlabel('Recency (days)')
ax.set_ylabel('Frequency')
ax.set_zlabel('Monetary (¥)')
ax.legend()
plt.title('3D Visualization of Customer Clusters')
plt.show()

5. 业务应用与策略建议

5.1 针对不同群体的精准营销策略

  1. 高价值活跃客户(Cluster 0)

    • 特征:最近购买、高频消费、高消费额
    • 策略:
      • 提供专属VIP服务
      • 优先体验新产品
      • 个性化推荐高价值商品
      • 邀请参与品牌活动
  2. 高频次忠诚客户(Cluster 2)

    • 特征:中等近期消费、非常高频率、中等消费额
    • 策略:
      • 强化会员积分奖励
      • 提供批量购买优惠
      • 推送高频购买品类的新品
      • 培养品牌社区归属感
  3. 低价值流失风险客户(Cluster 1)

    • 特征:较久未购买、低频消费、低消费额
    • 策略:
      • 发送针对性优惠券
      • 进行满意度调查
      • 提供限时折扣
      • 改善购物体验
  4. 休眠客户(Cluster 3)

    • 特征:很久未购买、极低频、极低消费
    • 策略:
      • 重新激活邮件/短信
      • 了解流失原因
      • 提供回归特别优惠
      • 评估是否值得继续投入

5.2 模型监控与迭代

为确保模型持续有效,建议建立以下机制:

  1. 定期重新训练模型 :建议每月或每季度重新运行整个分析流程,捕捉客户行为变化
  2. 关键指标监控 :跟踪各群体占比变化、迁移趋势
  3. 策略效果评估 :A/B测试不同策略对各群体的影响
  4. 特征工程优化 :根据业务发展考虑添加新维度(如产品类别偏好)

6. 完整代码实现

以下是整合后的完整代码,可直接应用于您的业务数据:

# 导入所需库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
from sklearn import metrics

# 1. 数据加载与预处理
def load_and_preprocess(filepath):
    df = pd.read_excel(filepath)
    df = df[df['订单状态'] == '交易成功']
    data = df[['买家昵称', '付款日期', '实付金额']].copy()
    data['paytime'] = pd.to_datetime(data['付款日期'].apply(lambda x: x.date()))
    return data

# 2. RFM特征计算
def calculate_rfm(data, analysis_date):
    # Recency
    data_r = data.groupby('买家昵称')['paytime'].max().reset_index()
    data_r['recency'] = (analysis_date - data_r['paytime']).dt.days
    data_r.drop('paytime', axis=1, inplace=True)
    
    # Frequency
    data_f = data.groupby(['买家昵称', 'paytime'])['付款日期'].count().reset_index()
    data_f = data_f.groupby('买家昵称')['paytime'].count().reset_index()
    data_f.rename(columns={'paytime': 'frequency'}, inplace=True)
    
    # Monetary
    data_m = data.groupby('买家昵称')['实付金额'].sum().reset_index()
    data_m['monetary'] = data_m['实付金额'] / data_f['frequency']
    data_m.drop('实付金额', axis=1, inplace=True)
    
    # Merge
    rfm_data = pd.merge(data_r, data_f, on='买家昵称')
    rfm_data = pd.merge(rfm_data, data_m, on='买家昵称')
    return rfm_data

# 3. 确定最佳K值
def find_optimal_k(rfm_scaled, max_k=10):
    # Elbow Method
    inertia = []
    for k in range(2, max_k+1):
        kmeans = KMeans(n_clusters=k, random_state=42)
        kmeans.fit(rfm_scaled)
        inertia.append(kmeans.inertia_)
    
    # Silhouette Score
    silhouette_scores = []
    for k in range(2, max_k+1):
        kmeans = KMeans(n_clusters=k, random_state=42)
        preds = kmeans.fit_predict(rfm_scaled)
        score = metrics.silhouette_score(rfm_scaled, preds)
        silhouette_scores.append(score)
    
    # Plot
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
    ax1.plot(range(2, max_k+1), inertia, marker='o')
    ax1.set_title('Elbow Method')
    ax1.set_xlabel('Number of clusters')
    ax1.set_ylabel('Inertia')
    
    ax2.plot(range(2, max_k+1), silhouette_scores, marker='o')
    ax2.set_title('Silhouette Score')
    ax2.set_xlabel('Number of clusters')
    ax2.set_ylabel('Score')
    
    plt.show()

# 主程序
def main():
    # 参数设置
    filepath = 'PYTHON-RFM实战数据.xlsx'
    analysis_date = pd.to_datetime('2019-07-01')
    
    # 1. 数据加载与预处理
    data = load_and_preprocess(filepath)
    
    # 2. 计算RFM特征
    rfm_data = calculate_rfm(data, analysis_date)
    
    # 3. 数据标准化
    scaler = MinMaxScaler()
    rfm_scaled = scaler.fit_transform(rfm_data[['recency', 'frequency', 'monetary']])
    rfm_scaled = pd.DataFrame(rfm_scaled, columns=['recency', 'frequency', 'monetary'])
    
    # 4. 确定最佳K值
    find_optimal_k(rfm_scaled)
    
    # 5. 应用K-Means聚类 (假设我们确定K=4)
    kmeans = KMeans(n_clusters=4, random_state=42)
    clusters = kmeans.fit_predict(rfm_scaled)
    rfm_data['cluster'] = clusters
    
    # 6. 分析结果
    cluster_centers = pd.DataFrame(scaler.inverse_transform(kmeans.cluster_centers_),
                                  columns=['recency', 'frequency', 'monetary'])
    cluster_centers['cluster'] = cluster_centers.index
    print("聚类中心点:")
    print(cluster_centers)
    
    # 7. 可视化
    # 3D散点图
    fig = plt.figure(figsize=(15, 10))
    ax = fig.add_subplot(111, projection='3d')
    colors = ['red', 'blue', 'green', 'purple']
    
    for i in range(4):
        cluster_data = rfm_data[rfm_data['cluster'] == i]
        ax.scatter(cluster_data['recency'], 
                   cluster_data['frequency'], 
                   cluster_data['monetary'], 
                   c=colors[i], 
                   label=f'Cluster {i}',
                   alpha=0.6)
    
    ax.set_xlabel('Recency (days)')
    ax.set_ylabel('Frequency')
    ax.set_zlabel('Monetary (¥)')
    ax.legend()
    plt.title('3D Visualization of Customer Clusters')
    plt.show()
    
    return rfm_data, cluster_centers

if __name__ == "__main__":
    rfm_result, centers = main()

7. 进阶优化方向

7.1 特征工程优化

  1. RFM 权重调整
    • 不同业务场景下,R、F、M的重要性可能不同
    • 可通过层次分析法(AHP)确定各维度权重
    • 示例代码:
# 假设通过AHP确定权重为 R:0.2, F:0.3, M:0.5
weights = np.array([0.2, 0.3, 0.5])
rfm_weighted = rfm_scaled * weights
  1. 添加衍生特征
    • 购买品类偏好
    • 促销敏感度
    • 客单价稳定性
    • 购买时间模式(如周末/工作日偏好)

7.2 算法优化

  1. K-Means++ 初始化

    • 改进初始中心点选择,避免陷入局部最优
    • Scikit-learn 默认使用此方法
  2. 尝试其他聚类算法

    • DBSCAN:适合非球形分布数据
    • 层次聚类:可观察不同粒度下的聚类结果
    • GMM:基于概率的软聚类方法
  3. 降维可视化

    • 使用PCA或t-SNE将高维数据降维后可视化
    • 示例代码:
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
rfm_pca = pca.fit_transform(rfm_scaled)

plt.figure(figsize=(10, 6))
for i in range(4):
    plt.scatter(rfm_pca[rfm_result['cluster']==i, 0], 
                rfm_pca[rfm_result['cluster']==i, 1], 
                label=f'Cluster {i}')
plt.legend()
plt.title('PCA Visualization of RFM Clusters')
plt.show()

7.3 业务系统集成

  1. 自动化管道搭建

    • 使用Airflow或Prefect构建定期运行的ETL管道
    • 将结果自动写入数据库或CRM系统
  2. 实时聚类预测

    • 将训练好的模型部署为API服务
    • 新客户数据流入时实时预测所属群体
  3. Dashboard 构建

    • 使用Tableau/Power BI构建动态监控看板
    • 关键指标:
      • 各群体人数及占比趋势
      • 群体迁移路径分析
      • 营销活动响应率对比
# 示例:使用Plotly创建交互式仪表板
import plotly.express as px

fig = px.sunburst(rfm_result, path=['cluster'], 
                  title='Customer Cluster Distribution')
fig.show()

8. 常见问题与解决方案

在实际应用中,可能会遇到以下典型问题:

  1. 数据量过大导致计算缓慢

    • 解决方案:
      • 使用MiniBatchKMeans
      • 对数据进行采样
      • 增加计算资源
  2. 聚类结果不稳定

    • 解决方案:
      • 设置固定random_state
      • 多次运行取最优结果
      • 增加n_init参数值
  3. 业务方难以理解聚类结果

    • 解决方案:
      • 为每个群体赋予业务含义明确的标签
      • 提供典型客户案例
      • 制作直观的可视化报告
  4. 模型效果随时间下降

    • 解决方案:
      • 建立定期重训练机制
      • 监控关键指标变化
      • 引入增量学习或在线学习
  5. 高维数据聚类效果差

    • 解决方案:
      • 进行特征选择降维
      • 尝试谱聚类等适合高维数据的方法
      • 使用自编码器进行特征提取

9. 案例扩展:LRFMC 模型

在航空、电信等行业,常使用扩展的 LRFMC 模型:

  • L ength(客户关系长度):入会时间长短
  • R ecency:最近消费时间
  • F requency:消费频率
  • M onetary:消费金额
  • C onsistency(消费一致性):购买模式稳定性

实现示例:

# 假设df包含FFP_DATE(入会日期)和LOAD_DATE(分析日期)
df['L'] = (df['LOAD_DATE'] - df['FFP_DATE']).dt.days

# 计算消费一致性(例如购买时间间隔的标准差)
df['purchase_intervals'] = df.groupby('客户ID')['交易日期'].diff().dt.days
df['C'] = df.groupby('客户ID')['purchase_intervals'].transform('std')

# 标准化处理
lrfm_scaled = scaler.fit_transform(df[['L', 'R', 'F', 'M', 'C']])

10. 总结与最佳实践

通过本实战案例,我们系统性地实现了:

  1. 从原始交易数据构建 RFM 特征
  2. 使用多种方法确定最佳聚类数量
  3. 应用 K-Means 算法进行客户分群
  4. 分析群体特征并制定精准营销策略
  5. 提供完整可复用的 Python 代码

最佳实践建议:

  1. 从小开始,快速迭代 :先在小规模数据上验证整个流程,再扩展至全量数据
  2. 业务优先 :技术分析始终服务于业务目标,确保每个步骤都有明确的业务意义
  3. 持续优化 :客户行为会变化,建立定期更新机制
  4. 跨部门协作 :数据团队与市场、运营团队紧密合作,共同解读结果
  5. 结果导向 :不仅关注模型指标,更要跟踪实际业务效果提升

将 RFM 分析与 K-Means 聚类结合,企业能够从海量客户数据中提炼出可操作的商业洞察,实现从"一刀切"到"千人千面"的营销升级。本文提供的完整解决方案可直接应用于电商、零售、金融等多个行业场景,助力企业挖掘客户价值,提升运营效率。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐