KMeans核心原理与关键代码实现
K-Means算法的核心原理是通过迭代将数据集划分为K个簇使得每个样本点到其所属簇质心的距离平方和最小。核心原理与流程K-Means是一种基于距离划分的无监督聚类算法其核心是优化误差平方和SSE算法流程如下表所示步骤描述核心操作1. 初始化随机选择K个样本点作为初始质心centroids X[np.random.choice(len(X), K, replaceFalse)]2. 分配样本计算每个样本点到所有质心的距离将其分配到最近的簇distances np.linalg.norm(X[:, np.newaxis] - centroids, axis2)labels np.argmin(distances, axis1)3. 更新质心重新计算每个簇中所有样本点的均值作为新的质心new_centroids np.array([X[labels i].mean(axis0) for i in range(K)])4. 收敛判断检查质心是否不再变化或SSE变化小于阈值if np.all(centroids new_centroids): break5. 迭代重复步骤2-4直到满足收敛条件循环执行关键代码实现以下是从头实现的Python代码包含了上述核心步骤import numpy as np import matplotlib.pyplot as plt class KMeans: def __init__(self, n_clusters3, max_iter300, tol1e-4): 初始化K-Means模型 :param n_clusters: 簇的数量K :param max_iter: 最大迭代次数 :param tol: 收敛容忍度质心变化阈值 self.n_clusters n_clusters self.max_iter max_iter self.tol tol self.centroids None self.labels None self.inertia_ None # 存储最终的SSE值 def fit(self, X): 训练模型拟合数据 :param X: 输入数据形状为 (n_samples, n_features) n_samples, n_features X.shape # 1. 初始化质心随机选择K个不同的样本点 random_indices np.random.choice(n_samples, self.n_clusters, replaceFalse) self.centroids X[random_indices] for iteration in range(self.max_iter): # 2. 分配样本到最近的质心 distances self._compute_distances(X) self.labels np.argmin(distances, axis1) # 3. 计算新的质心 new_centroids np.zeros((self.n_clusters, n_features)) for i in range(self.n_clusters): if np.sum(self.labels i) 0: # 防止空簇 new_centroids[i] X[self.labels i].mean(axis0) else: # 如果出现空簇重新随机初始化该质心 new_centroids[i] X[np.random.randint(n_samples)] # 4. 收敛判断检查质心变化是否小于容忍度 centroid_shift np.linalg.norm(new_centroids - self.centroids) if centroid_shift self.tol: print(f在第 {iteration 1} 次迭代后收敛) break self.centroids new_centroids # 计算最终的SSE惯性 self.inertia_ self._compute_inertia(X) def _compute_distances(self, X): 计算每个样本点到所有质心的欧氏距离 :param X: 输入数据 :return: 距离矩阵形状为 (n_samples, n_clusters) distances np.zeros((X.shape[0], self.n_clusters)) for i, centroid in enumerate(self.centroids): distances[:, i] np.linalg.norm(X - centroid, axis1) # 计算欧氏距离 return distances def _compute_inertia(self, X): 计算所有样本点到其所属质心的距离平方和SSE :param X: 输入数据 :return: SSE值 inertia 0 for i in range(self.n_clusters): cluster_points X[self.labels i] if len(cluster_points) 0: inertia np.sum((cluster_points - self.centroids[i]) ** 2) return inertia def predict(self, X): 预测新样本的簇标签 :param X: 新数据 :return: 预测的簇标签 distances self._compute_distances(X) return np.argmin(distances, axis1) # 使用示例 if __name__ __main__: # 生成模拟数据 np.random.seed(42) from sklearn.datasets import make_blobs X, y_true make_blobs(n_samples300, centers4, cluster_std0.60, random_state0) # 创建并训练K-Means模型 kmeans KMeans(n_clusters4, max_iter300, tol1e-4) kmeans.fit(X) # 输出结果 print(f最终质心坐标: {kmeans.centroids}) print(fSSE (惯性): {kmeans.inertia_:.2f}) # 可视化聚类结果 plt.figure(figsize(10, 4)) # 真实分布 plt.subplot(1, 2, 1) plt.scatter(X[:, 0], X[:, 1], cy_true, cmapviridis, s50, alpha0.7) plt.title(真实数据分布) plt.xlabel(特征 1) plt.ylabel(特征 2) # K-Means聚类结果 plt.subplot(1, 2, 2) plt.scatter(X[:, 0], X[:, 1], ckmeans.labels, cmapviridis, s50, alpha0.7) plt.scatter(kmeans.centroids[:, 0], kmeans.centroids[:, 1], cred, markerX, s200, label质心) plt.title(K-Means聚类结果) plt.xlabel(特征 1) plt.ylabel(特征 2) plt.legend() plt.tight_layout() plt.show()使用Scikit-learn库实现在实际应用中推荐使用优化过的scikit-learn库它提供了更高效、功能更完整的实现from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import silhouette_score # 1. 数据标准化重要步骤尤其是特征量纲不同时 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 2. 创建并训练模型 kmeans_sklearn KMeans(n_clusters4, initk-means, # 更智能的初始化方法加速收敛 n_init10, # 用不同初始质心运行10次取最佳结果 max_iter300, random_state42) kmeans_sklearn.fit(X_scaled) # 3. 获取结果 labels kmeans_sklearn.labels_ centroids scaler.inverse_transform(kmeans_sklearn.cluster_centers_) # 将质心逆变换回原始尺度 inertia kmeans_sklearn.inertia_ # 4. 评估聚类质量轮廓系数 silhouette_avg silhouette_score(X_scaled, labels) print(f轮廓系数: {silhouette_avg:.3f}) # 值越接近1聚类效果越好 print(fSSE (惯性): {inertia:.2f})关键参数与优化技巧参数/技巧说明代码示例/建议K值选择使用肘部法则或轮廓系数确定最佳K值inertias [KMeans(n_clustersk).fit(X).inertia_ for k in range(1, 10)]质心初始化k-means比随机初始化更快收敛效果更好KMeans(initk-means, n_init10)数据标准化对量纲不同的特征必须标准化StandardScaler().fit_transform(X)空簇处理算法实现中需防止空簇导致计算错误检查簇大小为空时重新初始化质心收敛加速Elkan K-Means利用三角不等式减少距离计算KMeans(algorithmelkan)应用场景示例客户RFM分群K-Means常用于客户细分例如基于RFM最近消费时间、消费频率、消费金额模型import pandas as pd from sklearn.cluster import KMeans # 假设df是客户交易数据已计算好R、F、M三个特征 df[[Recency, Frequency, Monetary]] ... # 计算RFM值 # 标准化数据 from sklearn.preprocessing import StandardScaler scaler StandardScaler() rfm_scaled scaler.fit_transform(df[[Recency, Frequency, Monetary]]) # 使用肘部法则确定K值 inertias [] K_range range(1, 11) for k in K_range: kmeans KMeans(n_clustersk, random_state42) kmeans.fit(rfm_scaled) inertias.append(kmeans.inertia_) # 可视化肘部曲线通常选择拐点处的K值 plt.plot(K_range, inertias, bx-) plt.xlabel(K值) plt.ylabel(SSE) plt.title(肘部法则确定最佳K值) plt.show() # 假设确定K4为最佳 best_kmeans KMeans(n_clusters4, random_state42) df[Cluster] best_kmeans.fit_predict(rfm_scaled) # 分析各簇特征 cluster_profile df.groupby(Cluster)[[Recency, Frequency, Monetary]].mean() print(cluster_profile)算法局限性K-Means算法虽然经典但也有其局限性主要包括1) 需要预先指定K值2) 对初始质心敏感可能陷入局部最优3) 对噪声和离群点敏感4) 假设簇为凸形且大小相近对非球形簇效果不佳。对于这些情况可考虑使用DBSCAN基于密度或GMM高斯混合模型等替代算法。参考来源【数据挖掘】K-Means算法实战从核心原理到Python代码实现K-means 聚类算法分析【数据挖掘】聚类算法学习—K-MeansK-means聚类算法及python代码实现从密度到聚类DBSCAN算法的第一性原理解析【聚类算法】Elkan K-Means算法