二分K-means:让聚类更高效、更精准!
大家好!!欢迎再次来到我的技术分享博客~ 👋在前期文章中,我们系统剖析了K-means的随机初始化缺陷、Canopy+K-means的粗粒度预处理以及K-means++的概率化质心选择。今天,我们解锁另一种高效优化方案——二分K-means(Bisecting K-Means),它用层次分裂策略彻底规避初始点敏感性问题,并与前三篇内容形成完美闭环!🔗
- 📚 K-means算法详解
- 📚 Canopy + K-means优化方案
- 📚 K-means++优化算法
今天,我们将一起学习 二分K-means,看看它是如何通过一种递归二分的方法,来优化K-means算法的聚类效果和效率的!💡
📌 什么是二分K-means?
二分K-means 是对传统K-means算法的改进,它通过递归地将数据集一分为二,逐步增加聚类数量,直到达到指定的K值。这种方法可以避免传统K-means在初始化中心点时可能带来的问题,同时提高聚类的准确性和效率。🌱
🔍 二分K-means算法原理
二分K-means的核心思想是:通过递归二分的方式,逐步优化聚类结果。每次迭代中,算法会选择当前聚类中SSE(误差平方和)最大的那个聚类进行二分,直到聚类数量达到K。📉
📝 二分K-means算法步骤
-
初始化:将所有数据点视为一个聚类。🌐
-
计算SSE:计算当前所有聚类的SSE(误差平方和)。SSE越小,说明聚类效果越好。📊
-
选择二分聚类:选择SSE最大的那个聚类进行二分。🔍
-
执行K-means++:对选定的聚类使用K-means++算法进行二分(即分为两个聚类)。🚀
-
重复步骤2-4:直到聚类数量达到指定的K值。🔄
-
输出结果:得到最终的K个聚类。🎉
🌟 二分K-means的优缺点
优点
- 提高聚类准确性:通过递归二分的方式,逐步优化聚类结果,更有可能找到全局最优解。📈
- 避免初始中心点问题:使用K-means++进行二分,避免了传统K-means在初始化中心点时可能带来的问题。🛠️
- 高效性:相比传统K-means,二分K-means在达到相同聚类效果时,通常需要更少的迭代次数。⏳
缺点
- K值需要预先指定:和传统K-means一样,二分K-means也需要预先指定K值,而K值的选择对聚类结果有很大影响。🔢
- 可能陷入局部最优:虽然相比传统K-means有所改进,但二分K-means仍然可能陷入局部最优解,特别是在数据分布复杂的情况下。🌀
🌈 适用场景
二分K-means适用于大多数需要聚类的场景,特别是当数据集较大、维度较高,且对聚类准确性有较高要求时。例如:
- 图像分割:将图像中的像素点聚类成不同的区域,提高分割的准确性。🖼️
- 客户细分:根据客户的购买行为将客户聚类成不同的群体,以便进行更精准的营销。🛍️
- 异常检测:通过聚类识别出数据中的异常点或离群点。🔍
💻 场景示例代码
下面是一个使用Python和自定义函数实现二分K-means的简单示例(由于scikit-learn没有直接提供二分K-means的实现,我们通过自定义函数来模拟):
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobsdef binary_kmeans(X, K):# 初始化聚类中心列表和聚类标签列表centers = [np.mean(X, axis=0)]labels = np.zeros(len(X), dtype=int)# 递归二分直到聚类数量达到Kwhile len(centers) < K:# 计算每个聚类的SSEsse = []for i, center in enumerate(centers):cluster_points = X[labels == i]distances = np.linalg.norm(cluster_points - center, axis=1)sse.append(np.sum(distances ** 2))# 选择SSE最大的聚类进行二分max_sse_idx = np.argmax(sse)cluster_points = X[labels == max_sse_idx]# 使用K-means++进行二分kmeans = KMeans(init='k-means++', n_clusters=2, random_state=0)kmeans.fit(cluster_points)new_labels = kmeans.labels_# 更新聚类中心和聚类标签centers[max_sse_idx] = kmeans.cluster_centers_[0]centers.append(kmeans.cluster_centers_[1])# 更新所有点的聚类标签new_labels = new_labels + max_sse_idx * np.ones_like(new_labels) # 调整标签以避免冲突for i, label in enumerate(labels):if label == max_sse_idx:labels[i] = new_labels[np.where((cluster_points == X[i]).all(axis=1))[0][0]]# 对于新加入的点(即二分后的第二个聚类中的点),需要重新分配标签(这里简化处理,实际可能需要更复杂的逻辑)# 由于上述简化处理可能不完美,以下是一个更完整的标签更新方式(但可能不是最高效的)# 更完整的标签更新(重新计算所有点的标签)all_centers = np.array(centers)distances = np.linalg.norm(X[:, np.newaxis] - all_centers, axis=2)labels = np.argmin(distances, axis=1)return labels, centers# 生成模拟数据
X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)# 使用二分K-means进行聚类
labels, centers = binary_kmeans(X, 4)# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis')
plt.scatter(np.array(centers)[:, 0], np.array(centers)[:, 1], c='red', s=200, alpha=0.75)
plt.title("Binary K-means Clustering")
plt.show()
注意:上面的代码是一个简化版的二分K-means实现,用于演示算法原理。在实际应用中,可能需要更复杂的逻辑来处理标签更新和聚类中心的存储。为了更高效和准确的实现,可以考虑使用其他优化方法或库。
运行这段代码,你将看到一幅聚类结果图,其中不同颜色的点代表不同的聚类,红色的点代表聚类中心。🖼️
🌐总结
二分K-means以层次分裂策略重塑K-means流程,是处理大规模稳定聚类的利器。其核心价值在于:
- 绝对稳定的输出:消除随机初始化影响
- 高效的树形分裂:K-1次迭代完成聚类
- 天然并行化:满二叉树结构适配分布式计算
💡 横向对比:
方法 | 初始点敏感性 | 速度 | 簇均衡性 | 适用场景 |
---|---|---|---|---|
K-means随机 | 极高 | 慢 | 中 | 小型均匀数据集 |
K-means++ | 低 | 中 | 高 | 中小型数据 |
Canopy+K-means | 中低 | 中慢 | 中 | 大样本高维数据 |
二分K-means | 极低 | 快 | 低 | 大规模稳定聚类 |
🔮 预告:下一篇笔记介绍ISODATA优化算法
在下一篇博客中,我们将继续探索K-means的优化方案,介绍ISODATA算法。ISODATA通过动态调整聚类数量和合并/分裂聚类,来应对数据分布复杂的情况。敬请期待哦!🎉
感谢大家的阅读!如果你对二分K-means或任何其他技术话题有疑问或建议,欢迎在评论区留言!💬
希望这篇博客能帮助你更好地理解二分K-means算法!如果你觉得有用,别忘了点赞、分享和关注哦!👍🔄👀
拓展阅读
1、一文搞懂K-means聚类:原理、选K技巧、实战代码全解析
2、Canopy + K-means:聚类算法的“黄金搭档”优化方案(附代码)
3、K-means++:让K-means“聪明”地选择初始中心点