简介:这份资源面向机器学习初学者与需要做故障诊断的工程人员,提供KMeans聚类的样本数据与可视化源码,帮助解决无监督场景下故障类型自动分组、聚类数目难以确定的问题。压缩包共2个文件,约57KB,包含1个xlsx数据表与1个m脚本:数据表存放设备异常加热片段等故障样本,脚本则实现聚类流程与结果可视化,二者配合即可完成从数据读取到图形输出的完整实验。资源重点演示了用Calinski-Harabasz指数评估聚类效果、以指数最大值确定最佳聚类数的方法,并借助散点图、直方图或箱线图直观呈现各簇分布,便于理解类间分离度与类内紧凑性。目前已有4508人学习下载,适合希望快速上手聚类分析、对照代码复现故障分类实验的读者参考。
1. Kmeans 聚类样本 + 可视化源码:从一份数据到一张能讲清楚的图
手上拿到一份没有标签的样本表,老板或客户只丢下一句「看看能分成几类」,这大概是 Kmeans 出现频率最高的场景。它属于无监督学习里最朴素也最实用的一类:给定样本集,预先指定簇数 K,算法反复把每个点分配给最近的质心,再重新计算质心,直到质心不再明显移动。它不告诉你「为什么」,只告诉你「谁和谁更像」。配合可视化源码,你能把高维特征压到二维平面上,用散点颜色把聚类结果直接画出来,一眼看出分簇是否合理、有没有离群点、K 选得对不对。
这套「样本 + 可视化源码」的组合,适合三类人:做数据分析想快速摸清数据分布的从业者、需要给非技术同事交付一张聚类结论图的产品/运营、以及正在学聚类算法想跑通完整链路的学生。它不解决所有聚类问题,密度不均、非球形簇、簇大小差异极大时,Kmeans 会翻车,这时候要换 DBSCAN 或层次聚类。但作为第一把锤子,它足够快、足够好解释,源码也短到能逐行读懂。下面按「先立住原理和选型,再动手复现,最后讲坑和进阶」的顺序展开。
2. Kmeans 的数学直觉与选型:为什么它先被拿来用
2.1 目标函数与迭代逻辑
Kmeans 要最小化的目标很直白:每个点到它所属簇质心的距离平方和,也就是 SSE(Sum of Squared Errors)。用公式写就是 ΣΣ||x - μ_i||²,外层遍历簇,内层遍历属于该簇的样本。算法分两步循环:分配步,固定质心,把每个样本分给最近的质心;更新步,固定分配,把每个质心移到它名下样本的均值位置。这两步交替,SSE 单调不增,所以一定收敛,但收敛到的可能是局部最优,不是全局最优。
这解释了两个常见现象。第一,初始质心不同,结果可能不同,所以要设n_init多次随机初始化取最优。第二,K 必须预先给定,因为目标函数里 K 是超参数,算法自己不会告诉你该分几类。理解这两点,后面调参和排错就有方向了。
2.2 距离度量与数据预处理
默认用欧氏距离,这也是「欧氏聚类」这个热搜词的来源。欧氏距离对量纲敏感:一个特征取值范围 0 到 1,另一个 0 到 10000,后者会主导距离计算,聚类结果基本被它绑架。所以标准做法是先做标准化,常用 Z-score(减均值除标准差)或 Min-Max 归一化。标准化之后每个特征权重相当,聚类才反映整体结构。
另一个预处理点是离群点。Kmeans 用均值更新质心,均值对极端值敏感,一个远离群体的点能把质心拽偏,连带整个簇变形。如果业务上离群点本身是重点(比如欺诈检测),不要直接删,可以先聚类再单独分析;如果只是噪声,考虑先剔除或改用对离群点更稳健的 K-medoids。
2.3 和层次聚类、DBSCAN 的选型对比
热搜里「层次聚类 python」「dbscan 聚类算法」和 Kmeans 经常一起出现,说明大家在选型上纠结。给一张对比表,按实际决策维度看:
| 维度 | Kmeans | 层次聚类 | DBSCAN |
|---|---|---|---|
| 是否需要预设簇数 | 需要 | 不需要,看树状图切 | 不需要,靠密度 |
| 簇形状假设 | 近似球形、大小相近 | 无强假设 | 任意形状 |
| 对离群点 | 敏感 | 较敏感 | 能识别噪声 |
| 大数据集速度 | 快 | 慢,O(n²) 以上 | 中等,依赖参数 |
| 结果可解释性 | 高,质心即代表 | 中,树状图直观 | 中,参数难调 |
选型建议:样本量大、簇大致球形、要快速出结论,选 Kmeans;样本量小、想看层次结构、不确定簇数,选层次聚类;簇形状不规则、有噪声、不想预设簇数,选 DBSCAN。很多实际项目会先用 Kmeans 快速摸底,再用 DBSCAN 验证密度结构,两者结果对照着看。
3. 用 sklearn 跑通 Kmeans:从样本到标签的最小代码
3.1 环境与依赖
常见做法是 Python 3.8 以上,装numpy、scikit-learn、matplotlib、pandas四个包就够。不指定具体版本号,因为不同版本 API 基本兼容,遇到KMeans参数报错再对照官方文档即可。安装命令:
pip install numpy scikit-learn matplotlib pandas如果要用中文标签,matplotlib 默认字体可能显示方块,需要额外设置字体,这一步在可视化章节处理。
3.2 生成或加载样本数据
为了可复现,先用make_blobs造一份带已知簇结构的数据,方便验证算法是否正确。真实项目里把这段换成pd.read_csv读自己的样本表即可。
import numpy as np from sklearn.datasets import make_blobs # 造 500 个样本,4 个簇,2 个特征,random_state 固定保证可复现 X, y_true = make_blobs( n_samples=500, centers=4, n_features=2, cluster_std=1.0, # 簇内标准差,越大簇越松散 random_state=42 ) print(X.shape) # (500, 2)n_samples控制样本量,centers是真实簇数,cluster_std控制簇的松散程度。真实数据没有y_true,这里保留只是为了后面和聚类结果对照。random_state一定要固定,否则每次跑出来的数据不同,没法排查问题。
3.3 标准化与训练
from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans # 标准化:Kmeans 对量纲敏感,这一步不能省 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 训练:n_clusters 是 K,n_init 是随机初始化次数,random_state 固定 kmeans = KMeans( n_clusters=4, n_init=10, # 跑 10 次不同初始化,取 SSE 最小的 max_iter=300, # 单次迭代上限 random_state=42 ) labels = kmeans.fit_predict(X_scaled) # 质心坐标(已标准化空间) centers = kmeans.cluster_centers_ print(labels[:10]) print(centers.shape) # (4, 2)n_init=10是经验值,样本量大或簇多时可以调到 20。max_iter一般 300 够用,如果收敛警告频繁出现再调大。fit_predict一步完成训练和预测,返回每个样本的簇标签。注意cluster_centers_是在标准化后的空间里,要还原到原始量纲得用scaler.inverse_transform。
3.4 评估聚类质量
没有真实标签时,用轮廓系数(silhouette score)和 SSE 两个指标。轮廓系数范围 -1 到 1,越接近 1 说明簇内紧、簇间远。
from sklearn.metrics import silhouette_score # 轮廓系数,样本量大时可用 sample_size 抽样加速 score = silhouette_score(X_scaled, labels, sample_size=500, random_state=42) print(f"轮廓系数: {score:.3f}") # SSE,即 inertia_,用来画肘部图 print(f"SSE: {kmeans.inertia_:.2f}")sample_size在样本超过几万时能显著提速,代价是估计值有波动。inertia_就是目标函数值,K 越大它越小,所以不能只看它绝对值,要看下降拐点。
4. 可视化源码:把聚类结果画成能交付的图
4.1 二维散点图与质心标注
最基础也最常用的图:样本按簇着色,质心用大标记标出。
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文标签 plt.rcParams['axes.unicode_minus'] = False plt.figure(figsize=(8, 6)) # 散点:c=labels 按簇着色,cmap 选定性色板 plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='viridis', s=30, alpha=0.7) # 质心:红色大叉 plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='X', s=200, label='质心') plt.title('Kmeans 聚类结果(K=4)') plt.xlabel('特征 1(标准化)') plt.ylabel('特征 2(标准化)') plt.legend() plt.tight_layout() plt.savefig('kmeans_result.png', dpi=150) plt.show()c=labels让每个簇自动分配颜色,cmap='viridis'是连续色板,簇多时换成'tab10'这类定性色板区分度更好。alpha控制透明度,样本重叠时能看出密度。dpi=150保证导出图清晰,交付够用。
4.2 肘部图选 K
K 选不对,图再漂亮也没意义。肘部图看 SSE 随 K 的下降曲线,找拐点。
sse = [] k_range = range(1, 11) for k in k_range: km = KMeans(n_clusters=k, n_init=10, random_state=42) km.fit(X_scaled) sse.append(km.inertia_) plt.figure(figsize=(8, 5)) plt.plot(k_range, sse, marker='o') plt.xlabel('簇数 K') plt.ylabel('SSE') plt.title('肘部图') plt.xticks(k_range) plt.grid(alpha=0.3) plt.tight_layout() plt.savefig('elbow.png', dpi=150) plt.show()拐点判断有主观性,常见做法是找下降速度明显变缓的位置。这份数据 K=4 附近应该能看到拐点。如果曲线平滑没有明显拐点,说明数据本身没有清晰簇结构,别硬分。
4.3 高维数据的降维可视化
真实样本往往几十上百维,直接画不了。常见做法是先用 PCA 降到二维再画,注意降维只用于可视化,聚类仍在原始标准化空间做。
from sklearn.decomposition import PCA pca = PCA(n_components=2, random_state=42) X_pca = pca.fit_transform(X_scaled) plt.figure(figsize=(8, 6)) plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap='tab10', s=30, alpha=0.7) plt.title('PCA 降维后的聚类结果') plt.xlabel(f'PC1(解释方差 {pca.explained_variance_ratio_[0]:.1%})') plt.ylabel(f'PC2(解释方差 {pca.explained_variance_ratio_[1]:.1%})') plt.tight_layout() plt.savefig('pca_cluster.png', dpi=150) plt.show()坐标轴标注解释方差比例,让读者知道这张二维图保留了多少原始信息。如果两个主成分加起来不到 50%,说明二维图失真严重,结论要谨慎。需要更强非线性降维可以换 t-SNE 或 UMAP,但它们的坐标轴没有物理意义,只适合看簇的分离度。
5. 避坑与排查:Kmeans 落地时最容易翻车的五件事
5.1 不标准化直接聚类,结果被大数值特征主导
现象:聚类结果和某个取值范围大的特征高度相关,其他特征几乎没起作用。原因:欧氏距离被大量纲特征主导。解决:训练前统一做 Z-score 或 Min-Max 标准化,并记录 scaler 用于还原质心。
5.2 K 靠拍脑袋定,肘部图不看
现象:换个人跑出不同簇数,结论对不上。原因:K 是超参数,没有唯一正确答案。解决:肘部图加轮廓系数双指标交叉验证,再结合业务可解释性定 K,把选择依据写进文档。
5.3 每次结果不一样,以为算法有 bug
现象:同一份数据两次运行簇标签不同。原因:初始化随机且未固定random_state,或n_init太小。解决:固定random_state,n_init设 10 以上,保证结果可复现。
5.4 用簇标签做后续分析,忘了标签会随运行变化
现象:上次「簇 0」是高风险客户,这次「簇 0」变成低风险。原因:Kmeans 的簇编号是任意的,没有固定语义。解决:每次聚类后按质心特征或簇内统计量重新映射语义,不要硬编码簇编号。
5.5 高维稀疏数据硬上 Kmeans
现象:文本 TF-IDF 或 one-hot 数据聚类效果差,簇内样本看不出共性。原因:高维空间距离趋于均匀,欧氏距离失效。解决:先降维(PCA/SVD)或改用余弦距离的球形 Kmeans,文本场景也可考虑主题模型替代。
6. 进阶技巧:让聚类结果真正能交付的三个习惯
第一个习惯是给每个簇生成画像。光有散点图不够,业务方要的是「这群人有什么共同点」。做法是对每个簇算各特征的均值和分布,挑差异最大的几个特征写成一句话描述。代码上就是pd.DataFrame(X_scaled).groupby(labels).mean(),再对照原始量纲解释。这一步能把「簇 2」翻译成「高消费低频次的中年用户」,交付价值立刻不一样。
第二个习惯是稳定性检验。Kmeans 对初始化和采样敏感,靠谱的做法是多次重采样聚类,看同一批样本是否稳定落在同一簇。可以用sklearn.utils.resample抽子集跑多次,统计每个样本的簇归属一致性,一致性低的样本往往是边界点,结论里要标注出来。这一步能提前发现「看起来分开了其实很脆弱」的假象。
第三个习惯是把可视化源码参数化。把簇数、颜色板、点大小、导出路径抽成配置,换数据时只改配置不改逻辑。我一般会留一个plot_clusters(X, labels, centers, title, save_path)函数,项目里反复调用。下面是一个可直接复用的封装:
def plot_clusters(X_2d, labels, centers_2d=None, title='聚类结果', save_path=None): """通用聚类可视化:X_2d 为二维坐标,centers_2d 可选""" plt.figure(figsize=(8, 6)) plt.scatter(X_2d[:, 0], X_2d[:, 1], c=labels, cmap='tab10', s=30, alpha=0.7) if centers_2d is not None: plt.scatter(centers_2d[:, 0], centers_2d[:, 1], c='red', marker='X', s=200, label='质心') plt.legend() plt.title(title) plt.tight_layout() if save_path: plt.savefig(save_path, dpi=150) plt.show()X_2d可以是原始二维特征,也可以是 PCA 降维结果,函数不关心来源。centers_2d可选,因为降维后质心需要单独变换。save_path为空时只显示不保存,方便调试。
最后说个血泪经验:聚类没有标准答案,别指望一次跑出完美结果。我现在的习惯是先跑三组不同 K 和预处理方案,把图并排贴出来对比,再和业务方一起挑。算法只是把数据摊开,真正决定分几类、怎么解释的,是对业务的理解。希望帮到你。
本文还有配套的精品资源,点击获取