K-means聚类算法详解 一、基本概念 1.1 什么是K-means聚类? K-means聚类(K-means Clustering)是一种经典的无监督学习算法 ,用于将数据集划分为K个互不重叠的簇 (clusters)。其核心目标是:
最大化簇内相似度 :同一簇内的数据点尽可能相似
最大化簇间差异度 :不同簇之间的数据点尽可能不同
1.2 算法类型
无监督学习 :不需要标签数据
基于划分的聚类 :将数据划分为预设数量的簇
原型聚类 :每个簇由一个质心(centroid)代表
1.3 核心思想 “物以类聚,人以群分 “——将数据点分配到距离最近的簇中心,通过迭代优化簇中心位置,使簇内误差平方和最小化。
二、数学原理 2.1 目标函数(损失函数) K-means的目标是最小化簇内误差平方和 (Sum of Squared Errors, SSE):
$$ J = \sum_{i=1}^{K} \sum_{x \in C_i} ||x - \mu_i||^2 $$
其中:
$K$:簇的数量
$C_i$:第$i$个簇
$x$:数据点
$\mu_i$:第$i$个簇的质心(均值)
$||x - \mu_i||^2$:数据点到质心的欧氏距离平方
2.2 距离度量 2.2.1 欧氏距离(Euclidean Distance) 最常用的距离度量:
$$ d(x, \mu) = \sqrt{\sum_{j=1}^{n} (x_j - \mu_j)^2} $$
2.2.2 其他距离度量
曼哈顿距离 (Manhattan Distance)
切比雪夫距离 (Chebyshev Distance)
余弦相似度 (Cosine Similarity)
三、算法流程 3.1 基本步骤 步骤1:初始化(Initialization) 随机选择K个数据点 作为初始簇中心(质心)。
问题 :随机初始化可能导致:
解决方案 :使用K-means++算法(见第五部分)
步骤2:分配(Assignment) 对于每个数据点,计算其到所有簇中心的距离,将其分配到距离最近的簇 :
$$ C^{(t+1)}(i) = \arg\min_k ||x^{(i)} - \mu_k^{(t)}||^2 $$
步骤3:更新(Update) 重新计算每个簇的质心(均值):
$$ \mu_k^{(t+1)} = \frac{1}{|C_k|} \sum_{x^{(i)} \in C_k} x^{(i)} $$
步骤4:迭代(Iteration) 重复步骤2和3,直到满足停止条件:
簇中心不再变化(或变化很小)
达到最大迭代次数
目标函数收敛
3.2 算法伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 输入:数据集X = {x₁, x₂, ..., xₘ},簇数量K,最大迭代次数max_iter 输出:簇划分C = {C₁, C₂, ..., Cₖ},簇中心μ = {μ₁, μ₂, ..., μₖ} 1. 初始化:随机选择K个数据点作为初始簇中心 μ₁, μ₂, ..., μₖ 2. for iter = 1 to max_iter do: 3. # 分配阶段 4. for i = 1 to m do: 5. 计算 xᵢ 到每个簇中心的距离 6. 将 xᵢ 分配到距离最近的簇 7. end for 8. 9. # 更新阶段 10. for k = 1 to K do: 11. μₖ = 当前簇Cₖ中所有点的均值 12. end for 13. 14. # 检查收敛 15. if 簇中心变化 < 阈值 then: 16. break 17. end if 18. end for 19. return C, μ
3.3 收敛性证明 K-means算法一定收敛 ,原因:
目标函数单调递减 :
分配阶段:固定簇中心,最小化距离 → 目标函数减小
更新阶段:固定簇划分,计算均值 → 目标函数最小化
状态空间有限 :
数据点有限,簇划分的可能组合有限
目标函数有下界(≥ 0)
收敛到局部最优 :
由于是贪心算法,只能保证收敛到局部最优解
多次运行取最优结果
四、K值选择方法 4.1 手肘法(Elbow Method) 4.1.1 原理 绘制K值 与SSE 的关系曲线,选择”肘部”点(SSE下降速度明显变缓的点)。
4.1.2 实现步骤 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import matplotlib.pyplot as pltfrom sklearn.cluster import KMeanssse = [] k_range = range (1 , 11 ) for k in k_range: kmeans = KMeans(n_clusters=k, random_state=42 ) kmeans.fit(X) sse.append(kmeans.inertia_) plt.plot(k_range, sse, 'bo-' ) plt.xlabel('K值' ) plt.ylabel('SSE(簇内误差平方和)' ) plt.title('肘部法选择最佳K值' ) plt.grid(True ) plt.show()
4.1.3 判读方法
肘部点 :曲线斜率明显变化的点
主观性强 :需要人工判断
4.2 轮廓系数法(Silhouette Coefficient) 4.2.1 定义 轮廓系数衡量样本与其所在簇的相似度与其他簇的不相似度:
$$ s(i) = \frac{b(i) - a(i)}{\max{a(i), b(i)}} $$
其中:
$a(i)$:样本 $i$ 到同簇其他样本的平均距离(簇内凝聚度)
$b(i)$:样本 $i$ 到最近其他簇所有样本的平均距离(簇间分离度)
4.2.2 取值范围
$s(i) \in [-1, 1]$
$s(i) \approx 1$:样本非常适合所在簇
$s(i) \approx 0$:样本在两个簇边界
$s(i) \approx -1$:样本可能被错误分配
4.2.3 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from sklearn.metrics import silhouette_scoresilhouette_scores = [] for k in range (2 , 11 ): kmeans = KMeans(n_clusters=k, random_state=42 ) labels = kmeans.fit_predict(X) score = silhouette_score(X, labels) silhouette_scores.append(score) plt.plot(range (2 , 11 ), silhouette_scores, 'ro-' ) plt.xlabel('K值' ) plt.ylabel('平均轮廓系数' ) plt.title('轮廓系数法选择最佳K值' ) plt.grid(True ) plt.show() best_k = range (2 , 11 )[np.argmax(silhouette_scores)] print (f"最佳K值: {best_k} " )
4.3 Gap Statistic方法 4.3.1 原理 比较实际数据的SSE与随机数据的SSE的差距(Gap),选择Gap最大的K值。
4.3.2 优点
五、改进算法 5.1 K-means++(优化初始化) 5.1.1 问题 标准K-means随机初始化可能导致:
5.1.2 改进策略 采用概率加权 的方式选择初始簇中心:
随机选择第一个簇中心
对于每个数据点 $x$,计算其到最近已选簇中心 的距离 $D(x)$
以概率 $\frac{D(x)^2}{\sum D(x)^2}$ 选择下一个簇中心
重复步骤2-3,直到选择K个簇中心
5.1.3 优点
5.1.4 实现 1 2 3 kmeans = KMeans(n_clusters=3 , init='k-means++' , random_state=42 ) kmeans.fit(X)
5.2 Mini-Batch K-means(优化大数据) 5.2.1 问题 标准K-means需要每次迭代使用全部数据 ,计算成本高。
5.2.2 改进策略 每次迭代只使用一小批数据 (mini-batch)更新簇中心:
随机选择一个小批量数据
将这批数据分配到最近的簇
使用增量更新 方式更新簇中心: $$ \mu_k^{(t+1)} = (1 - \eta_t) \mu_k^{(t)} + \eta_t \cdot \text{新样本均值} $$
5.2.3 优点
5.2.4 实现 1 2 3 4 from sklearn.cluster import MiniBatchKMeansmbkmeans = MiniBatchKMeans(n_clusters=3 , batch_size=100 , random_state=42 ) mbkmeans.fit(X)
5.3 Canopy聚类(预处理加速) 5.3.1 原理 先使用快速但粗糙的Canopy算法进行预聚类,再在每个Canopy内运行K-means。
5.3.2 步骤
选择两个距离阈值 $T_1 > T_2$
随机选择一个点作为Canopy中心
将距离 $< T_1$ 的点加入Canopy
将距离 $< T_2$ 的点从候选集中移除
重复直到所有点都被处理
5.3.3 优点
六、算法评估指标 6.1 内部指标(无需真实标签) 6.1.1 轮廓系数(Silhouette Coefficient) 已在4.2节详细介绍。
6.1.2 Calinski-Harabasz指数 $$ CH = \frac{\text{簇间离差平方和} / (K-1)}{\text{簇内离差平方和} / (n-K)} $$
1 2 3 4 from sklearn.metrics import calinski_harabasz_scorech_score = calinski_harabasz_score(X, labels) print (f"Calinski-Harabasz指数: {ch_score} " )
6.1.3 Davies-Bouldin指数 $$ DB = \frac{1}{K} \sum_{i=1}^{K} \max_{j \neq i} \left( \frac{S_i + S_j}{d(\mu_i, \mu_j)} \right) $$
其中 $S_i$ 是簇 $i$ 的平均离散度。
1 2 3 4 from sklearn.metrics import davies_bouldin_scoredb_score = davies_bouldin_score(X, labels) print (f"Davies-Bouldin指数: {db_score} " )
6.2 外部指标(需要真实标签) 6.2.1 调整兰德指数(Adjusted Rand Index, ARI) 衡量聚类结果与真实标签的一致性。
1 2 3 4 from sklearn.metrics import adjusted_rand_scoreari = adjusted_rand_score(true_labels, predicted_labels) print (f"调整兰德指数: {ari} " )
基于信息论的评估指标。
1 2 3 4 from sklearn.metrics import normalized_mutual_info_scorenmi = normalized_mutual_info_score(true_labels, predicted_labels) print (f"归一化互信息: {nmi} " )
6.2.3 同质性、完整性、V-measure 1 2 3 4 5 6 7 8 9 from sklearn.metrics import homogeneity_score, completeness_score, v_measure_scorehomo = homogeneity_score(true_labels, predicted_labels) comp = completeness_score(true_labels, predicted_labels) v_measure = v_measure_score(true_labels, predicted_labels) print (f"同质性: {homo} " )print (f"完整性: {comp} " )print (f"V-measure: {v_measure} " )
七、优缺点分析 7.1 优点 ✅ 简单高效 :算法原理简单,易于理解和实现 ✅ 计算速度快 :时间复杂度 $O(n \cdot K \cdot I \cdot d)$,适合大规模数据 ✅ 可扩展性好 :有多种改进算法适应不同场景 ✅ 结果直观 :每个簇由质心代表,易于解释 ✅ 广泛应用 :在多个领域都有成功应用案例
7.2 缺点 ❌ 需要预设K值 :需要事先知道或估计簇的数量 ❌ 对初始值敏感 :不同初始化可能导致不同结果 ❌ 只能发现凸形簇 :无法处理非凸形状的簇(如环形、月牙形) ❌ 对异常值敏感 :异常值会显著影响簇中心位置 ❌ 假设簇大小相近 :对大小差异很大的簇效果不佳 ❌ 只能处理数值型数据 :需要额外处理分类变量 ❌ 局部最优问题 :可能收敛到局部最优而非全局最优
八、应用场景 8.1 客户细分(Customer Segmentation) 8.1.1 应用场景
市场营销:将客户分为不同群体,制定针对性策略
产品推荐:基于用户群体特征推荐产品
客户价值分析:识别高价值客户群体
8.1.2 特征选择
8.2 图像分割(Image Segmentation) 8.2.1 应用场景
图像压缩:将相似颜色像素归为一类
目标检测:分割图像中的不同物体
医学影像:分割器官、肿瘤等区域
8.2.2 实现方法 将每个像素的RGB值作为特征,进行聚类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import numpy as npfrom sklearn.cluster import KMeansfrom PIL import Imageimg = Image.open ('image.jpg' ) img_array = np.array(img) h, w, c = img_array.shape X = img_array.reshape(-1 , 3 ) kmeans = KMeans(n_clusters=5 , random_state=42 ) labels = kmeans.fit_predict(X) segmented_img = kmeans.cluster_centers_[labels] segmented_img = segmented_img.reshape(h, w, 3 ).astype(np.uint8) result = Image.fromarray(segmented_img) result.save('segmented_image.jpg' )
8.3 文档聚类(Document Clustering) 8.3.1 应用场景
新闻分类:将相似新闻归为一类
主题建模:发现文档集合中的主题
搜索引擎:相似文档推荐
8.3.2 特征提取 使用TF-IDF、词袋模型等将文档转换为向量。
1 2 3 4 5 6 7 8 9 10 11 12 from sklearn.feature_extraction.text import TfidfVectorizerdocuments = ["文本1" , "文本2" , "文本3" , ...] vectorizer = TfidfVectorizer(max_features=1000 ) X = vectorizer.fit_transform(documents) kmeans = KMeans(n_clusters=5 , random_state=42 ) labels = kmeans.fit_predict(X)
8.4 异常检测(Anomaly Detection) 8.3.1 原理 异常点通常距离簇中心很远,可以通过距离判断。
1 2 3 4 5 6 7 8 9 10 11 distances = [] for i in range (len (X)): cluster = labels[i] centroid = kmeans.cluster_centers_[cluster] distance = np.linalg.norm(X[i] - centroid) distances.append(distance) threshold = np.percentile(distances, 95 ) anomalies = np.array(distances) > threshold
8.5 其他应用
生物信息学 :基因表达数据分析
社交网络 :社区发现
金融风控 :欺诈检测
推荐系统 :用户/物品聚类
九、实现示例 9.1 基础实现(Scikit-learn) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom sklearn.datasets import make_blobsfrom sklearn.preprocessing import StandardScalerX, y_true = make_blobs(n_samples=300 , centers=4 , cluster_std=0.60 , random_state=42 ) scaler = StandardScaler() X_scaled = scaler.fit_transform(X) kmeans = KMeans(n_clusters=4 , init='k-means++' , n_init=10 , max_iter=300 , random_state=42 ) labels = kmeans.fit_predict(X_scaled) plt.figure(figsize=(12 , 5 )) plt.subplot(1 , 2 , 1 ) plt.scatter(X[:, 0 ], X[:, 1 ], c='gray' , alpha=0.6 ) plt.title('原始数据' ) plt.xlabel('特征1' ) plt.ylabel('特征2' ) plt.grid(True ) plt.subplot(1 , 2 , 2 ) plt.scatter(X[:, 0 ], X[:, 1 ], c=labels, cmap='viridis' , alpha=0.6 ) plt.scatter(kmeans.cluster_centers_[:, 0 ], kmeans.cluster_centers_[:, 1 ], c='red' , marker='X' , s=200 , label='簇中心' ) plt.title('K-means聚类结果 (K=4)' ) plt.xlabel('特征1' ) plt.ylabel('特征2' ) plt.legend() plt.grid(True ) plt.tight_layout() plt.show() from sklearn.metrics import silhouette_score, calinski_harabasz_scoresilhouette = silhouette_score(X_scaled, labels) ch_score = calinski_harabasz_score(X_scaled, labels) print (f"轮廓系数: {silhouette:.4 f} " )print (f"Calinski-Harabasz指数: {ch_score:.2 f} " )print (f"簇中心:\n{kmeans.cluster_centers_} " )
9.2 K值选择(肘部法 + 轮廓系数) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom sklearn.metrics import silhouette_scoreX, _ = make_blobs(n_samples=500 , centers=4 , cluster_std=0.8 , random_state=42 ) sse = [] silhouette_scores = [] k_range = range (1 , 11 ) for k in k_range: kmeans = KMeans(n_clusters=k, init='k-means++' , n_init=10 , random_state=42 ) kmeans.fit(X) sse.append(kmeans.inertia_) if k > 1 : labels = kmeans.labels_ silhouette_scores.append(silhouette_score(X, labels)) else : silhouette_scores.append(0 ) fig, (ax1, ax2) = plt.subplots(1 , 2 , figsize=(15 , 5 )) ax1.plot(k_range, sse, 'bo-' , linewidth=2 , markersize=8 ) ax1.set_xlabel('K值' , fontsize=12 ) ax1.set_ylabel('SSE' , fontsize=12 ) ax1.set_title('肘部法' , fontsize=14 ) ax1.grid(True , alpha=0.3 ) ax2.plot(k_range, silhouette_scores, 'ro-' , linewidth=2 , markersize=8 ) ax2.set_xlabel('K值' , fontsize=12 ) ax2.set_ylabel('轮廓系数' , fontsize=12 ) ax2.set_title('轮廓系数法' , fontsize=14 ) ax2.grid(True , alpha=0.3 ) plt.tight_layout() plt.show() best_k_silhouette = np.argmax(silhouette_scores[1 :]) + 2 print (f"基于轮廓系数的最佳K值: {best_k_silhouette} " )print (f"最大轮廓系数: {max (silhouette_scores[1 :]):.4 f} " )
9.3 图像压缩应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom PIL import Imageimport urllib.requestfrom io import BytesIOurl = "https://images.unsplash.com/photo-1501854140801-50d01698950b" response = urllib.request.urlopen(url) img = Image.open (BytesIO(response.read())) img = img.resize((400 , 300 )) img_array = np.array(img) h, w, c = img_array.shape X = img_array.reshape(-1 , 3 ) k_values = [2 , 4 , 8 , 16 , 32 , 64 ] fig, axes = plt.subplots(2 , 3 , figsize=(15 , 10 )) for i, k in enumerate (k_values): kmeans = KMeans(n_clusters=k, random_state=42 , n_init=10 ) labels = kmeans.fit_predict(X) compressed_img = kmeans.cluster_centers_[labels] compressed_img = compressed_img.reshape(h, w, 3 ).astype(np.uint8) ax = axes[i//3 , i%3 ] ax.imshow(compressed_img) ax.set_title(f'K={k} (压缩比: {24 /(3 *np.log2(k)):.1 f} x)' , fontsize=12 ) ax.axis('off' ) plt.tight_layout() plt.show() fig, (ax1, ax2) = plt.subplots(1 , 2 , figsize=(12 , 6 )) ax1.imshow(img) ax1.set_title('原始图像' , fontsize=14 ) ax1.axis('off' ) kmeans = KMeans(n_clusters=16 , random_state=42 , n_init=10 ) labels = kmeans.fit_predict(X) compressed_img = kmeans.cluster_centers_[labels] compressed_img = compressed_img.reshape(h, w, 3 ).astype(np.uint8) ax2.imshow(compressed_img) ax2.set_title('压缩图像 (K=16)' , fontsize=14 ) ax2.axis('off' ) plt.tight_layout() plt.show()
9.4 客户细分实战 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 import pandas as pdimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeansfrom sklearn.preprocessing import StandardScalerfrom sklearn.decomposition import PCAnp.random.seed(42 ) n_customers = 1000 data = { '年龄' : np.random.normal(35 , 10 , n_customers), '年收入(万)' : np.random.normal(50 , 20 , n_customers), '消费金额(年)' : np.random.normal(20 , 10 , n_customers), '购买频率(月)' : np.random.poisson(2 , n_customers), '会员时长(年)' : np.random.uniform(0 , 10 , n_customers) } df = pd.DataFrame(data) scaler = StandardScaler() X_scaled = scaler.fit_transform(df) sse = [] for k in range (1 , 11 ): kmeans = KMeans(n_clusters=k, random_state=42 , n_init=10 ) kmeans.fit(X_scaled) sse.append(kmeans.inertia_) plt.figure(figsize=(10 , 5 )) plt.plot(range (1 , 11 ), sse, 'bo-' ) plt.xlabel('K值' ) plt.ylabel('SSE' ) plt.title('肘部法选择最佳K值' ) plt.grid(True ) plt.show() kmeans = KMeans(n_clusters=4 , random_state=42 , n_init=10 ) df['客户群体' ] = kmeans.fit_predict(X_scaled) group_stats = df.groupby('客户群体' ).mean() print ("各客户群体特征均值:" )print (group_stats)pca = PCA(n_components=2 ) X_pca = pca.fit_transform(X_scaled) plt.figure(figsize=(10 , 8 )) scatter = plt.scatter(X_pca[:, 0 ], X_pca[:, 1 ], c=df['客户群体' ], cmap='viridis' , alpha=0.6 , s=50 ) plt.colorbar(scatter, label='客户群体' ) plt.scatter(kmeans.cluster_centers_[:, 0 ], kmeans.cluster_centers_[:, 1 ], c='red' , marker='X' , s=200 , label='簇中心' ) plt.xlabel(f'PC1 ({pca.explained_variance_ratio_[0 ]:.2 %} 方差)' ) plt.ylabel(f'PC2 ({pca.explained_variance_ratio_[1 ]:.2 %} 方差)' ) plt.title('客户群体可视化(PCA降维)' ) plt.legend() plt.grid(True , alpha=0.3 ) plt.show() group_names = { 0 : '高价值忠诚客户' , 1 : '年轻潜力客户' , 2 : '普通大众客户' , 3 : '低频消费客户' } for i in range (4 ): print (f"\n【{group_names[i]} 】(群体{i} )" ) print (f" 样本数量: {sum (df['客户群体' ] == i)} " ) print (f" 平均年龄: {group_stats.loc[i, '年龄' ]:.1 f} 岁" ) print (f" 平均年收入: {group_stats.loc[i, '年收入(万)' ]:.1 f} 万" ) print (f" 平均年消费: {group_stats.loc[i, '消费金额(年)' ]:.1 f} 万" ) print (f" 平均购买频率: {group_stats.loc[i, '购买频率(月)' ]:.1 f} 次/月" ) print (f" 平均会员时长: {group_stats.loc[i, '会员时长(年)' ]:.1 f} 年" )
十、工程实践建议 10.1 数据预处理
缺失值处理 :删除或填充
异常值处理 :识别并处理
特征标准化 :必须进行标准化/归一化
特征选择 :选择与聚类目标相关的特征
降维处理 :高维数据可使用PCA降维
10.2 参数调优
K值选择 :结合肘部法、轮廓系数等方法
初始化方法 :优先使用K-means++
运行次数 :设置n_init参数多次运行取最优
最大迭代次数 :根据数据规模调整
10.3 结果验证
多次运行 :检查结果稳定性
可视化分析 :使用PCA/t-SNE降维可视化
业务验证 :结合业务知识判断合理性
对比实验 :与其他聚类算法对比
10.4 常见陷阱
忽略特征缩放 :不同量纲的特征会影响结果
盲目选择K值 :需要多种方法综合判断
忽视数据分布 :非凸形数据不适合K-means
过度解读结果 :聚类结果需要业务验证
十一、与其他聚类算法对比
特性
K-means
层次聚类
DBSCAN
高斯混合模型
是否需要预设K
✓
✗
✗
✓
处理非凸簇
✗
△
✓
✓
对异常值敏感
✓
△
✗
△
计算复杂度
$O(n)$
$O(n^2)$
$O(n \log n)$
$O(n)$
可扩展性
✓✓✓
✗
✓✓
✓✓
概率输出
✗
✗
✗
✓
总结 K-means聚类作为最经典、最常用的聚类算法 ,具有以下特点:
核心优势
简单高效 :易于理解和实现
计算快速 :适合大规模数据
应用广泛 :在多个领域都有成功案例
使用要点
必须进行特征标准化
合理选择K值 (肘部法 + 轮廓系数)
使用K-means++初始化
多次运行取最优结果
适用场景
数据分布近似球形
簇大小相近
簇间分离度高
需要快速聚类结果
局限性
无法处理非凸形簇
对异常值敏感
需要预设K值
可能收敛到局部最优
掌握K-means不仅是学习聚类算法的基础,更是理解更复杂无监督学习方法的起点。在实际应用中,应结合数据特点和业务需求,灵活选择和调整算法参数。