MATLAB 2021a聚类分析:kmeans聚类点输出与收敛图绘制
2026/9/14 14:02:45 网站建设 项目流程

简介:面向机器学习与数据挖掘入门者的KMeans聚类分析MATLAB仿真资源,基于MATLAB 2021a实现,重点演示如何对数据进行聚类、输出聚类点并绘制算法收敛图,适合需要直观理解KMeans迭代过程的学生、科研人员或竞赛爱好者。资源共4个文件,压缩包仅27KB,其中m文件为核心算法源码,txt文件提供示例数据,docx文档包含项目介绍与运行说明,便于边读边练。KMeans实现覆盖初始化质心、距离分配与质心更新等关键步骤,并借助可视化呈现质心移动轨迹与收敛趋势,同时附带fpga与matlab相关文本,拓展了硬件加速聚类的思考方向。运行后可获得清晰的聚类散点图和收敛曲线,帮助理解不同迭代次数对结果的影响。已有755人学习,这份小而精的资料能帮助初学者快速跑通从数据读取、聚类计算到结果展示的完整流程,是理解经典聚类算法的实用入门素材。

1. 聚类分析的入口:用 kmeans 在 MATLAB 2021a 中定位数据簇

聚类分析在 MATLAB 2021a 里的落地形态,通常就是一行kmeans(X,k),但要让输出的聚类点和聚类收敛图真正可信,得先弄清楚迭代过程中算法到底在做什么。kmeans 把无标签样本划分成 k 个互不相交的簇,使总体簇内平方和(SSE)尽量小,收敛图就是 SSE 随迭代次数变化的下降曲线。它既能证明这个聚类分析任务的迭代确实收住了,也能在 K 值选取不当、初始化不合理时直接暴露出病态曲线。对做数据分析、信号处理、图像像素分割的工程师来说,聚类分析的意义就是把看似无序的数据变成可解释的结构,而是否收敛、收敛到哪个目标值,直接决定这组结构能不能用。本文就用 MATLAB 2021a 的 kmeans 函数,从最小代码出发,覆盖聚类点输出、聚类收敛图绘制和参数诊断这几个关键环节。

2. K-means 迭代机制与 MATLAB 2021a 的收敛逻辑

2.1 目标函数与分配、更新两阶段循环

K-means 的核心优化目标是把样本划分进 k 个簇,最小化簇内平方和:

J = Σ(j=1..k) Σ(i∈Cj) || xi - μj ||²

其中 μj 是簇 Cj 的均值向量,即该簇质心。求解过程是交替迭代:分配阶段把每个样本归入距离最近的质心,更新阶段用簇内样本均值重算质心。每轮迭代后 J 单调下降,但由于目标函数非凸,最终会停在某个局部极小值,MATLAB 里的 kmeans 函数实现的正是这个标准 Lloyd 流程。

MATLAB 2021a 的 kmeans 默认最大迭代次数是 100,如果质心不再明显移动,或相对 SSE 变化低于默认容差 1e-4,迭代会提前终止。这两个触发条件都由 Options 结构中的 TolFun 和 TolX 控制。我一般会在调试阶段把收敛图需要的迭代日志打开,确认每条样本是不是真的进入了稳定分配,再决定要不要增大 MaxIter。

2.2 kmeans 函数输出与关键参数速查

[idx, C, sumd, D] = kmeans(X, k, Name, Value);
  • X 是 n×p 样本矩阵,n 个样本、p 维特征,类型为 double,不能含 NaN 或 Inf。
  • idx 是 n×1 簇标签向量,取值 1 到 k。
  • C 是 k×p 质心矩阵,每行对应一个簇中心。
  • sumd 是 1×k 向量,记录每个簇内的 SSE,总体 SSE 即 sum(sumd)。
  • D 是 n×k 距离矩阵,D(i,j) 表示样本 i 到质心 j 的最近距离,按指定距离度量计算。

其中 sumd 就是判断收敛和选择 K 值的直接依据。每次运行 kmeans 后,比较不同参数组合下的 sum(sumd),本质就是在比较不同聚类划分质量。

参数默认值作用
Distance'sqeuclidean'距离度量,默认欧氏距离平方
Start'plus'初始质心策略,k-means++
Replicates1随机初始化重复次数,取最小 SSE 结果
MaxIter100单次运行最大迭代次数
Optionsstatset控制 TolFun、TolX、Display 等
EmptyAction'singleton'空簇出现时的处理方式

2.3 收敛判定与 Display 迭代日志

很多人在 MATLAB 里做完 kmeans 只拿 idx 和 C,却不知道迭代到底收敛没有。常用做法是打开 Display 选项:

