
1. K-Means聚类算法入门指南第一次听说K-Means聚类算法时我脑海中浮现的是小时候玩磁铁的场景——铁屑会自动聚集到磁极周围。这个简单的物理现象完美诠释了聚类的核心思想让相似的数据点自动吸附到同一个中心点周围。K-Means作为最经典的聚类算法之一它的工作原理出奇地简单随机选取K个中心点就像放置K块磁铁计算每个数据点到中心点的距离归入最近的中心点铁屑被磁铁吸引重新计算每个簇的中心点位置移动磁铁到铁屑群的中心重复2-3步直到中心点不再移动磁铁找到最终位置这个算法最神奇的地方在于它不需要任何先验标签完全依靠数据自身的分布规律来发现内在结构。就像考古学家通过陶器碎片自动分类来推测古代文明类型一样K-Means能帮助我们发现数据中隐藏的文明类型。2. 从零实现K-Means算法2.1 算法核心实现让我们用Python一步步构建自己的K-Means类。先看核心代码框架import numpy as np import matplotlib.pyplot as plt class MyKMeans: def __init__(self, n_clusters3, max_iter300): self.n_clusters n_clusters # 聚类数量 self.max_iter max_iter # 最大迭代次数 self.centroids None # 中心点存储 self.history [] # 记录迭代过程 def fit(self, X): # 随机初始化中心点 indices np.random.choice(len(X), self.n_clusters, replaceFalse) self.centroids X[indices] for _ in range(self.max_iter): # 分配样本到最近的中心点 distances np.linalg.norm(X[:, np.newaxis] - self.centroids, axis2) labels np.argmin(distances, axis1) # 更新中心点位置 new_centroids np.array([X[labelsk].mean(axis0) for k in range(self.n_clusters)]) # 记录当前状态用于可视化 self.history.append((np.copy(self.centroids), np.copy(labels))) # 检查是否收敛 if np.allclose(self.centroids, new_centroids): break self.centroids new_centroids这个实现包含了K-Means的核心逻辑随机选择初始中心点np.random.choice计算每个点到中心点的欧式距离np.linalg.norm将点分配到最近的中心点np.argmin重新计算中心点位置mean(axis0)2.2 距离计算的优化技巧实际项目中距离计算可能成为性能瓶颈。我们可以用矩阵运算加速def _calc_distances(X, centroids): 向量化距离计算 X_sq np.sum(X**2, axis1, keepdimsTrue) C_sq np.sum(centroids**2, axis1) cross np.dot(X, centroids.T) return np.sqrt(X_sq C_sq - 2*cross)这种方法避免了显式循环利用广播机制和矩阵乘法加速计算。在我的测试中万级数据点的计算时间从3秒缩短到0.1秒。3. 动态可视化眼见为实的聚类过程3.1 基础可视化方法让我们用Matplotlib实现迭代过程的可视化def plot_iteration(self, iteration): centroids, labels self.history[iteration] plt.figure(figsize(8,6)) # 绘制数据点 for k in range(self.n_clusters): cluster_data X[labels k] plt.scatter(cluster_data[:,0], cluster_data[:,1], labelfCluster {k}, alpha0.6) # 绘制中心点轨迹 for k in range(self.n_clusters): path np.array([step[0][k] for step in self.history[:iteration1]]) plt.plot(path[:,0], path[:,1], k--, linewidth1) plt.scatter(centroids[k,0], centroids[k,1], cblack, markerx, s100) plt.title(fIteration {iteration}) plt.legend() plt.show()3.2 交互式可视化进阶使用IPython的交互控件可以创建更生动的演示from ipywidgets import interact def show_animation(): interact(iteration(0, len(kmeans.history)-1, 1)) def update(iteration0): kmeans.plot_iteration(iteration) show_animation()这样就能通过滑块实时观察中心点如何一步步找到最佳位置就像看一场数据点的集体舞蹈。4. 鸢尾花数据集实战4.1 数据准备与预处理from sklearn.datasets import load_iris iris load_iris() X iris.data[:, :2] # 只取前两个特征方便可视化 y iris.target # 数据标准化 X (X - X.mean(axis0)) / X.std(axis0) plt.scatter(X[:,0], X[:,1], cy) plt.xlabel(Sepal Length (标准化)) plt.ylabel(Sepal Width (标准化))4.2 聚类效果评估我们实现一个轮廓系数评估方法from sklearn.metrics import silhouette_samples def plot_silhouette(X, labels): silhouette_vals silhouette_samples(X, labels) y_lower 10 for k in range(len(np.unique(labels))): kth_cluster silhouette_vals[labels k] kth_cluster.sort() plt.barh(range(y_lower, y_lowerlen(kth_cluster)), kth_cluster, height1) y_lower len(kth_cluster) 10 plt.axvline(xnp.mean(silhouette_vals), colorred, linestyle--) plt.ylabel(Cluster) plt.xlabel(Silhouette Coefficient)应用示例kmeans MyKMeans(n_clusters3) kmeans.fit(X) plot_silhouette(X, kmeans.labels_)5. 算法优化与实用技巧5.1 K-Means初始化原始K-Means对初始中心点敏感改进版K-Means能显著提升效果def _kmeans_plus_plus(X, n_clusters): centroids [X[np.random.randint(len(X))]] for _ in range(1, n_clusters): distances np.array([min([np.linalg.norm(x-c)**2 for c in centroids]) for x in X]) prob distances / distances.sum() centroids.append(X[np.argmax(prob)]) return np.array(centroids)5.2 肘部法则确定K值def find_optimal_k(X, max_k10): inertias [] for k in range(1, max_k1): kmeans MyKMeans(n_clustersk) kmeans.fit(X) inertias.append(kmeans.inertia_) plt.plot(range(1, max_k1), inertias, bo-) plt.xlabel(Number of clusters) plt.ylabel(Inertia) plt.show()6. 与scikit-learn的实现对比scikit-learn的KMeans在效率和功能上更强大from sklearn.cluster import KMeans sk_kmeans KMeans(n_clusters3) sk_kmeans.fit(X) # 比较中心点位置 print(Our centroids:\n, kmeans.centroids) print(sklearn centroids:\n, sk_kmeans.cluster_centers_)主要差异包括支持多种距离度量更高效的C底层实现提供并行计算选项完整的API接口7. 常见问题与解决方案问题1空簇现象原因初始中心点位置不佳导致某些簇无样本解决重新初始化或采用K-Means问题2不同量纲影响现象某个特征值范围远大于其他特征解决数据标准化(X - mean)/std问题3非球形簇效果差示例环形分布数据替代方案考虑DBSCAN等密度聚类算法8. 进阶应用图像压缩K-Means可应用于图像颜色压缩from sklearn.datasets import load_sample_image china load_sample_image(china.jpg) X china.reshape(-1, 3) / 255 kmeans MyKMeans(n_clusters16) kmeans.fit(X) compressed kmeans.centroids[kmeans.labels_].reshape(china.shape)这样就将数百万种颜色压缩到16种代表性颜色图像大小可减少90%以上。