4、特征工程(上):RFM模型详解(最近一次消费、频率、金额)、从原始数据中提取RFM特征。

好,咱们进入特征工程环节。

说实话,在客户分群这个领域,特征工程比算法本身重要得多。你想想看,你喂给模型的是垃圾,它吐出来的肯定也是垃圾。我见过太多团队,一上来就调参、换模型,结果效果不好,回头一看,连最基本的RFM都没算清楚。

今天咱们就先把RFM模型吃透。这是客户分群的基石,也是我个人最常用的特征组合。

4.1 什么是RFM模型?

RFM,三个字母,三个维度:

  • R(Recency):最近一次消费时间。说白了,就是客户多久没来了。
  • F(Frequency):消费频率。客户在一段时间内买了多少次。
  • M(Monetary):消费金额。客户总共花了多少钱。

为什么这三个维度这么重要?

我举个例子。你开了一家店,有个客户上个月刚来过,另一个客户一年没来了。你会把资源投给谁?肯定是那个刚来过的,对吧?这就是R的作用。

再比如,一个客户一个月来10次,另一个一个月来1次。谁更忠诚?显然是频率高的那个。这就是F。

至于M,更不用说了。大客户和小客户,服务策略能一样吗?

核心思想:RFM模型认为,客户的未来行为,很大程度上可以由这3个历史行为指标预测。说白了,过去的行为是未来行为最好的预测器。

4.2 从原始数据中提取RFM特征

好,理论说完了,咱们来点实际的。怎么从原始数据里把RFM算出来?

我假设你的原始数据长这样:一张交易记录表,每行是一笔订单。字段至少包含:customer_id(客户ID)、transaction_date(交易日期)、amount(交易金额)。

嗯,这里要注意:原始数据往往很脏。我曾经遇到过日期格式不统一、金额有负数、甚至客户ID重复的情况。所以第一步,永远是数据清洗。

4.2.1 数据清洗与准备

咱们先做几件事:

  1. 把日期列转成标准格式(比如 datetime 类型)。
  2. 去掉金额为负的记录(可能是退款,但咱们先不考虑)。
  3. 去掉缺失值。
import pandas as pd
import numpy as np
from datetime import datetime

# 加载原始数据
df = pd.read_csv('transactions.csv')

# 数据清洗
df['transaction_date'] = pd.to_datetime(df['transaction_date'])
df = df[df['amount'] > 0]  # 只保留正金额
df = df.dropna(subset=['customer_id', 'transaction_date', 'amount'])

print(f"清洗后数据量: {len(df)}")

我的习惯:在清洗这一步,我会先看一眼数据的基本统计信息,比如 df.describe()。如果金额的最大值比平均值大几百倍,那很可能有异常值,需要进一步处理。

4.2.2 计算R值(最近一次消费时间)

R值怎么算?很简单:用分析截止日期,减去每个客户最近一次消费的日期。差值就是R值。

注意:R值越小,说明客户最近刚来过,活跃度越高。

# 设定分析截止日期(比如今天)
analysis_date = datetime.now()

# 计算每个客户最近一次消费日期
recency_df = df.groupby('customer_id')['transaction_date'].max().reset_index()
recency_df.columns = ['customer_id', 'last_purchase_date']

# 计算R值(天数)
recency_df['R'] = (analysis_date - recency_df['last_purchase_date']).dt.days

print(recency_df.head())

这里有个坑:如果你的数据不是最新的,分析截止日期一定要选对。我曾经犯过这个错,用当前日期去算历史数据,结果R值全偏大,模型完全失效。

4.2.3 计算F值(消费频率)

F值就是每个客户在分析周期内消费了多少次。注意,这里的时间窗口很重要。你是看过去3个月?还是过去1年?

我个人习惯:如果是做月度分析,就看过去3个月;如果是做季度分析,就看过去6个月。具体看业务场景。

# 设定分析时间窗口(比如过去90天)
time_window = 90
cutoff_date = analysis_date - pd.Timedelta(days=time_window)

# 筛选时间窗口内的数据
df_window = df[df['transaction_date'] >= cutoff_date]

# 计算每个客户的消费次数
frequency_df = df_window.groupby('customer_id')['transaction_date'].count().reset_index()
frequency_df.columns = ['customer_id', 'F']

print(frequency_df.head())

避坑指南:我曾经遇到过一个客户,他在时间窗口内只消费了1次,但金额巨大。如果只看F值,他会被归为低频客户。但实际上,他是高价值客户。所以,F和M一定要结合起来看。

4.2.4 计算M值(消费金额)

M值就是每个客户在分析周期内的总消费金额。同样,时间窗口要和F值保持一致。

# 计算每个客户的总消费金额
monetary_df = df_window.groupby('customer_id')['amount'].sum().reset_index()
monetary_df.columns = ['customer_id', 'M']

print(monetary_df.head())

4.2.5 合并RFM特征

最后,把三个表合并到一起,就得到了完整的RFM特征矩阵。

# 合并RFM
rfm_df = recency_df.merge(frequency_df, on='customer_id', how='left')
rfm_df = rfm_df.merge(monetary_df, on='customer_id', how='left')

# 填充缺失值(有些客户可能在时间窗口内没有消费)
rfm_df['F'] = rfm_df['F'].fillna(0)
rfm_df['M'] = rfm_df['M'].fillna(0)

print(rfm_df.head())

你看,代码其实不多。但真正难的是理解每个维度背后的业务含义。

4.3 RFM特征的应用场景

RFM算出来之后,能干嘛?

  • 客户分层:把客户分成高价值、低价值、流失风险等群体。
  • 精准营销:对R值小的客户发新品推荐,对R值大的客户发召回优惠券。
  • 流失预警:R值突然变大,说明客户可能快流失了。

我记得有一次,帮一个电商平台做客户分群。他们之前一直用消费金额来分客户,结果发现很多高消费客户其实已经半年没来了。后来我们用RFM重新分群,把R值高的客户单独拉出来做召回活动,效果立竿见影,复购率提升了15%。

总结一下:RFM模型虽然简单,但非常实用。它把客户行为浓缩成了3个核心指标,是后续所有聚类分析的基础。下一节,咱们会讲怎么对RFM特征做标准化和降维,为聚类算法做准备。

好,今天就到这儿。记住,特征工程是数据挖掘的灵魂。RFM算好了,你的客户分群就成功了一半。