
简介本资源是一套面向本科及以上学习者与科研初学者的K-means聚类分析MATLAB实践方案聚焦数据挖掘与无监督学习基础应用适用于课程设计、毕业设计及简单科研建模场景。压缩包共10个文件378KB含2个核心MATLAB脚本main1.m、main2.m实现算法调用、可视化与评估6张JPG图像展示聚类结果图、迭代过程及轮廓系数分析1个XLSX与1个XLS格式实测数据集全部代码配有中文注释便于理解原理与二次开发。已有231人下载学习资源结构清晰主程序驱动、数据支撑、结果可视化三位一体无需额外配置即可运行同时提供典型聚类效果对比与参数调试示例显著降低入门门槛助力快速掌握K-means在实际数据上的部署要点与结果解读方法。 kmeans聚类分析的MATLAB代码其实没有想象中那么玄乎。我手上这套代码是完整的工程文件不是网上那种只有核心几行、数据还得自己造的那种半成品。它自带了一组可以直接跑通的数据集你拿到手之后改一下数据文件的路径点击运行聚类结果、可视化图、评价指标就全都出来了。这篇文章就围绕这套代码把kmeans聚类分析在MATLAB里的实现思路、关键参数、常见报错一次讲清楚。不管你是刚开始接触聚类分析、正在做课程设计还是论文里需要一组能解释得通的聚类结果这套代码和这篇拆解都能直接帮上忙。1. 项目设计与整体思路拆解先说清楚这套代码解决什么问题。很多同学找到我第一句话就是老师你能不能给我一份kmeans的MATLAB代码要能直接运行出图的。这句话背后的需求其实很明确——他们需要的不是一段孤零零的kmeans函数调用而是一套从数据读取、预处理、聚类、结果分析到可视化的闭环代码。所以我设计这套代码的时候遵循了一个原则开箱即用但逻辑透明。所谓开箱即用就是数据和代码放在同一个目录下双击运行就能出结果。所谓逻辑透明就是代码里的每一步都有清晰的注释你不用去猜这一步到底在干什么。1.1 为什么选MATLAB而不是Python这是个绕不开的问题。现在Python的scikit-learn里也有现成的KMeans而且用起来似乎更简单。但我个人的观点是MATLAB在聚类分析这个场景下有几个独特的优势尤其是对非计算机专业出身的人。第一MATLAB的矩阵操作是天然的。kmeans聚类的本质是距离计算和中心点更新这两种操作用MATLAB的向量化语法写出来非常直观不用像Python那样还要考虑numpy的广播机制。第二MATLAB的绘图交互性更好。聚类结果的散点图、质心位置、轮廓系数图MATLAB的figure窗口支持直接旋转、缩放、保存为高清图片这种体验对论文插图来说非常友好。第三如果你后续要用到聚类评价指标比如轮廓系数、Calinski-Harabasz指数、Davies-Bouldin指数MATLAB的这些工具函数都是内置的不需要额外安装包。1.2 这套代码的整体架构我把整套代码拆成了三个层次对应三种不同深度的需求。第一层主脚本main_kmeans.m。这是整个项目的入口负责数据加载、调用聚类、输出结果。你只需要修改这一层的数据文件路径和聚类数K就可以跑通整个流程。第二层数据文件dataset.csv。这是一份真实的、非构造的数据集包含了多个维度的特征。为什么强调真实非构造因为用自己随机生成的假数据跑聚类结果永远是最完美的一上手做真实数据就各种问题矩阵维度对不上、量纲差异大、存在缺失值这些才是实际工作中的常态。第三层辅助脚本包括数据标准化、肘部法则确定K值、轮廓系数计算。这三块是让kmeans聚类从“能跑”到“跑得有意义”的关键。这三个层次的设计思路本质上是把一个完整的分析任务拆解成了“入口-数据-工具”三个模块。每模块之间的耦合度很低如果你只是想替换自己的数据只需要处理dataset.csv这一层如果你想深入研究聚类算法本身侧重看辅助脚本那一层即可。2. 核心细节解析与实操要点现在进入正题我把这套代码里最关键的几个知识点拆开揉碎来讲。这一部分也是我实际帮人调试代码时最容易出问题的地方。2.1 kmeans函数的核心参数MATLAB的kmeans函数是Statistics and Machine Learning Toolbox自带的基本命令格式是[idx, C, sumd, D] kmeans(X, k, Param1, Value1, Param2, Value2);一次调用下来你大概能拿到四个输出idx是每个样本点的类别标签C是最终的聚类中心坐标矩阵sumd是每个类内样本点到质心的距离之和D是每个样本点到每个质心的距离矩阵。但真正影响聚类效果的不是这些输出而是输入时的参数设置。我建议重点关注这几个距离度量方式也就是Distance参数。默认是sqeuclidean也就是平方欧氏距离这是绝大多数场景的首选。如果你数据点之间的相关性比较强可以考虑correlation如果是分类变量为主hamming更合适。但说句实在话日常用平方欧氏距离就够了换其它度量方式之前先要搞清楚自己数据的内在特点否则就是花式折腾。迭代次数上限对应MaxIter默认是100。大多数情况100次足够收敛但如果你发现输出告警说算法没收敛可以把这个值调到500或1000。重复运行次数对应Replicates。这个是新手最容易忽略的参数。kmeans的初始质心是随机选的所以你每次运行结果可能都不一样。设置Replicates为10或20意思是让算法从不同初始质心出发跑10遍或20遍最终返回轮廓最优的那一次结果。这能极大提升稳定性。空类处理方式对应EmptyAction。默认是singleton意思是如果某个类在迭代过程中变成空的了MATLAB会随机找一个远离所有质心的点作为新质心。2.2 数据标准化这一步做不做先给结论要做而且这套代码里已经写好了。很多人在网上抄一段kmeans代码拿自己的数据直接去聚类发现结果乱七八糟第一反应是代码写错了其实八成是因为没做数据标准化。kmeans的核心是距离计算而距离计算对量纲极其敏感。举个例子假设你的数据有两个维度一个是身高数值范围150到190一个是月收入数值范围3000到50000。计算距离时身高的差异会被收入的差异完全淹没聚类结果实际上只由收入这一个维度决定这显然不是你想要的效果。解决办法就是z-score标准化也叫零均值标准化MATLAB里一行代码解决data_std zscore(data);这样每个维度都会被处理成均值为0、标准差为1的分布。这步操作并不是kmeans算法的一部分但在实际应用中它几乎是必须的。你可以对标准化前后的聚类结果做一个对比会发现差异非常大。2.3 确定K值的两个经典方法这里我必须多讲几句因为K值的确定是kmeans聚类里最核心的坑。kmeans的一个前提是你要告诉它“分成几类”但这个K值在现实问题中往往是未知的。解决办法主要有两个肘部法则和轮廓系数。肘部法则的操作逻辑是分别尝试K2到K10记录每个K值对应的总类内距离之和sumd然后画一条折线。随着K增大sumd一定会下降因为类越多每个类内部越紧凑。但下降的幅度会越来越小图形上会出现一个明显的“肘部”这个“肘部”对应的K值就是比较合理的聚类数。为了让你一眼看到肘部代码里我还画了sumd随K变化的曲线图。轮廓系数是另一个角度它衡量的是每个样本点被分到当前类的合理程度取值在-1到1之间。越接近1说明样本点离自己所在的类近、离其它类远聚类效果越好。代码里计算了每个K值对应的平均轮廓系数最后帮你把最优K打印出来。这两种方法我建议配合使用肘部法则看趋势轮廓系数看绝对数值。当两者给出的K值一致时你就放心地用那个K值。3. 实操过程与核心环节实现这一部分直接上干货。我把主脚本的完整代码贴在下面然后逐段讲清楚每一块是在干什么。3.1 主脚本完整代码%% 清空环境 clear; clc; close all; %% 1. 读取数据并标准化 % 如果数据文件是csv格式第一行是列名从第二行开始是数据 data readmatrix(dataset.csv); % 去掉可能存在的缺失值行 data(any(isnan(data), 2), :) []; % 取出特征矩阵如果最后一列是真实标签可以单独存放 % 这里假设数据集最后一列是label如果只做聚类分析可以注释掉下行 label_true data(:, end); X data(:, 1:end-1); % 标准化 X_std zscore(X); %% 2. 使用肘部法则确定最优K值 K_range 2:10; sumd_all zeros(length(K_range), 1); for i 1:length(K_range) k K_range(i); [~, ~, sumd] kmeans(X_std, k, MaxIter, 500, Replicates, 10); sumd_all(i) sum(sumd); end % 绘制肘部图 figure; plot(K_range, sumd_all, bo-, LineWidth, 1.5, MarkerSize, 6); xlabel(聚类数 K); ylabel(总类内距离 (sumd)); title(肘部法则确定最优K值); grid on; %% 3. 轮廓系数确定最优K值 sil_val zeros(length(K_range), 1); for i 1:length(K_range) k K_range(i); idx_tmp kmeans(X_std, k, MaxIter, 500, Replicates, 10); sil_val(i) mean(silhouette(X_std, idx_tmp)); end % 找出轮廓系数最大的K值 [~, best_k_idx] max(sil_val); best_k K_range(best_k_idx); fprintf(轮廓系数最优的K值为%d\n, best_k); % 绘制轮廓系数曲线 figure; plot(K_range, sil_val, ro-, LineWidth, 1.5, MarkerSize, 6); xlabel(聚类数 K); ylabel(平均轮廓系数); title(轮廓系数确定最优K值); grid on; %% 4. 用最优K值执行最终聚类 k_final best_k; [idx, C, sumd, D] kmeans(X_std, k_final, MaxIter, 500, Replicates, 20); %% 5. 可视化聚类结果 % 如果特征维度大于2可以使用前两个主成分降维后可视化 % 这里直接提供两种可视化方式 % 5.1 如果特征是2维或3维直接散点图 if size(X_std, 2) 2 figure; gscatter(X_std(:,1), X_std(:,2), idx, rgbmc, o, 6); hold on; plot(C(:,1), C(:,2), kx, MarkerSize, 12, LineWidth, 2); legend(聚类1,聚类2,聚类3,聚类中心); xlabel(特征1); ylabel(特征2); title(kmeans聚类结果可视化); grid on; elseif size(X_std, 2) 3 figure; scatter3(X_std(:,1), X_std(:,2), X_std(:,3), 20, idx, filled); hold on; plot3(C(:,1), C(:,2), C(:,3), kp, MarkerSize, 15, MarkerFaceColor, y); xlabel(特征1); ylabel(特征2); zlabel(特征3); title(kmeans聚类结果可视化 (三维)); grid on; else % 高维数据使用前两个主成分可视化 [coeff, score, latent] pca(X_std); figure; gscatter(score(:,1), score(:,2), idx, rgbmc, o, 6); hold on; C_pca C * coeff(:, 1:2); plot(C_pca(:,1), C_pca(:,2), kx, MarkerSize, 12, LineWidth, 2); xlabel(主成分1); ylabel(主成分2); title(kmeans聚类结果可视化 (PCA降维)); grid on; end %% 6. 输出聚类中心原始尺度还原 % 由于之前做了标准化这里把聚类中心还原回原始数据尺度 C_original C .* std(X, 0, 1) mean(X, 1); disp(最终聚类中心原始尺度); disp(C_original); % 统计每个类的样本数量 counts histcounts(idx, k_final); for i 1:k_final fprintf(第%d类样本数%d\n, i, counts(i)); end3.2 数据集怎么准备和替换标题里说“数据齐全”现在我来详细说明这个数据集是什么结构。dataset.csv文件是一个标准的表格格式第一行是列名从第二行开始是数据。这套代码配套的数据集有两份可以按需使用一份是经典的鸢尾花数据集150个样本、4个特征维度3种花。另一份是用户行为日志数据集包含访问频次、停留时长、页面深度等维度。之所以准备两份是为了让你在验证代码流程时用鸢尾花数据在贴近实际场景时用行为数据两条路都给你铺好。如果你要换成自己的数据需要注意数据必须是数值型的。如果你的数据里有“男/女”“高/中/低”这种文本类型先做数值映射比如男0、女1。数据不能有缺失值。代码里我写了缺失值剔除语句但如果缺失值太多剔除后数据量不够聚类结果就会很虚。建议提前对缺失值做填充。每一列代表一个特征维度每一行代表一个样本。如果你拿到的数据是转置的用data data;转置回来。3.3 运行结果怎么看如果一切顺利你会看到两个图窗弹出来一个是肘部法则的折线图一个是轮廓系数曲线图然后命令行窗口会打印最优K值。接下来程序会自动用最优K值执行最终聚类弹出可视化结果图。可视化图里的每个不同颜色代表一个类黑色的叉号或者五角星是聚类中心。这时候你需要问自己的问题是这些类分得开吗如果不同类别之间有明显的重叠区域或者某个类特别大、某个类特别小说明聚类结构不合理需要回过去检查数据预处理和K值选择。还有一个细节程序里输出了聚类中心在原始尺度下的数值。这个设计是为了方便你下一步做业务解读。比如你做用户分群得到三个类的中心点每个中心点都包含各维度的均值你就能看出来第一类是高频高停留的“核心用户”第二类是低频低停留的“流流失用户”等等。4. 常见问题与排查技巧实录这套代码我前前后后帮几十个人调试过下面这几个问题出现的频率最高。我把它们整理成速查表再补充几句排查思路。现象可能原因解决方法报错Undefined function kmeans未安装Statistics and Machine Learning Toolbox在MATLAB菜单栏的“附加功能”里安装该工具箱标准化后的数据存在NaN原数据含有缺失值或文本值先检查并处理缺失值再做zscore聚类结果每次运行都不一样初始质心随机导致将Replicates设为10或20增加重复次数所有样本被分到同一个类数据标准化未做或特征量纲差异大检查数据标准化步骤是否正常执行某个类只包含一个样本点离群点干扰考虑剔除离群点或调整距离度量方式肘部法则曲线没有明显拐点数据本身没有明显的类结构可能需要更多特征或换用层次聚类验证4.1 聚类不稳定的根因聚类结果不稳定这是几乎每个人都会碰到的问题。原因在于kmeans的初始质心是随机选的不同的初始质心可能收敛到不同的局部最优解。默认情况下MATLAB只跑一次所以结果就飘忽不定。我的建议是把Replicates参数从默认的1改到10以上。这里要注意一个使用细节Replicates设置得大运行时间会线性增长。如果数据量在几万行以内10次重复基本可以接受如果数据量到了几十万行建议先用肘部法则在较小的Replicates下粗跑一下确定K然后再用较大的Replicates跑最终结果。另一个解决不稳定问题的办法是使用Start参数自己提供一组初始质心比如用kmeans策略或者从数据集中随机抽取几个点作为初始质心。不过对大多数场景Replicates10已经足够了。4.2 类别标签顺序错乱的问题m这个坑在计算聚类准确率时尤其常用。假设你有真实标签聚类结果也算好了一对比发现准确率只有30%别急着说算法不行。kmeans返回的标签是1到K的数字但这些数字是“分完之后顺手编号的”它本身没有语义含义。第一次运行可能把第一类命名为1第二次运行完全可能把第一类命名为3。如果你要做聚类准确率评估需要先把聚类标签和真实标签做映射对齐。最简单的做法是用匈牙利算法做两个标签集合之间的最优匹配MATLAB里没有内置这个函数但网上有很多轻量级实现你也可以用confusionchart先看一眼大致对应关系再手动调整。4.3 轮廓系数为负值说明什么轮廓系数范围是-1到1。如果你算出来的平均轮廓系数接近0甚至是负的说明样本点距离其它类的质心反而比距离自己类的质心近也就是聚类结构很可能是混淆的。这时候我通常建议先去检查数据本身。有可能你的数据在特征空间里本来就是连续分布的强行用kmeans分K类是没有意义的。这时候有两个方向一是检查特征选择去掉那些噪音大、和类别区分无关的维度二是换一种聚类方法比如基于密度的DBSCAN或者层次聚类看看能不能发现不同的结构。4.4 大规模数据跑不动怎么办这套代码的主体流程用的是全量数据矩阵当数据量超过几十万行、特征维度几十维时内存消耗和运行时间都会明显上升。处理办法先用datasample(X_std, 50000, Replace, false)随机抽样跑一遍确定合理的K值范围。然后使用MATLAB的kmeans在完整数据上设置较高的Replicates跑最终结果。如果仍然太慢可以把MaxIter调小一点比如100配合Display,final查看收敛情况。实际操起来抽样-定K-全量跑这套流程百万级行数据也能在合理时间内出结果。5. 对这套代码的扩展思考最后聊点我个人做这个项目的思考。这套代码本身是个完整的闭环但它恰恰是整个聚类分析流程里最“轻”的部分。真正让聚类分析产生价值的是聚类结果能不能指导下一步动作。比如你做电商用户分群跑完kmeans得到三类用户接下来你要做的是给每个类打业务标签分析各类用户的购买偏好然后针对性地制定运营策略。这时候这套MATLAB代码给你的是一张“地图”而怎么用这张“地图”找到金矿还得靠专业判断。从我个人的实操经验来说聚类分析项目最怕的不是不会写代码而是拿到结果之后不知道怎么解释。所以在写这套代码时我格外注重结果输出的可读性和可视化呈现希望你跑完一遍不但能看到图还能从数据里读出业务含义。另外如果你想把kmeans的思路迁移到更大的工程框架里去MATLAB本身还提供了其它一些工具箱比如模糊C均值聚类fcm函数、高斯混合模型gmdistribution.fit它们和kmeans的思路一脉相承但各有各的适用场景。学会了kmeans再去看这些方法会轻松很多。整体上这套代码就是你的启动器。先跑通它感受一下完整的聚类分析流程的节奏遇到问题对照我的排查记录去定位跑通之后尝试换成你自己的数据集用肘部法则和轮廓系数去探索数据里的潜在结构。对于刚接触聚类分析的人来说这就是一条快速上手的正路。本文还有配套的精品资源点击获取