首页 / 资讯中心 / 文章详情

k-means聚类实验报告:MATLAB代码实现与避坑指南

k-means聚类实验报告:MATLAB代码实现与避坑指南 ★ FEATURED ARTICLE
简介这份实验报告面向学习数据挖掘与聚类分析的高校学生及算法入门者围绕k-means聚类算法的原理、流程与MATLAB实现展开帮助读者理解无监督划分方法并完成Iris数据集的聚类实践。资源包共1个doc文件约126KB内容涵盖实验目的、算法原理与流程图、k3与k4两种取值下的聚类效果分析、实验结论与心得体会并附有完整的MATLAB源代码便于对照复现与调试。报告重点讨论了初始类中心选择、数据输入顺序及类别数k对迭代次数和聚类结果的影响也指出算法对离群点敏感、难以处理非凸簇等局限并给出k值选取与初始中心优化的思路。目前已有2741人学习适合作为课程实验参考或聚类算法的入门练手材料。1. 一份能跑通的 k-means 实验报告到底值不值得下带过课程设计的人大概都遇到过这种场面数据集给了、算法原理也背了真到 MATLAB 里写循环聚类结果要么全挤成一坨要么每次跑出来的颜色分布都不一样报告里那句“聚类效果良好”写得心虚。这份《k-means 数据聚类实验报告MATLAB 详细代码》解决的正是这个断层——它不是只给结论的文档而是把 Iris 数据集、k-means 主程序、手写的 kmeans 子函数、k3 与 k4 的对比图、误差平方和准则、初始中心选取的讨论一并打包。适合两类人一是要交实验报告、需要一份能逐行读懂并改参数的学生二是想快速回顾划分式聚类实现细节、拿 MATLAB 做原型验证的从业者。下面按“原理怎么立住、代码怎么跑、坑在哪”拆开讲。2. 先立住原理k-means 的划分准则与收敛条件2.1 平方误差准则为什么是这套代码的目标函数k-means 的本质是找一个划分让簇内紧凑、簇间分离。这份报告采用的是最经典的平方误差准则目标函数写成对每个簇内点到簇中心的欧氏距离平方求和。用公式表达就是 E Σ_{i1}^{k} Σ_{p∈C_i} ||p − m_i||²其中 m_i 是第 i 个簇的均值中心。代码里所有“距离”计算最终都落到这个式子上理解这一点后面看sum((repmat(x(i,:),k,1)-nc).^2,2)就不会觉得是黑匣子。为什么选欧氏距离而不是曼哈顿距离Iris 的四个特征都是连续数值、量纲接近欧氏距离对球形簇的刻画最自然而且均值中心在欧氏度量下正好是使平方误差最小的点——这是 k-means 能用“求平均”来更新中心的数学前提。换成其他距离均值未必是最优中心更新公式就得改。报告里提到“也可以用其他距离度量”但代码没有展开实际动手时如果换距离mean那一步必须同步替换否则收敛性没有保证。收敛判据方面报告写的是“新的平均值不再改变则结束”。严格说这是中心不再移动的判据等价于划分不再变化。代码里用move标志位实现一轮扫描中没有任何点改变归属move保持 0循环退出。这个判据比“目标函数变化小于阈值”更硬好处是不会因为浮点误差提前停坏处是数据量大时可能多跑几轮。我在自己的原型里一般会加一个最大迭代次数兜底防止震荡。2.2 初始中心怎么选报告的做法与它的边界报告里初始中心取的是x(bn,:)、x(2*bn,:)、x(3*bn,:)其中bn round(n/k*rand)也就是在前 1/k 的数据范围内随机取一个起点再等间隔往后取。这个做法的意图在正文里说得很直白前 k 个数据差别较大能提高效率和准确率。它比纯随机抽 k 个点稳一些因为等间隔采样降低了抽到相邻近点的概率。但这里有个容易被忽略的边界bn是随机数如果bn恰好很小三个中心可能落在同一片密集区迭代次数会明显上升甚至陷入局部最优。报告自己也承认“初始类中心的选择对聚类准确度有较大影响”。所以这份代码适合用来观察“初值影响迭代次数”这个现象但不适合当作生产级初始化方案。真要稳常见做法是 k-means 或者多次随机重启取平方误差最小的那次报告没写但这是读代码时应该自己补上的一课。2.3 两段式循环先粗分再微调代码里的kmeans.m子函数有两段 while。第一段maxgn100做的是标准 Lloyd 迭代算距离、归簇、重算均值。第二段maxiter2做的是逐个点的“调整式”再判断用dadj nr./(nr1).*dist计算调整后距离只有更优才移动点并即时更新该簇中心。这个第二段其实是增量式更新能让结果对输入顺序不那么敏感但也意味着它不再是严格的批量 k-means收敛性分析要打折扣。读这段代码时不要被maxiter2迷惑它不是“只迭代两次就收敛”而是“最多做两轮微调”。实际聚类质量主要由第一段决定第二段是锦上添花。报告正文的算法流程写的是标准六步和代码的两段式并不完全一一对应这是文档与实现之间的一个缝隙后面避坑章节会专门说。3. 把代码跑起来数据组织、主程序与可视化3.1 数据怎么进 MATLABIris 的 150×4 矩阵报告附录把 Iris 数据直接硬编码成一个 150 行 4 列的矩阵x每行一个样本四列对应四个特征。这样做的优点是复制粘贴就能跑不依赖外部文件缺点是数据被归一化过数值大致落在 0 到 1 之间和原始 Iris 的厘米量纲不同如果拿这份矩阵去和别的实现对比数值对不上是正常的。如果你手上有ch7 iris.txt原文件更规范的做法是读文件而不是硬编码。常见做法是用load或readmatrix并确认分隔符和缺失值% 读取 Iris 数据集假设为制表符或空格分隔的纯数值文件 raw readmatrix(ch7 iris.txt); % 若含表头改用 readtable 后取数值列 x raw(:, 1:4); % 前四列为特征第五列若为标签则单独存 labels raw(:, 5); % 标签仅用于事后评估不参与聚类 [n, d] size(x);这里readmatrix对纯数值文件最省事遇到表头会返回 NaN 行需要检查。labels单独拿出来是为了后面算准确率k-means 本身是无监督的训练时绝不能把标签喂进去否则就是数据泄漏。硬编码矩阵和读文件两条路都行前者适合快速复现报告图后者适合换成自己的数据。3.2 主程序逐段拆k 值、初始中心、调用与绘图主程序开头k3;然后定义x接着算bn和nc再调用[cid,nr,centers] kmeans(x,k,nc)。cid是 1×n 的归属向量nr是每簇样本数centers是最终的 k×d 中心矩阵。这三个输出就是后续分析和绘图全部依赖的东西。绘图部分用了一个 150 次的 for 循环按cid(i)的值给每个点打红、蓝、绿星号。这段代码能跑但写法很啰嗦而且text(-4,-3.6,...)的坐标是写死的换数据集就会跑到图外面。更清爽的写法是按簇索引一次性画% 按簇批量绘图避免逐点 if-else colors {r*,b*,g*,k*}; figure; hold on; for c 1:k idx (cid c); plot(x(idx,1), x(idx,2), colors{c}, MarkerSize, 6); end plot(centers(:,1), centers(:,2), kx, MarkerSize, 12, LineWidth, 2); legend(簇1,簇2,簇3,中心); hold off;注意这里只画了前两个特征因为二维图能看。Iris 有四维前两维的可分性其实一般k3 时图上会有交叠这不是算法失败而是降维可视化的信息损失。报告里的效果图也是二维的看的时候要有这个预期。想更客观就补一个混淆矩阵或者轮廓系数别只凭图下结论。3.3 换 k 值和换初值两个必须亲手做的对照实验报告给了 k3 和 k4 两组结果结论是 k4 出现过度分割。这个对照很有价值但只跑一次说明不了初值敏感性。建议至少做两组实验固定 k3改rand的种子跑五次记录每次的迭代次数和最终平方误差再固定种子把 k 从 2 跑到 5看平方误差随 k 单调下降但边际收益递减的现象。% 初值敏感性对照固定 k换随机种子重复 k 3; for s 1:5 rng(s); % 固定种子保证可复现 bn round(n/k*rand); nc [x(bn,:); x(2*bn,:); x(3*bn,:)]; [cid, nr, centers] kmeans(x, k, nc); % 计算平方误差和 E 0; for c 1:k idx (cid c); E E sum(sum((x(idx,:) - centers(c,:)).^2)); end fprintf(seed%d, E%.4f, 各簇样本数%s\n, s, E, mat2str(nr)); end这段代码的关键是rng(s)没有它每次结果都不同对照就失去意义。E的计算直接对应第 2 章的目标函数可以拿来验证“初值不同、E 略有差异”这个结论。如果某次 E 明显偏高多半是初值撞到了坏点这正是报告里“初始中心特别重要”的实证。4. 避坑与排查这份代码最容易翻车的五个地方4.1 现象每次运行颜色分布都不一样报告没法复现原因bn round(n/k*rand)里的rand没有固定种子初始中心每次都在变。解决在调用前加rng(42)之类的固定种子并在报告里写明种子值。如果要求更稳把初始化换成 k-means 或多次重启取最优别依赖单次随机。4.2 现象k4 时某个簇只有一两个点图上一片稀疏原因Iris 本身只有三个真实类别强行 k4 必然把一个自然簇劈开或者产生离群小簇。这不是代码 bug是 k 值与数据结构不匹配。解决用肘部法或轮廓系数辅助选 k报告里把 k4 作为“过度分割”的反例讲清楚而不是当成失败案例藏起来。4.3 现象第二段微调循环几乎不生效move一直是 0原因第一段 100 轮 Lloyd 迭代后划分已经稳定第二段maxiter2的增量调整没有空间。这在干净数据上是正常的。解决不要为了看到“Some points were moved”而调大maxiter那只会增加运行时间如果确实想观察增量更新的作用把第一段maxgn调小到 5 左右再对比。4.4 现象换自己的数据后绘图点全挤在角落或跑出坐标轴原因绘图用了text(-4,-3.6,...)和固定的星号坐标逻辑坐标范围是照着归一化后的 Iris 写死的。解决去掉硬编码 text改用axis auto或根据min/max动态设范围绘图前先zscore标准化特征避免量纲大的列主导距离。4.5 现象距离计算报维度不匹配或结果全为 NaN原因repmat(x(i,:),k,1)-nc要求nc是 k×d如果手工改nc时少了一列或者读文件时把标签列混进特征维度就对不上。解决在kmeans函数入口加一句assert(size(nc,2)d)读数据后打印size(x)确认列数标签列务必剔除。5. 进阶用法把实验代码改成可评估的小工具报告给的是“能出图”的脚本离“能判断聚类好不好”还差一步。我一般会在跑完之后补三样东西平方误差随迭代次数的下降曲线、用真实标签算的聚类纯度、以及不同 k 下的肘部图。这三样不需要额外工具箱几十行就能写完却能把一份实验报告从“看起来对”变成“有据可查”。先看迭代曲线。把kmeans.m里每轮结束时的 E 存进一个数组主程序画出来能直观看到前几轮陡降、后面趋平收敛慢的那次往往就是初值不好。再看纯度对每个簇取该簇内出现最多的真实标签作为簇标签正确数除以总数就是纯度。Iris 三类的纯度在 k3 时通常能到 0.9 上下低于这个值就该怀疑初始化或标准化。最后是肘部图k 从 1 跑到 6画 E 对 k 的曲线拐点就是相对合理的 k。评估项计算方式看什么平方误差 E簇内点到中心距离平方和随迭代下降、随 k 下降聚类纯度各簇多数标签正确数 / nk3 时应接近 0.9肘部拐点E-k 曲线斜率突变处辅助确定 k各簇样本数nr输出是否出现极小簇有一个细节值得单独说报告里的数据是归一化过的如果你换成原始量纲的 Iris萼片长度约 4 到 8、花瓣宽度约 0.1 到 2.5欧氏距离会被大数值特征主导聚类结果会明显偏向萼片。所以无论用哪份数据进kmeans之前先做zscore标准化这一步在报告里没强调但它是复现别人结果时最容易翻车的地方。从那以后我每次拿聚类代码改数据都强制先打印各列均值和方差、再跑一次标准化前后的对照确认结果不是被量纲带偏的。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站