共计 2495 个字符,预计需要花费 7 分钟才能阅读完成。
为什么需要 AP 聚类?
刚接触聚类分析时,大家往往从 K -means 开始学习。但实践中会发现两个头疼的问题:

- 必须预先指定聚类数量 K 值
- 对初始中心点敏感,容易陷入局部最优
AP 聚类(Affinity Propagation)完美解决了这些痛点。它通过消息传递自动确定最佳聚类数量,且不需要随机初始化。我第一次用它分析用户行为数据时,仅用三行代码就得到了比 K -means 更合理的分组结果。
算法原理大白话
AP 聚类的核心思想很形象:假设数据点是一群参会者,每个人通过『喊话』决定谁当会议主持人(聚类中心)。整个过程依赖两个关键矩阵:
- 相似度矩阵 (S):就像座位表,记录每两人之间的『亲密度』(负欧式距离)
- 偏好参数 (preference):相当于每个人的『领导力』,值越大越可能成为中心
算法通过两种消息反复传递:
- 责任度 (responsibility):点 i 告诉点 k『你有多适合当我的代表』
- 可用度 (availability):点 k 回应点 i『我有多适合当大家的代表』
经过多次『讨论』后,最靠谱的中心点会脱颖而出。这个自组织过程让我联想到蚂蚁觅食时的群体智能。
手把手代码实战
下面用 Python 实现 AP 聚类完整流程,数据集使用经典的鸢尾花:
# 环境准备
import numpy as np
from sklearn.cluster import AffinityPropagation
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
# 数据加载与预处理
iris = datasets.load_iris()
X = iris.data[:, :2] # 只取前两个特征方便可视化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # 重要!必须标准化数据
# 模型训练
af = AffinityPropagation(preference=-50, random_state=0).fit(X_scaled)
cluster_centers_indices = af.cluster_centers_indices_
labels = af.labels_
n_clusters = len(cluster_centers_indices)
print(f'自动识别的聚类数:{n_clusters}')
可视化结果时,我习惯用不同颜色标记聚类,并突出显示中心点:
# 结果可视化
plt.figure(figsize=(10, 6))
colors = ['#4EACC5', '#FF9C34', '#4E9A06', '#FF3300']
for k in range(n_clusters):
class_members = labels == k
cluster_center = X_scaled[cluster_centers_indices[k]]
plt.scatter(X_scaled[class_members, 0], X_scaled[class_members, 1],
c=colors[k], s=20, alpha=0.5)
plt.scatter(cluster_center[0], cluster_center[1],
c=colors[k], s=200, marker='*', edgecolor='k')
plt.title('AP 聚类结果(鸢尾花数据集)')
plt.xlabel('标准化后的花萼长度')
plt.ylabel('标准化后的花萼宽度')
plt.show()
参数调优实战技巧
preference 是最关键的参数,它控制聚类数量。通过实验发现:
- 值越小 → 聚类数越少(领导力门槛高)
- 值越大 → 聚类数越多(人人都能当领导)
我常用的调优方法是结合轮廓系数:
from sklearn.metrics import silhouette_score
preferences = range(-100, -10, 10)
silhouette_scores = []
for p in preferences:
af = AffinityPropagation(preference=p, random_state=0).fit(X_scaled)
if len(np.unique(af.labels_)) >= 2: # 至少需要 2 个聚类才能计算
score = silhouette_score(X_scaled, af.labels_)
silhouette_scores.append(score)
plt.plot(preferences[:len(silhouette_scores)], silhouette_scores, 'bo-')
plt.xlabel('Preference 参数值')
plt.ylabel('轮廓系数')
plt.title('参数选择与聚类质量关系')
plt.grid(True)
plt.show()
新手避坑指南
根据我踩过的坑,总结这些经验:
- 数据未标准化 :AP 聚类对尺度敏感,一定要用 StandardScaler 或 MinMaxScaler
- 相似度计算不当 :默认使用负欧式距离,对于文本数据建议改用余弦相似度
- preference 设置不合理 :可以先取相似度矩阵的中位数作为初始值
- 内存溢出问题 :数据量 >1 万时建议换用 FastAP 等改进算法
- 迭代不收敛 :适当调大 max_iter 参数(默认 200 次)
算法性能与适用场景
AP 聚类的时间复杂度是 O(N²T),其中 N 是样本数,T 是迭代次数。实测发现:
- 1000 个样本:约 3 秒
- 5000 个样本:约 2 分钟
- 10000 个样本:内存可能溢出
与 K -means 对比:
| 特性 | AP 聚类 | K-means |
|---|---|---|
| 需指定 K 值 | 不需要 | 必须指定 |
| 中心点初始化 | 自动确定 | 随机初始化 |
| 计算效率 | O(N²) | O(NKT) |
| 最佳场景 | 中小规模数据 | 大规模数据 |
思考与延伸
当处理百万级数据时,AP 聚类会遇到严重性能瓶颈。业界常用的优化思路包括:
- 使用稀疏矩阵存储相似度
- 采用层次化 AP(先粗聚类再细化)
- 基于 GPU 加速的消息传递
你认为哪种方法最适合电商用户分群场景?欢迎在评论区分享见解。
正文完
