保姆级教程:用Python的scikit-learn-extra搞定K-Medoids聚类,比K-Means更抗噪的实战代码分享
实战进阶:用scikit-learn-extra实现抗噪更强的K-Medoids聚类
在数据分析的实际场景中,我们常常遇到数据质量不理想的情况——异常值、噪声点像不请自来的客人,打乱我们的分析节奏。传统的K-Means算法虽然高效,但对这些"数据捣蛋鬼"显得力不从心。今天我们就来解锁一个更强大的替代方案:K-Medoids聚类算法。
1. 为什么需要K-Medoids?
K-Means算法通过计算数据点到簇中心的均值距离来划分簇,这种机制让它对异常值极其敏感。想象一下,如果数据集中有几个极端值,它们会像磁铁一样把簇中心"拽"向自己,导致整个聚类结果失真。
相比之下,K-Medoids选择实际存在的数据点作为簇中心(medoids),而非计算均值。这种特性让它具有三大优势:
- 抗噪性强 :medoids必须是真实数据点,不会被极端值带偏
- 适用性广 :可以处理各种距离度量,不限于欧氏空间
- 解释性好 :每个簇中心都是真实存在的样本,便于业务理解
典型应用场景 :
- 客户细分中的异常消费行为识别
- 医疗数据中的离群病例分析
- 图像处理中的噪声像素过滤
2. 环境准备与安装
在开始之前,我们需要准备好Python环境。推荐使用Python 3.8+版本,并创建独立的虚拟环境:
python -m venv kmedoids_env
source kmedoids_env/bin/activate # Linux/Mac
# 或 kmedoids_env\Scripts\activate # Windows
安装必要的依赖包:
pip install scikit-learn-extra scikit-learn matplotlib pandas numpy
验证安装是否成功:
import sklearn_extra
print(sklearn_extra.__version__) # 应显示版本号如0.3.0
提示:如果使用Jupyter Notebook,可以在单元格中运行
!pip install scikit-learn-extra直接安装
3. K-Medoids算法核心原理
K-Medoids算法的核心思想可以概括为以下步骤:
- 初始化 :随机选择k个数据点作为初始medoids
- 分配阶段 :将每个点分配到最近的medoid所在的簇
- 更新阶段 :在每个簇中,选择使总距离最小的点作为新medoid
- 迭代 :重复2-3步直到medoids不再变化或达到最大迭代次数
与K-Means的关键区别在于更新规则:
| 算法特性 | K-Means | K-Medoids |
|---|---|---|
| 簇中心类型 | 均值点(可能虚拟) | 实际数据点 |
| 距离度量 | 主要用欧氏距离 | 支持任意距离 |
| 计算复杂度 | O(n) | O(n²) |
| 抗噪性 | 弱 | 强 |
| 适用数据规模 | 大规模 | 中小规模 |
4. 完整实战案例:客户价值分析
让我们通过一个实际的客户价值分析案例,对比K-Means和K-Medoids的表现。假设我们有一组客户数据,包含年消费额和购买频率两个维度,其中混入了一些异常值。
4.1 数据准备与可视化
首先生成模拟数据并添加噪声:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# 生成正常客户数据
X, _ = make_blobs(n_samples=300, centers=3, cluster_std=0.8, random_state=42)
# 添加异常值
np.random.seed(42)
outliers = np.random.uniform(low=-10, high=20, size=(20, 2))
X = np.vstack([X, outliers])
# 可视化
plt.scatter(X[:, 0], X[:, 1], s=50, alpha=0.6)
plt.title("原始数据分布(含异常值)")
plt.xlabel("年消费额(标准化)")
plt.ylabel("购买频率(标准化)")
plt.show()
4.2 K-Means vs K-Medoids对比实现
现在让我们同时实现两种算法进行对比:
from sklearn.cluster import KMeans
from sklearn_extra.cluster import KMedoids
from sklearn.metrics import silhouette_score
# K-Means实现
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans_labels = kmeans.fit_predict(X)
kmeans_score = silhouette_score(X, kmeans_labels)
# K-Medoids实现
kmedoids = KMedoids(n_clusters=3, random_state=42)
kmedoids_labels = kmedoids.fit_predict(X)
kmedoids_score = silhouette_score(X, kmedoids_labels)
# 可视化对比
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.scatter(X[:, 0], X[:, 1], c=kmeans_labels, s=50, alpha=0.6)
ax1.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
marker='x', s=200, linewidths=3, color='r')
ax1.set_title(f"K-Means (轮廓系数: {kmeans_score:.2f})")
ax2.scatter(X[:, 0], X[:, 1], c=kmedoids_labels, s=50, alpha=0.6)
ax2.scatter(kmedoids.cluster_centers_[:, 0], kmedoids.cluster_centers_[:, 1],
marker='x', s=200, linewidths=3, color='r')
ax2.set_title(f"K-Medoids (轮廓系数: {kmedoids_score:.2f})")
plt.show()
4.3 结果分析与业务解读
从可视化结果中我们可以明显看出:
- K-Means 的簇中心被异常值拉偏,导致部分正常点被错误分类
- K-Medoids 的簇中心始终位于数据密集区域,对异常值表现出良好的鲁棒性
- 轮廓系数也显示K-Medoids的聚类质量更高
在实际业务中,这意味着:
- 客户细分更准确,不会因为少数极端客户影响整体分群
- 营销策略可以更有针对性,避免资源错配
- 异常客户能够被有效识别,便于单独分析
5. 高级技巧与优化建议
5.1 距离度量的选择
K-Medoids支持多种距离度量,通过 metric 参数指定:
# 使用曼哈顿距离
kmedoids_manhattan = KMedoids(n_clusters=3, metric="manhattan", random_state=42)
kmedoids_manhattan.fit(X)
# 使用余弦相似度
kmedoids_cosine = KMedoids(n_clusters=3, metric="cosine", random_state=42)
kmedoids_cosine.fit(X)
不同距离度量的适用场景:
| 距离类型 | 适用场景 | 优点 |
|---|---|---|
| 欧氏距离 | 连续数值数据,各维度尺度相似 | 直观,计算高效 |
| 曼哈顿距离 | 高维数据,存在稀疏特征 | 对异常值更鲁棒 |
| 余弦相似度 | 文本数据,方向比大小重要 | 不受向量长度影响 |
| 马氏距离 | 各维度相关性强的数据 | 考虑特征间相关性 |
5.2 处理大规模数据的技巧
由于K-Medoids的计算复杂度较高,对于大数据集可以考虑以下优化:
- 数据采样 :先在小样本上确定最佳参数,再应用到全量数据
- 并行计算 :利用
n_jobs参数启用多核并行 - 近似算法 :使用
method="alternate"加速收敛
# 启用并行计算
kmedoids_large = KMedoids(n_clusters=3, n_jobs=-1, random_state=42)
5.3 确定最佳簇数
除了轮廓系数,还可以使用肘部法则确定最佳簇数:
distortions = []
K_range = range(2, 8)
for k in K_range:
kmedoids = KMedoids(n_clusters=k, random_state=42)
kmedoids.fit(X)
distortions.append(kmedoids.inertia_)
plt.plot(K_range, distortions, 'bx-')
plt.xlabel('簇数(k)')
plt.ylabel('总距离平方和')
plt.title('肘部法则确定最佳簇数')
plt.show()
在实际项目中,建议结合业务理解和多种评估方法综合判断。
更多推荐


所有评论(0)