opts = statset('Display', 'iter', 'TolFun', 1e-6, 'TolX', 0); [idx, C, sumd] = kmeans(X, k, 'Options', opts, 'Replicates', 1);

运行后命令行会逐行打印迭代次数、阶段、参与计算的样本数和当前 SSE。最后一行会给出最佳距离总和。这里 TolFun 设为 1e-6 比默认更严格,适合需要精确收敛图的场景。TolX 设为 0 表示只依赖目标函数变化判定。如果显示日志里 SSE 最后几行不再变化,说明已经收敛;如果到达 MaxIter 时 SSE 仍在下降,就要提高 MaxIter。

3. 在 MATLAB 2021a 中输出聚类点:数据准备与可视化

3.1 构造测试数据与最小可复现调用

先用合成数据走通完整链路。生成三簇二维高斯样本,模拟聚类分析最常见的处理对象:

% 生成三类二维高斯样本,模拟真实聚类分析场景 rng(1); X = [randn(60,2)*0.6 + [2,2]; randn(60,2)*0.5 + [-2,-1]; randn(60,2)*0.7 + [0,3]]; k = 3; [idx, C, sumd] = kmeans(X, k, 'Replicates', 5); totalSSE = sum(sumd); fprintf('总体 SSE = %.4f\n', totalSSE);

这段代码里 rng(1) 固定随机数种子,保证每次运行结果一致。randn 生成高斯分布样本,分别向右上、左下、正上方偏移,形成三个可分离的簇。'Replicates' 设为 5 表示用 5 组不同随机初始质心分别运行,最后返回 SSE 最小的一次结果。这样能明显降低局部极小值带来的抖动,是中间章节实际项目里最常用的防护手段。

3.2 多维特征标准化:zscore 与缺失值清理

真实数据往往各维度量纲不同,比如年龄和收入混在一起,直接做 kmeans 会由量纲大的特征主导距离,收敛图会好看但聚类结果没有业务意义。

% 标准化到零均值、单位标准差 X = zscore(X); % 若存在 NaN 行,删除后再聚类 X(any(isnan(X), 2), :) = [];

标准化对 kmeans 并不是强制步骤,但几乎总是推荐。zscore 等价于对每列做 (x - mean) ./ std。如果特征分布偏斜严重,也可以改用 min-max 归一化。对图像分割这类像素值本身在同一量纲的场景,标准化反而可能破坏原始对比度,这时跳过这一步。

3.3 用散点图绘制聚类点与质心

二维数据聚类后直接用 gscatter 着色,质心用五角星叠加:

figure; gscatter(X(:,1), X(:,2), idx, 'brk', '.x+', 8); hold on; plot(C(:,1), C(:,2), 'kp', 'MarkerSize', 14, 'MarkerFaceColor', 'm'); legend('簇 1', '簇 2', '簇 3', '质心', 'Location', 'best'); grid on; title('kmeans 聚类点与质心(MATLAB 2021a)');

gscatter 第一个参数是 x 坐标列,第二个是 y 坐标列,第三个是分组变量 idx。'brk' 指定三个簇的颜色(蓝、红、黑),'.x+' 指定每个簇的标记符号。这里数据是二维,所以直接用原始特征坐标绘制。如果数据维度超过三维,常见做法是先做主成分分析(PCA)降到两维,再用同样代码可视化,聚类点之间的空间关系仍然可用。

数据维度可视化方式
1 维scatter(X, ones(size(X)))
2 维gscatter(X(:,1), X(:,2), idx)
3 维scatter3(X(:,1), X(:,2), X(:,3), 20, idx)
高于 3 维PCA 降维到 2 维后再 gscatter

4. 聚类收敛图:迭代曲线绘制与典型异常诊断

4.1 手动迭代记录 SSE 轨迹,绘制收敛图

MATLAB 的 kmeans 函数本身不返回逐次迭代的 SSE 向量,所以要输出完整的聚类收敛图,常用做法是把 Lloyd 迭代手动实现一遍,每次记录 SSE:

% 以第 3 章生成的 X、k=3 为基础,手动实现 kmeans 迭代 rng(1); centroids = X(randperm(size(X,1), k), :); % 随机挑 k 个样本作初始质心 maxIters = 50; sseLog = zeros(1, maxIters); for iter = 1:maxIters % 分配阶段:计算每个样本到全部质心的欧氏距离 dists = pdist2(X, centroids, 'euclidean'); [~, idx] = min(dists, [], 2); % 更新阶段:用每个簇的均值作为新质心 for j = 1:k members = X(idx == j, :); if ~isempty(members) centroids(j, :) = mean(members, 1); end end % 更新后重新计算 SSE dists2 = pdist2(X, centroids, 'euclidean').^2; [minD, ~] = min(dists2, [], 2); sseLog(iter) = sum(minD); end figure; plot(1:maxIters, sseLog, 'b-o', 'LineWidth', 1.5); grid on; xlabel('迭代次数'); ylabel('簇内平方和 SSE'); title('kmeans 聚类收敛图(MATLAB 2021a 仿真)');

