ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kmeans聚类算法Matlab代码实战:从原理到调参避坑指南

Kmeans聚类算法Matlab代码实战:从原理到调参避坑指南 简介这份资源是一份面向Matlab初学者与数据分析入门者的K-means聚类算法实现文档帮助读者理解无监督学习中最经典的聚类方法并掌握其在Matlab环境下的落地方式。文档围绕算法原理、基本步骤、代码实现与结果可视化展开包含可直接运行的示例代码演示如何调用内置kmeans函数完成数据分簇、获取簇索引与质心坐标并用scatter绘制带颜色区分的聚类结果图。同时梳理了K-means需要预先指定K值、对异常值与初始化敏感等局限性并延伸介绍K-means、Bisecting K-means、Kernel K-means等改进思路便于读者建立从原理到实践的完整认知。资源包共1个docx文件大小约15KB轻量易读适合课堂学习、课程作业或自学参考。目前已有441人学习可作为聚类算法入门与Matlab实操的参考材料。1. 从一份 kmeans 聚类算法 matlab 代码说起为什么你跑出来的分类总是不对很多人第一次拿到 kmeans 聚类算法 matlab 代码是在做数据分群、图像分割或者需求分类这类任务。代码跑通了图也画出来了但结果要么把明显该分开的两拨数据揉成一团要么每次运行分类结果都在跳。问题往往不在算法本身而在于 kmeans 对初始质心、距离度量、K 值选择极度敏感而大多数流传的代码把这些参数写死了。这份代码真正要解决的是给定一批没有标签的样本怎么用 matlab 把它们自动分成若干组并且让分组结果稳定、可解释、能复现。它适合做数据分析、模式识别、图像处理、市场分群的工程师和学生前提是你得知道哪些参数必须自己调哪些坑必须提前避开。下面按「先立住原理、再动手复现、最后排错」的顺序拆开讲。2. kmeans 在 matlab 里到底怎么算从目标函数到迭代终止2.1 目标函数与两步交替为什么它一定会收敛但未必收敛到最优kmeans 的核心目标函数是最小化每个样本到其所属簇中心的距离平方和写成公式就是 J Σ Σ ||x - μ||²。matlab 里无论你调 kmeans 函数还是自己写循环底层都是两步交替第一步把每个点分配给最近的质心第二步把每个簇的质心更新为簇内均值。这两步每轮都会让 J 单调不增所以算法一定会在有限步内收敛。但收敛点可能是局部最优取决于初始质心怎么选。常见做法是 kmeans 初始化matlab 的 kmeans 函数默认就是 Start,plus它让初始质心彼此尽量远比纯随机稳得多。如果你手头的代码用的是 randperm 随机选点那结果跳动就正常了。2.2 距离度量与数据标准化欧氏距离不是万能的matlab 的 kmeans 默认用 sqeuclidean 平方欧氏距离。如果你的特征量纲差得远比如一个特征是收入几千到几万另一个是年龄十几到几十欧氏距离会被大数值特征主导聚类结果基本只反映收入。所以动手前先做 z-score 标准化用 zscore 函数一行搞定。如果数据是稀疏的或者特征维度很高可以考虑 cosine 距离但 matlab 的 kmeans 只支持 sqeuclidean、cityblock、cosine 等几种需要在 Distance 参数里指定。注意 cosine 距离下质心更新方式不同matlab 内部会处理但你要知道结果解释起来和欧氏距离不一样。2.3 用 matlab 内置 kmeans 跑通最小示例先给一段可以直接抄的代码用 iris 数据集演示完整流程。这段代码覆盖了标准化、K 值选择、聚类、可视化四个环节。% 加载数据iris 自带 150 个样本4 个特征 load fisheriris X meas; % 150x4 矩阵 % 标准化消除量纲影响这是最容易被跳过的一步 X_norm zscore(X); % 用肘部法辅助选 K计算 K1 到 10 的簇内平方和 rng(42); % 固定随机种子保证结果可复现 maxK 10; wss zeros(maxK, 1); for k 1:maxK [~, ~, sumd] kmeans(X_norm, k, Replicates, 5); wss(k) sum(sumd); end % 画肘部图找拐点 figure; plot(1:maxK, wss, -o); xlabel(簇数 K); ylabel(簇内平方和); title(肘部法选择 K); % 假设从肘部图看出 K3 合适正式聚类 K 3; [idx, C, sumd] kmeans(X_norm, K, ... Distance, sqeuclidean, ... Start, plus, ... Replicates, 10, ... MaxIter, 300, ... Display, final); % 可视化取前两个主成分投影 [coeff, score] pca(X_norm); figure; gscatter(score(:,1), score(:,2), idx); hold on; % 把质心也投影到主成分空间 C_pca (C - mean(X)) ./ std(X) * coeff; plot(C_pca(:,1), C_pca(:,2), kx, MarkerSize, 12, LineWidth, 2); title(sprintf(kmeans 聚类结果K%d, K));逻辑说明先 zscore 标准化再用循环算不同 K 的簇内平方和画肘部图最后用 kmeans 正式聚类。参数方面Replicates,10 表示用 10 次不同初始化取最优能显著降低陷入局部最优的概率Start,plus 启用 kmeansMaxIter,300 是单次迭代上限一般 100 到 500 够用。sumd 是每个簇内点到质心的距离和用来算 WSS。注意 rng(42) 固定种子否则每次跑出来的 idx 可能不同这在调试阶段很关键。2.4 自己写 kmeans 循环理解每一步在干什么如果你拿到的代码是手写版本或者你想改距离度量可以照着下面这个骨架改。这段代码把分配和更新两步显式写出来方便你插入自定义逻辑。function [idx, C] my_kmeans(X, K, maxIter) % X: n x d 样本矩阵K: 簇数maxIter: 最大迭代次数 [n, d] size(X); % kmeans 初始化第一个质心随机选后续按距离概率选 C zeros(K, d); C(1,:) X(randi(n), :); for k 2:K D2 min(pdist2(X, C(1:k-1,:)).^2, [], 2); P D2 / sum(D2); C(k,:) X(find(rand cumsum(P), 1), :); end idx zeros(n, 1); for iter 1:maxIter % 分配步每个点到最近质心 D pdist2(X, C); [~, new_idx] min(D, [], 2); % 提前终止分配不再变化 if iter 1 isequal(new_idx, idx) break; end idx new_idx; % 更新步质心取簇内均值 for k 1:K if any(idx k) C(k,:) mean(X(idx k, :), 1); else % 空簇处理重新随机选一个点当质心 C(k,:) X(randi(n), :); end end end end逻辑说明初始化用 kmeans 的概率选点比纯随机好。分配步用 pdist2 算距离矩阵更新步用 mean 算均值。空簇处理是手写代码最容易漏的地方一旦某个簇没分到点mean 会返回 NaN后面全崩。参数上 maxIter 一般设 100 到 300实际通常十几轮就收敛。这段代码可以直接替换 matlab 内置函数方便你加约束比如必须让某个簇至少包含多少样本。3. K 值怎么定、初始质心怎么选三个可操作的判断方法3.1 肘部法加轮廓系数两个指标交叉验证肘部法看 WSS 随 K 增大的下降速度拐点就是候选 K。但拐点有时不明显这时候补一个轮廓系数。轮廓系数衡量每个点跟自己簇的紧密度和跟最近其他簇的分离度取值 -1 到 1越大越好。matlab 没有内置轮廓系数函数但可以自己算或者用 evalclusters 函数。% 用 evalclusters 自动评估 K rng(42); eva evalclusters(X_norm, kmeans, silhouette, KList, 2:8); figure; plot(eva); bestK eva.OptimalK; fprintf(轮廓系数推荐 K %d\n, bestK);evalclusters 支持 silhouette、CalinskiHarabasz、DaviesBouldin 三种准则。我一般三个都跑一遍如果两个以上推荐同一个 K那就比较可信。注意 evalclusters 内部会多次调用 kmeans数据量大时比较慢可以先抽样再评估。3.2 初始质心为什么 Replicates 比 Start 更值得调matlab 的 kmeans 里Start 控制初始化方式Replicates 控制重复次数。很多人只改 Start 不改 Replicates结果还是不稳。实际上 Replicates 才是保底手段每次用不同随机初始化解最后返回 WSS 最小的那个。经验值是 Replicates 设 5 到 20数据越复杂设越大。代价是计算时间线性增长。如果数据超过十万行可以先用 Start,plus 加 Replicates3再根据结果决定要不要加。3.3 用 DBSCAN 做对照什么时候不该用 kmeans热搜里 dbscan 聚类算法 出现频率很高因为 kmeans 有两个硬伤一是必须指定 K二是只能找凸形簇。如果你的数据簇形状不规则或者有噪声点kmeans 会把噪声硬塞进某个簇结果很难看。这时候用 matlab 的 dbscan 函数做对照它能自动发现簇数并标记噪声。常见做法是先用 dbscan 看数据大概分几团再用 kmeans 做精细划分。dbscan 的关键参数是邻域半径 epsilon 和最小点数 MinPts可以用 kdist 图辅助选 epsilon。% dbscan 对照先看数据自然分几簇 kdist sort(pdist2(X_norm, X_norm), 2); kdist kdist(:, 5); % 看第 5 近邻距离 figure; plot(sort(kdist, descend)); % 从拐点选 epsilon假设 0.8 epsilon 0.8; idx_db dbscan(X_norm, epsilon, 5); fprintf(dbscan 发现 %d 个簇%d 个噪声点\n, ... max(idx_db), sum(idx_db -1));这段代码先画第 5 近邻距离降序图拐点处对应的距离就是 epsilon 的参考值。dbscan 的结果如果噪声点占比超过 20%说明 epsilon 太小如果只有一个大簇说明 epsilon 太大。用 dbscan 的结果反过来指导 kmeans 的 K 值比盲试靠谱。4. 一份 kmeans 聚类算法 matlab 代码常见的翻车点排查4.1 每次运行结果都不一样现象同一份数据同样的 K跑两次 idx 完全不同。原因没有固定随机种子且 Replicates 设得太小或没设。解决在调用 kmeans 前加 rng(固定值)并把 Replicates 设到 10 以上。如果还跳检查数据里有没有重复点或极端离群值它们会让初始质心选择不稳定。4.2 某个簇是空的或者质心是 NaN现象输出的 C 里有一行全是 NaN或者 idx 里某个标签从来没出现。原因初始化时某个质心离所有点都远分配步没点归它更新步 mean 空数组返回 NaN。解决内置 kmeans 会自动处理空簇但手写代码必须加空簇判断重新随机选一个点当质心。另外检查 K 是不是设得比实际簇数大太多。4.3 聚类结果和肉眼观察完全不符现象二维图上明显两团K2 却分出一条斜线把两团各切一半。原因没做标准化某个特征量纲太大主导了距离或者用了 cosine 距离但数据不适合。解决先 zscore 标准化再用 Distance,sqeuclidean 跑一遍对比。如果还是不对用 pca 降到二维画图看是不是高维空间里距离定义和低维视觉不一致。4.4 数据量大时内存爆掉或跑得极慢现象十万行以上数据kmeans 卡死或者报 out of memory。原因pdist2 会生成 n×K 的距离矩阵n 大时内存吃不消Replicates 又成倍放大计算量。解决用 matlab 的 tall array 或者分批处理先把 Replicates 降到 3MaxIter 降到 100。如果只是探索先随机抽样一万行跑通再上全量。4.5 中文注释乱码导致代码报错现象从网上下的 .m 文件打开后注释全是乱码甚至影响字符串解析。原因文件编码是 GBK而 matlab 2023 之后默认 UTF-8。解决用记事本或 VS Code 把文件另存为 UTF-8 编码或者在 matlab 里用 feature(DefaultCharacterSet,UTF-8) 临时切换。这个坑在 matlab 2023 的中文注释乱码 热搜里很常见提前处理省得调试半天。5. 把 kmeans 用进真实项目从图像分割到需求分类的调参习惯图像分割是 kmeans 在 matlab 里最直观的应用之一。把每个像素的 RGB 三通道当成三维样本聚成 K 类每类用质心颜色替换就得到色彩量化效果。这里有个技巧不要直接对原始 RGB 跑 kmeans先转到 Lab 颜色空间因为 Lab 的欧氏距离更接近人眼感知差异。matlab 里用 rgb2lab 转换再对 a、b 通道加权亮度通道可以降权这样分割出来的区域更符合视觉。% 图像分割Lab 空间 kmeans img imread(peppers.png); lab rgb2lab(img); % 把图像拉成 n x 3 样本a、b 通道权重加大 [n, m, ~] size(lab); X_img reshape(lab, n*m, 3); X_img(:,1) X_img(:,1) * 0.5; % 亮度降权 X_img zscore(X_img); K 4; [idx, C] kmeans(X_img, K, Replicates, 5, Start, plus); % 用质心颜色重建图像 C_orig C; C_orig(:,1) C_orig(:,1) / 0.5; % 还原亮度权重 seg reshape(C_orig(idx,:), n, m, 3); seg_rgb lab2rgb(seg); figure; imshow(seg_rgb);这段代码的关键在权重亮度通道乘 0.5 再标准化相当于降低它对距离的贡献让颜色差异主导分割。K 一般取 3 到 6太大就过分割。Replicates 设 5 足够因为图像像素多单次迭代已经比较稳。另一个常见场景是社区服务需求分类比如把居民诉求文本转成 TF-IDF 向量后用 kmeans 分群。这时候 K 的选择更依赖业务解释不能只看轮廓系数。我一般会跑 K3 到 8把每个簇的关键词导出来人工看选那个簇内主题最一致的 K。matlab 里用 fitctfidf 或者自己算词频矩阵都行但记得做 L2 归一化否则长文本会主导距离。调参习惯上我固定一套流程先 rng 固定种子再 zscore 标准化然后 evalclusters 跑三个准则取交集 K最后 Replicates10 正式跑。跑完必看三样东西WSS 肘部图、轮廓系数分布、每个簇的样本量和质心坐标。如果某个簇样本量不到总数 5%要么合并要么检查是不是离群点聚集。这套流程不保证每次都对但能挡住八成以上的翻车。最后说一个我踩过的坑有次对传感器数据聚类标准化之后忘了把质心还原到原始量纲直接把 C 当成物理量写进报告结果数值全错。后来养成习惯聚类完先把 C 反标准化再和业务方对齐。这个后悔药不好吃希望帮到你。本文还有配套的精品资源点击获取
返回列表