AI 智能营销数据分析:RFM + 聚类 + 推荐的全链路方案
一、营销数据分析的三个阶段
做营销数据分析久了,你会发现大部分公司的营销分析都停留在"第一阶段"——算算 ROI、看看转化率、出个周报。但实际上,真正能驱动业务增长的营销分析应该走完三个阶段:
这篇文章就把这三个阶段串起来,用一套"RFM + 聚类 + 推荐"的全链路方案,从数据到决策到执行,一气呵成。
为什么大多数公司的营销分析都停留在第一阶段? 原因不是技术能力不够,而是组织惯性。用户分层需要数据分析师跑 SQL,精准推荐需要算法工程师训练模型,效果闭环需要产品和运营配合设计 AB 测试。三个阶段涉及三个角色,任何一个环节掉链子,整个链路就断了。RFM + 聚类的优势在于:数据分析师或熟练的 Python 工程师一个人就能跑通全流程,不需要专门的算法团队——K-Means 够用了。跑通一次链路后,用数据结果去说服业务方配合做 AB 测试,阻力会小得多。先用轻量方案快速出成果,再用成果推动深度合作,这是在资源有限情况下的最佳实践。
二、RFM 模型:经典但不过时
RFM(Recency 最近一次消费、Frequency 消费频率、Monetary 消费金额)是用户分层的经典模型,简单好用,解释性极强。
为什么 30 年前的 RFM 模型到今天仍然管用? 因为这三个维度直接对应了消费行为的三个底层驱动力:Recency 衡量用户的"记忆热度"(刚买过的人最容易再次购买),Frequency 衡量"习惯程度"(买得越多越容易接着买),Monetary 衡量"投入程度"(花得越多越不会轻易离开)。这三件事不随行业变化,电商、游戏、SaaS、金融都适用。RFM 的另一个巨大优势是"可解释"——你对着老板说"这是一个 R=5, F=1, M=5 的用户",老板可能听不懂;但你说"这个用户最近花了大钱但只买了一次",老板立刻知道该怎么运营。**
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import warnings
warnings.filterwarnings('ignore')
# ==================== 第1步:计算RFM指标 ====================
# 模拟交易数据
np.random.seed(42)
n_users = 1000
transactions = pd.DataFrame({
'user_id': np.random.choice([f'U{i:04d}' for i in range(1, n_users + 1)], 5000),
'order_date': pd.to_datetime([
datetime(2026, 7, 1) – timedelta(days=np.random.randint(0, 365))
for _ in range(5000)
]),
'order_amount': np.random.lognormal(mean=4.0, sigma=0.8, size=5000), # 对数正态分布模拟交易金额
'order_id': [f'ORD{i:06d}' for i in range(1, 5001)]
})
# 设置分析基准日期(比如今天是2026-07-23)
REFERENCE_DATE = datetime(2026, 7, 23)
# 计算每个用户的RFM指标
rfm = transactions.groupby('user_id').agg(
# Recency: 最近一次购买距离今天的天数(越小越好)
recency=('order_date', lambda x: (REFERENCE_DATE – x.max()).days),
# Frequency: 购买次数(越多越好)
frequency=('order_id', 'count'),
# Monetary: 总消费金额(越多越好)
monetary=('order_amount', 'sum')
).reset_index()
print("=== RFM指标统计 ===")
print(rfm.describe())
# —- 给RFM打分(1-5分制) —-
# 按分位数将每个指标分为5个等级
def rfm_score(series: pd.Series, ascending: bool = True) -> pd.Series:
"""
将连续值映射到1-5的评分
参数:
series: 需要评分的序列
ascending: True表示值越小分数越高(适用于Recency),
False表示值越大分数越高(适用于Frequency和Monetary)
"""
labels = [5, 4, 3, 2, 1] if ascending else [1, 2, 3, 4, 5]
return pd.qcut(series, q=5, labels=labels, duplicates='drop').astype(int)
rfm['R_score'] = rfm_score(rfm['recency'], ascending=True) # R: 越近分数越高
rfm['F_score'] = rfm_score(rfm['frequency'], ascending=False) # F: 越多分数越高
rfm['M_score'] = rfm_score(rfm['monetary'], ascending=False) # M: 越多分数越高
# RFM总分
rfm['RFM_score'] = rfm['R_score'] + rfm['F_score'] + rfm['M_score']
print(f"\\n=== RFM评分分布 ===")
print(rfm[['R_score', 'F_score', 'M_score', 'RFM_score']].describe())
三、K-Means 聚类:从 RFM 到用户画像
RFM 打分是一种粗分类,想得到更精细的用户画像,需要对 RFM 的原始值做聚类:
为什么不能直接用 RFM 打分,还要做 K-Means? RFM 打分的本质是"等分"——把用户按 R/F/M 三个维度分别切成 5 等份,然后组合出 125 种可能(5×5×5)。问题是:等分不反映数据的真实分布。如果 80% 的用户 Frequency=1(只买过一次),那你把"买过一次"的用户硬切成 5 组毫无意义。K-Means 的聚类是基于实际数据密度的——用户群在哪聚集,边界就在哪,不是人为硬分。另外,K-Means 前必须做 StandardScaler 标准化,原因是 recency(0-365 天)、frequency(1-50 次)、monetary(10-100000 元)这三个特征的量纲完全不同,如果不标准化,monetary 几乎会完全主导聚类结果,recency 和 frequency 的信息被淹没。这一点 90% 的新手会忽略,结果得出一个只有金额维度的分群。**
# ==================== 第2步:K-Means聚类 ====================
# 选择聚类特征:使用RFM原始值
cluster_features = rfm[['recency', 'frequency', 'monetary']].copy()
# —- 特征标准化(K-Means对尺度敏感) —-
scaler = StandardScaler()
features_scaled = scaler.fit_transform(cluster_features)
# —- 确定最佳聚类数(手肘法) —-
# 计算不同K值下的SSE(误差平方和)
sse_list = []
k_range = range(1, 11)
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(features_scaled)
sse_list.append(kmeans.inertia_)
# 找到手肘点(简化:选择SSE下降变缓的位置)
# 实际项目中建议用轮廓系数(Silhouette Score)更严谨
# —- 使用K=5进行聚类 —-
optimal_k = 5
kmeans = KMeans(n_clusters=optimal_k, random_state=42, n_init=10)
rfm['cluster'] = kmeans.fit_predict(features_scaled)
# —- 分析每个聚类的特征,给分群命名 —-
cluster_profile = rfm.groupby('cluster').agg(
avg_recency=('recency', 'mean'),
avg_frequency=('frequency', 'mean'),
avg_monetary=('monetary', 'mean'),
user_count=('user_id', 'count'),
avg_rfm_score=('RFM_score', 'mean')
).round(1)
print("\\n=== 聚类特征画像 ===")
print(cluster_profile)
# —- 根据聚类特征自动打标签 —-
def label_cluster(row):
"""
根据RFM均值给聚类打标签
判断逻辑:
– 高Monetary + 高Frequency → 高价值用户
– 高Monetary + 低Frequency → 大单客户
– 低Monetary + 高Frequency → 活跃小客户
– 低Recency + 中低Frequency → 潜力用户(最近活跃但频次不高)
– 高Recency + 低Frequency → 流失风险用户
"""
r, f, m = row['avg_recency'], row['avg_frequency'], row['avg_monetary']
# 判断标准(相对于整体均值的比较)
r_median = rfm['recency'].median()
f_median = rfm['frequency'].median()
m_median = rfm['monetary'].median()
if m > m_median and f > f_median:
return "高价值用户"
elif m > m_median and f <= f_median:
return "大单低频客户"
elif m <= m_median and f > f_median:
return "高频小单客户"
elif r < r_median and f <= f_median:
return "潜力新用户"
else:
return "流失风险用户"
cluster_profile['segment_name'] = cluster_profile.apply(label_cluster, axis=1)
# 将标签映射回用户表
segment_map = cluster_profile['segment_name'].to_dict()
rfm['user_segment'] = rfm['cluster'].map(segment_map)
print("\\n=== 用户分群结果 ===")
print(rfm['user_segment'].value_counts())
print(f"\\n各分群人数占比:")
for seg, count in rfm['user_segment'].value_counts().items():
print(f" {seg}: {count}人 ({count/len(rfm):.1%})")
四、个性化推荐:基于分群的协同过滤
有了用户分群之后,推荐就不再是盲目的了:
为什么分群推荐比全局统一推荐效果好得多? 全局推荐的问题是"平均化"——对所有用户推一样的东西,结果是高价值用户觉得"太 low"、新用户觉得"太贵"、流失用户无感。分群推荐的核心逻辑是:同群用户有相似的消费能力和偏好。高价值用户群里的用户 A 买了某款高端产品,用户 B 很可能也会感兴趣——即使他们俩的历史行为完全不同。这就是"分群协同过滤"比"全局协同过滤"更精准的原因。更进一步,不同群的推送文案也该不同:高价值用户看到"为您臻选"会觉得被尊重,流失用户看到"好久不见,送你一张优惠券"才会点开。一句话总结:精准的秘密不在算法复杂度,而在"谁"收到"什么"的匹配度。
# ==================== 第3步:基于分群的推荐策略 ====================
class SegmentBasedRecommender:
"""
基于用户分群的推荐引擎
根据不同用户群的特性,采用差异化的推荐策略
"""
# 各分群的推荐策略
SEGMENT_STRATEGIES = {
"高价值用户": {
"priority": "vip_exclusive", # 优先推VIP专属/高客单价商品
"price_range": (200, 10000), # 价格区间
"discount_sensitivity": "low", # 对折扣不敏感,更关注品质
"channel": "push + sms", # 推送渠道
"message": "为您臻选的品质好物" # 文案风格
},
"大单低频客户": {
"priority": "similar_upsell", # 推相似品类的高端款(升单)
"price_range": (100, 5000),
"discount_sensitivity": "medium",
"channel": "sms + in_app",
"message": "基于您的偏好,这些好物值得一试"
},
"高频小单客户": {
"priority": "bundle_deal", # 推组合套餐/凑单优惠
"price_range": (10, 200),
"discount_sensitivity": "high", # 凑单敏感,适合推满减
"channel": "in_app + coupon",
"message": "凑单满99减20,这些好物加购立减"
},
"潜力新用户": {
"priority": "new_user_bundle", # 推新人专享/入门爆款
"price_range": (10, 300),
"discount_sensitivity": "high",
"channel": "push + coupon",
"message": "新人专属福利,首单立减30元"
},
"流失风险用户": {
"priority": "recall_coupon", # 推大额召回优惠券
"price_range": (10, 500),
"discount_sensitivity": "very_high",
"channel": "sms + push",
"message": "好久不见,送你一张50元优惠券"
},
}
def get_strategy(self, user_segment: str) -> dict:
"""根据用户分群获取推荐策略"""
return self.SEGMENT_STRATEGIES.get(
user_segment,
self.SEGMENT_STRATEGIES["潜力新用户"] # 默认策略
)
def generate_recommendations(self, user_id: str, user_segment: str,
user_history: list, top_n: int = 5) -> list:
"""
生成个性化推荐列表
参数:
user_id: 用户ID
user_segment: 用户分群标签
user_history: 用户历史购买商品ID列表
top_n: 推荐数量
"""
strategy = self.get_strategy(user_segment)
# 实际生产环境中,这里会调用协同过滤或内容推荐算法
# 简化示意:
recommendations = []
priority = strategy['priority']
price_range = strategy['price_range']
# 根据策略筛选候选商品
# (实际会用向量检索或矩阵分解)
# …
return {
'user_id': user_id,
'segment': user_segment,
'strategy': priority,
'message': strategy['message'],
'channel': strategy['channel'],
'candidates': recommendations # 推荐商品列表
}
# —- 使用示例 —-
recommender = SegmentBasedRecommender()
# 为不同分群的用户生成推荐
test_users = [
("U0001", "高价值用户"),
("U0500", "流失风险用户"),
("U0800", "潜力新用户"),
]
print("\\n=== 个性化推荐策略 ===")
for uid, seg in test_users:
result = recommender.generate_recommendations(uid, seg, user_history=[])
print(f"\\n{uid} ({seg}):")
print(f" 推荐策略: {result['strategy']}")
print(f" 推送文案: {result['message']}")
print(f" 推送渠道: {result['channel']}")
踩坑提醒
- 坑1:RFM 基准日期选错导致用户分群全歪 — 如果你用"今天"作为基准日期来计算 Recency,但你的交易数据只到 3 天前(数据延迟),那么所有用户的 Recency 都会多了 3 天。高价值用户可能因此被错分到流失风险群。基准日期应该是"数据的最新日期"而不是代码的执行日期。
- 坑2:K-Means K 值拍脑袋选 5 — 手肘法虽然简单,但很多数据集的肘点并不明显。真正的金标准是轮廓系数(Silhouette Score)和业务可解释性的折中。K=5 是一个经验值,但如果轮廓系数在 K=6 时明显更高,就应该用 K=6。
- 坑3:聚类标签生成后不验标,直接推给运营 — 自动打的标签(如"潜力新用户")跑出来后,必须人工抽样验标,确认标签和实际用户画像一致。否则运营按错误标签发了错误优惠券,效果为负还伤了用户体验。
五、总结
营销数据分析的"三段论"——用户分层、精准推荐、效果闭环——缺一不可。
从"拍脑袋做营销"到"数据驱动做营销",这条路一旦走通,ROI 的提升是肉眼可见的。

![[特殊字符]DeepSeek‑Harness(DSH)小白保姆教程-171主机测评](https://www.171host.com/wp-content/uploads/2026/08/20260816085112-6a817a009aabf-220x150.png)