这段代码的逻辑要点在分配和更新两个阶段。pdist2 计算距离矩阵,min 取每行最小值得到最近质心;更新质心时用 mean 取簇内样本均值。注意 SSE 计算用的是欧氏距离平方,因为聚类目标本身是平方误差,取平方值才能和内置 kmeans 的 sumd 对齐。代码里加了对空簇的判断,避免某个簇完全没有样本时 mean 计算出 NaN。实际仿真时,我会把这段手动迭代封装成一个函数,输入 X 和 k,输出 sseLog 和最终质心。

4.2 用内置 Options 输出标准迭代日志做交叉对比

手写迭代能拿到完整曲线,但和官方实现的质心初始化策略不完全一致。交叉验证办法是打开 MATLAB 内置迭代日志:

opts = statset('Display', 'iter', 'MaxIter', 50); [idx, C, sumd] = kmeans(X, k, 'Options', opts, 'Replicates', 1);

命令行会输出每轮迭代的 SSE 变化,最后给出 best total distance。这个值应该和手动迭代的 sseLog 末尾一致。如果两个结果差异明显,优先以内置 kmeans 为准,检查手写代码里的距离度量和初始化方式。交叉验证是聚类分析仿真里最容易遗漏的一步,却最能在问题初期暴露实现错误。

4.3 收敛图典型病态与参数对照

收敛图形态可能原因调整方式
曲线在第 MaxIter 次仍未走平MaxIter 太小增大到 300 或 500
多次运行曲线末尾 SSE 不同局部极小值增大 Replicates 到 10 以上
曲线出现向上跳动空簇引发质心重置检查 EmptyAction 设置
曲线下降缓慢但不停留在高位距离度量选择不当标准化数据或换 'cityblock'
所有簇几乎重合K 值偏大结合 4.4 节肘部法则降 K

4.4 用肘部法则帮助确定 K 值

聚类收敛图只证明算法在某个 K 值下达到稳定,不能证明 K 选对了。肘部法则通过对比不同 K 值下的总体 SSE 来辅助选择:

Klist = 1:8; sseK = zeros(size(Klist)); for k = Klist [~, ~, sumd] = kmeans(X, k, 'Replicates', 10); sseK(k) = sum(sumd); end figure; plot(Klist, sseK, 'ro-', 'LineWidth', 1.5); grid on; xlabel('簇数 K'); ylabel('总体 SSE'); title('肘部法则选择 K 值');

当 K 从 1 逐渐增大,SSE 会持续下降,但下降幅度会在某个 K 处明显变缓,曲线的拐点就是所谓的肘部。对第 3 章的合成数据,拐点应该在 K=3 附近。这里 Replicates 设置到 10,是避免个别初始化差导致 SSE 偏高,让曲线更平滑。

5. 验证聚类结果的进阶技巧:evalclusters 与可复现收敛图

5.1 用 evalclusters 批量比较 K 值

肘部法则依赖人工看图,自动化的做法是用 MATLAB 自带的 evalclusters:

eva = evalclusters(X, 'kmeans', 'silhouette', 'KList', 1:8); figure; plot(eva); xlabel('簇数 K'); ylabel('轮廓平均值');

evalclusters 会按 KList 逐个运行 kmeans,并计算轮廓系数、Calinski-Harabasz 或 GAP 统计量。轮廓平均值越接近 1,说明簇内紧凑、簇间分离越明显。判读原则是选轮廓平均值最高或明显尖峰处的 K。'silhouette' 计算量比肘部法则大,数据量到十万条样本时建议先抽样再评估。

5.2 用固定 Start 生成可复现的聚类收敛图

验证类场景和论文仿真里,收敛图必须能复现。kmeans 默认的随机初始化每次结果会有差异,解决办法是手动固定初始质心:

rng(0); initC = X(randperm(size(X,1), k), :); % 固定取前 k 个样本当质心 [idxFinal, CFinal] = kmeans(X, k, 'Start', initC, 'MaxIter', 300);

这样即使换一台机器重跑,只要 X 不变,聚类点和收敛图就完全一致。实际项目中,我还会把标准化参数 meanX、stdX 一起保存,对新增样本做同样的标准化后再预测归属。这样处理之后,K 值选择、聚类标签可视化、收敛图输出和验证后发布之间,形成一条可全量重跑的链路,这也是从仿真脚本升级为可交付分析代码的关键一步。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询