K-均值聚类算法详解
一、引言
K-均值(K-means)是机器学习中最经典、最常用的无监督学习算法之一。它通过迭代的方式将数据集中的样本划分为K个簇,使得每个簇内的样本尽可能相似,而不同簇之间的样本尽可能不同。
本文将从K-均值的原理、实现步骤、优缺点以及应用场景等方面进行全面介绍,帮助读者深入理解这一基础但强大的聚类算法。
二、K-均值的原理
2.1 基本思想
K-均值算法的核心思想是通过不断迭代优化来最小化"簇内平方和"(Within-Cluster Sum of Squares, WCSS),即:
WCSS = Σ||x - μ||²其中x是样本点,μ是对应簇的质心(centroid)。
2.2 算法流程
K-均值的标准流程如下:
- 初始化:随机选择K个初始质心
- 分配阶段:将每个样本分配到距离最近的质心所在的簇
- 更新阶段:重新计算每个簇的质心(所有样本点的均值)
- 收敛判断:重复分配和更新步骤,直到质心不再显著变化或达到最大迭代次数
三、算法实现
3.1 Python实现
import numpy as np
import matplotlib.pyplot as plt
class KMeans:
def init(self, k=3, maxiters=100, tol=1e-4):
self.k = k
self.maxiters = maxiters
self.tol = tol
def fit(self, X):
# 初始化质心
nsamples, nfeatures = X.shape
self.centroids = X[np.random.choice(nsamples, self.k, replace=False)]
for _ in range(self.maxiters):
# 分配样本到最近的质心
labels = self.assignclusters(X)
# 保存旧质心用于收敛判断
oldcentroids = self.centroids.copy()
# 更新质心
self.updatecentroids(X, labels)
# 检查是否收敛
if self.isconverged(oldcentroids):
break
return labels
def assignclusters(self, X):
distances = np.sqrt(((X - self.centroids[:, np.newaxis])**2).sum(axis=2))
return np.argmin(distances, axis=0)
def updatecentroids(self, X, labels):
for i in range(self.k):
clusterpoints = X[labels == i]
if len(clusterpoints) > 0:
self.centroids[i] = clusterpoints.mean(axis=0)
def isconverged(self, oldcentroids):
return np.linalg.norm(self.centroids - oldcentroids) < self.tol
3.2 使用示例
# 生成测试数据
from sklearn.datasets import makeblobs
X, = makeblobs(nsamples=300, centers=4, nfeatures=2,
randomstate=42, clusterstd=1.5)
应用K-均值
kmeans = KMeans(k=4)
labels = kmeans.fit(X)
可视化结果
plt.figure(figsize=(10, 8))
colors = ['red', 'blue', 'green', 'purple']
for i in range(kmeans.k):
clusterpoints = X[labels == i]
plt.scatter(clusterpoints[:, 0], clusterpoints[:, 1],
c=colors[i], alpha=0.6, s=50)
plt.scatter(kmeans.centroids[:, 0], kmeans.centroids[:, 1],
c='black', marker='x', s=200, linewidths=3)
plt.title('K-Means Clustering Results')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
四、关键问题与挑战
4.1 K值的选择
选择最优的K值是K-均值面临的主要挑战。常用的方法包括:
- 肘部法则(Elbow Method):寻找WCSS下降速度明显减缓的点
- 轮廓系数(Silhouette Score):衡量聚类的紧密性和分离性
- Gap Statistic:比较实际数据与随机数据的聚类效果
4.2 初始化敏感性问题
K-均值的初始质心选择会影响最终结果。解决方案包括:
- K-means++:改进的初始化方法,使初始质心分布更合理
- 多次运行:执行算法多次并选择最佳结果
五、优缺点分析
优点
- 简单易懂:算法直观,易于理解和实现
- 高效快速:时间复杂度为O(nkd),适合大规模数据集
- 可扩展性好:易于并行化和分布式处理
缺点
- 需要预先指定K值:在实际应用中可能难以确定
- 对异常值敏感:异常值会影响质心的位置
- 假设球形簇:不适合发现任意形状的簇
- 对初始值敏感:不同的初始质心可能导致不同的聚类结果
六、改进版本
6.1 K-means++
K-means++通过改进初始质心的选择来缓解初始化敏感性问题:def kmeansplusplusinit(X, k):
nsamples, nfeatures = X.shape
centroids = np.zeros((k, nfeatures))
# 随机选择第一个质心
centroids[0] = X[np.random.randint(nsamples)]
for i in range(1, k):
# 计算每个点到最近质心的距离
distances = np.array([min([np.sum((x - c)**2) for c in centroids[:i]])
for x in X])
probabilities = distances / distances.sum()
# 根据概率选择下一个质心
cumulativeprobabilities = probabilities.cumsum()
r = np.random.rand()
for j, p in enumerate(cumulativeprobabilities):
if r < p:
centroids[i] = X[j]
break
return centroids
6.2 Mini-Batch K-means
适用于超大数据集的改进版本,使用数据子集进行迭代:
from sklearn.cluster import MiniBatchKMeans
minibatchkmeans = MiniBatchKMeans(nclusters=4, batchsize=100)
labels = minibatchkmeans.fitpredict(X)
七、应用场景
K-均值在实际中有广泛的应用:
- 客户细分:基于购买行为对客户进行分组
- 图像压缩:将像素颜色量化为K种主要颜色
- 文档分类:对文本向量进行聚类
- 异常检测:识别远离簇中心的异常点
- 基因表达分析:发现相似的基因表达模式
八、总结
K-均值作为经典的聚类算法,以其简洁性和高效性在数据挖掘和机器学习领域占据重要地位。尽管存在一些局限性,但通过合理的改进和应用场景适配,K-均值仍然是一个非常实用的工具。
掌握K-均值的原理和实现,不仅有助于理解无监督学习的本质,也为深入学习更复杂的聚类算法奠定了坚实基础。