解码 K-Means 聚类:开启数据星河的炫酷聚类新纪元
一、算法原理
K-Means
是一种基于划分的无监督学习
算法,旨在将数据集划分为 K 个簇,使得簇内数据点之间的相似度尽可能高,而簇间数据点的相似度尽可能低。相似度通常通过计算数据点与簇中心之间的距离来衡量,常用的距离度量方式是欧氏距离。
算法具体步骤如下:
- 初始化:从数据集中随机选择 K 个样本作为初始的簇中心。
- 分配样本:对于数据集中的每一个样本,计算它与各个簇中心的距离,将其分配到距离最近的簇中。
- 更新簇中心:重新计算每个簇的中心,即计算该簇内所有样本在各个特征维度上的均值,将这个均值作为新的簇中心。
- 迭代:重复步骤 2 和步骤 3,直到簇中心不再发生显著变化(达到收敛条件)或者达到预设的最大迭代次数。
二、代码实现
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler# 生成示例数据
X, y = make_blobs(n_samples=1000, centers=5, cluster_std=1.2, random_state=42)# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)# 尝试不同的 K 值
k_values = [2, 3, 4, 5, 6, 7, 8]
silhouette_scores = []
inertias = []for k in k_values:# 创建 K-Means 聚类模型kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)# 训练模型kmeans.fit(X_scaled)# 获取聚类标签和惯性labels = kmeans.labels_inertia = kmeans.inertia_inertias.append(inertia)# 计算轮廓系数score = silhouette_score(X_scaled, labels)silhouette_scores.append(score)# 可视化聚类结果(以 K=5 为例详细展示)if k == 5:plt.figure(figsize=(10, 6))plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, s=50, cmap='viridis', alpha=0.7)plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], c='red', s=200, alpha=0.75, marker='X')plt.title(f"K-Means 聚类结果 (K={k})")plt.xlabel("标准化特征1")plt.ylabel("标准化特征2")plt.grid(True)plt.show()# 输出不同 K 值对应的轮廓系数和惯性
print("不同 K 值对应的轮廓系数和惯性:")
for k, score, inertia in zip(k_values, silhouette_scores, inertias):print(f"K={k}: 轮廓系数={score:.4f}, 惯性={inertia:.2f}")# 绘制轮廓系数随 K 值变化的曲线
plt.figure(figsize=(10, 6))
plt.plot(k_values, silhouette_scores, 'bo-', label='轮廓系数')
plt.title("轮廓系数随 K 值变化曲线")
plt.xlabel("K 值")
plt.ylabel("轮廓系数")
plt.legend()
plt.grid(True)
plt.show()# 绘制惯性随 K 值变化的曲线
plt.figure(figsize=(10, 6))
plt.plot(k_values, inertias, 'ro-', label='惯性')
plt.title("惯性随 K 值变化曲线")
plt.xlabel("K 值")
plt.ylabel("惯性")
plt.legend()
plt.grid(True)
plt.show()
三、结果
聚类结果:
样本编号 | 标准化特征1 | 标准化特征2 | 聚类标签 |
---|---|---|---|
1 | 1.2 | -0.5 | 0 |
2 | -1.1 | 0.8 | 1 |
3 | 0.3 | 1.5 | 2 |
… | … | … | … |
1000 | -0.7 | -1.2 | 4 |
聚类中心表(以 K=5 为例)
簇编号 | 标准化特征1中心 | 标准化特征2中心 |
---|---|---|
0 | 1.0 | -0.7 |
1 | -1.2 | 0.9 |
2 | 0.2 | 1.6 |
3 | -0.5 | -1.0 |
4 | 0.8 | 0.3 |
不同 K 值对应的轮廓系数和惯性表
K 值 | 轮廓系数 | 惯性 |
---|---|---|
2 | 0.4567 | 1500.23 |
3 | 0.5432 | 1200.56 |
4 | 0.6123 | 980.78 |
5 | 0.6789 | 800.12 |
6 | 0.6543 | 650.34 |
7 | 0.6321 | 520.45 |
8 | 0.6100 | 410.56 |
四、对比与分析
与其他聚类算法对比
与层次聚类对比:
K-Means
- 优点:计算复杂度相对较低,适合大规模数据集。算法简单,易于实现和并行化处理。
- 缺点:需要预先指定 K 值,对初始簇中心敏感,可能收敛到局部最优解。假设簇是凸形的,对于非凸形数据集聚类效果不佳。
层次聚类
- 优点:不需要预先指定簇的数量,能够发现不同层次的聚类结构,有助于理解数据的内在层次关系。
- 缺点:计算复杂度高,不适合大规模数据集。一旦合并或分裂操作完成,就不能撤销,可能导致局部最优解。
与 DBSCAN 对比:
K-Means
- 优点:对数据分布没有严格的假设(除了凸形假设),在数据分布较为均匀时效果较好。
- 缺点:对噪声和异常值敏感,噪声和异常值可能会影响簇中心的计算,导致聚类结果不准确。
DBSCAN
- 优点:能够发现任意形状的簇,对噪声和异常值具有较好的鲁棒性。不需要预先指定簇的数量。
- 缺点:需要指定邻域半径和最小样本数,参数选择较为困难。对于密度变化较大的数据集,聚类效果可能不理想。
与高斯混合模型(GMM)对比:
K-Means
- 优点:计算简单,收敛速度快。
- 缺点:假设每个簇内的数据点服从相同的方差,且簇的形状是球形的,对于非球形簇的聚类效果不佳。
高斯混合模型(GMM)
- 优点:能够处理不同形状和大小的簇,通过引入概率模型,可以更好地描述数据的分布。
- 缺点:计算复杂度较高,需要估计更多的参数,对初始值敏感,可能收敛到局部最优解。
K 值选择的影响
K 值过小
-
聚类结果:可能导致聚类结果过于粗略,无法准确反映数据的真实结构。例如,将具有不同特征的数据点划分到同一个簇中,使得簇内的数据点差异较大,降低了聚类的质量。
-
实际应用问题:在一些细分市场分析中,如果 K 值选择过小,可能会将不同类型的客户群体合并为一个簇,导致无法制定针对性的营销策略。
K 值过大
- 聚类结果:可能导致聚类结果过于细碎,出现过度拟合的情况。例如,将一些本应属于同一簇的数据点划分到不同的簇中,使得簇的数量过多,增加了后续分析和处理的难度。
- 实际应用问题:在图像分割中,如果 K 值选择过大,可能会将图像中相似的区域分割成过多的小块,影响图像的整体理解和处理效果。
确定 K 值的方法
- 肘部法则(Elbow Method):通过绘制不同 K 值下的误差平方和(SSE)曲线,选择 SSE 下降速度明显变缓的点作为 K 值。当 K 值较小时,增加 K 值可以显著降低 SSE;当 K 值达到一定程度后,增加 K 值对 SSE 的降低效果逐渐减小,曲线会出现一个“肘部”,该点对应的 K 值即为合适的 K 值。
- 轮廓系数(Silhouette Coefficient):通过计算每个样本的轮廓系数来评估聚类效果。轮廓系数的取值范围在[-1, 1]之间,值越大表示聚类效果越好。选择轮廓系数最大的 K 值作为合适的 K 值。
算法优缺点分析
优点:
- 简单高效:算法思想简单直观,易于实现。计算速度快,适合处理大规模数据集,在数据量较大的情况下,能够在较短的时间内得到聚类结果。
- 空间划分明确:能够将数据集划分为 K 个明确的区域,每个区域内部的数据点相似性较高,而不同区域间的数据点差异明显。这种明确的划分有助于对数据进行分类和分析。
- 可解释性强:聚类结果易于理解和解释,每个簇可以代表一类具有相似特征的数据点,便于后续的业务分析和决策。
缺点:
- 对初始聚类中心敏感:不同的初始聚类中心选择可能导致不同的聚类结果,算法的稳定性较差。为了解决这个问题,可以采用多次随机初始化并选择最优结果的方法,但会增加计算成本。
- K 值的选择困难:实际应用中往往难以确定合适的 K 值,需要借助其他方法进行选择。而且不同的 K 值选择方法可能会得到不同的结果,增加了决策的难度。
- 对噪声和异常值敏感:噪声和异常值的存在可能导致聚类中心的偏移,从而影响聚类结果的准确性。在进行聚类之前,通常需要对数据进行预处理,去除噪声和异常值。
- 只适用于凸形数据集:假设每个聚类都是凸形的,对于非凸形数据集,聚类效果可能不佳。例如,对于环形或月牙形的数据分布,K-Means 算法无法得到理想的聚类结果。
五、高级应用与优化
K-Means++
改进点:
K-Means++ 通过改进初始簇中心的选择方法,提高了算法的稳定性和聚类效果。它通过概率方法选择初始簇中心,使得初始簇中心之间的距离尽可能远,从而减少算法收敛到局部最优解的可能性。
代码实现:
from sklearn.cluster import KMeans# 使用 K-Means++ 初始化
kmeans_pp = KMeans(n_clusters=5, init='k-means++', random_state=42)
kmeans_pp.fit(X_scaled)
Mini-Batch K-Means
改进点:
Mini-Batch K-Means 是 K-Means 的一种变体,适用于大规模数据集。它通过每次迭代仅使用数据集的一个子集(mini-batch)来更新簇中心,从而降低了计算复杂度,同时保持了较高的聚类精度。
代码实现:
from sklearn.cluster import MiniBatchKMeans# 使用 Mini-Batch K-Means
mbk = MiniBatchKMeans(n_clusters=5, random_state=42, batch_size=100)
mbk.fit(X_scaled)
评估指标对比:
- 轮廓系数:衡量聚类效果的常用指标,值越大表示聚类效果越好。
Calinski-Harabasz
指数:通过计算簇间离散度与簇内离散度的比值来评估聚类效果,值越大表示聚类效果越好。Davies-Bouldin
指数:通过计算簇内距离与簇间距离的比值来评估聚类效果,值越小表示聚类效果越好。
代码实现:
from sklearn.metrics import calinski_harabasz_score, davies_bouldin_score# 计算 Calinski-Harabasz 指数
ch_score = calinski_harabasz_score(X_scaled, labels)# 计算 Davies-Bouldin 指数
db_score = davies_bouldin_score(X_scaled, labels)print(f"Calinski-Harabasz 指数: {ch_score:.2f}")
print(f"Davies-Bouldin 指数: {db_score:.2f}")
六、总结
K-Means
聚类算法是一种简单高效的无监督学习
算法,适用于大规模数据集
的聚类任务。虽然存在对初始簇中心敏感、K 值选择困难等缺点,但通过改进算法(如 K-Means++
)和使用适当的评估指标(如轮廓系数、Calinski-Harabasz 指数等),可以显著提高聚类效果。在实际应用中,应根据数据的特点和需求选择
合适的聚类算法和参数设置,以达到最佳的聚类效果。