Matlab多分类混淆矩阵绘制全攻略:从原理到论文级出图

发布时间:2026/8/31 2:06:15
Matlab多分类混淆矩阵绘制全攻略:从原理到论文级出图 简介本资源面向计算机、电子信息工程及数学等专业的本科生聚焦多分类问题中混淆矩阵的可视化实现适用于课程设计、期末大作业或毕业设计阶段的算法验证与结果展示需求。压缩包共17个文件10个MATLAB脚本文件用于核心绘图与指标计算5个.mat数据文件含真实标签、预测结果及分类置信度等关键变量2个txt说明文档提供使用指引与类标映射整体仅51KB轻量易部署。资源已获52人学习下载内容结构清晰包含主运行脚本main.m、混淆矩阵生成模块ConfusionMatrices、精度/召回率分析脚本PrecisionRecall及PG_Curve绘图支持配套name_class.mat与num_in_class.mat确保多类别标签可读性与统计一致性。读者可直接运行复现标准混淆热力图并基于源码快速适配自定义分类器输出掌握从预测结果到评估可视化的完整技术链路。 咱们搞分类模型的人电脑里几乎都存着这么一份资源《基于Matlab实现多分类问题中混淆矩阵的画法源码数据.rar》。我当年第一次做多分类实验时也是从这类包里东拼西凑学起来的。这标题看着挺直白但真正用起来很多人卡在第一步明明训练好了模型预测结果也对但矩阵图就是画不出来或者画出来了却不知道怎么看、怎么用。这篇博文我就把这个资源包背后的完整链路拆开讲清楚从混淆矩阵的原理、源码逻辑到数据怎么组织、参数怎么改再到怎么把矩阵图变成论文里能直接用的高质量图片一次性帮你把这块短板补上。内容对刚接触Matlab分类任务的研究生、做算法对比的工程师以及所有被导师催着出图的人应该都有参考价值。1. 混淆矩阵在多分类任务中的地位1.1 为什么二分类那套评估方法不够用了做二分类的时候大家习惯看准确率、精确率、召回率、F1配合ROC曲线和AUC值基本能说清楚模型好坏。但一旦切到多分类场景比如手写数字识别要分10类、遥感影像地物分类要分几十类这些指标就变得不太好用了。你会遇到几个很实际的问题整体准确率可能是高的但到底哪些类别经常被搞混模型是把“猫”错认成“狗”多还是把“狗”错认成“狐狸”多每一类的召回率分别是多少这些问题靠一个总体准确率完全回答不了。多分类里更麻烦的是类别不平衡。假设三类样本比例是90:5:5模型全预测成第一类准确率也有90%看起来很漂亮实际却是废的。这时候就需要一个能把每一类、每一对类别的预测结果都摊开来看的工具。混淆矩阵Confusion Matrix就是干这个的。它是一个N乘N的表格N是类别数第i行第j列表示“真实类别为i、预测类别为j”的样本数。你只要盯着这个矩阵看一眼哪一类容易被哪一类吃掉、哪一类几乎不会错、哪些类别高度混淆全都暴露无遗。1.2 这个资源包到底能帮你解决什么问题标题里写的“源码数据”在绝大多数这类包里通常包含三样东西一是训练好的预测结果或者一个可直接运行的分类demo二是一段绘制混淆矩阵图的Matlab脚本三是用来演示的数据文件可能是.mat格式也可能是.csv。这些资源的核心目的就是把“模型的预测结果”可视化成一个直观的网格图而不是只给你一堆数字。我见过太多人花时间在调模型上最后交报告时却因为图太丑被导师打回。其实画混淆矩阵这件事本身并不复杂难点在于第一怎么把模型输出的原始预测标签和真实标签优雅地喂给绘图函数第二怎么处理类别标签顺序、显示百分比还是数量、颜色深浅代表什么第三怎么把图调整到论文要求的分辨率和样式。这个资源包正好帮你绕过前面那些造轮子的过程把重心放在理解和使用上。1.3 借助Matlab做这件事的优势选择Matlab而不是Python有几个实际理由。一是很多工科生的实验环境本来就是Matlab用现成工具链最顺手二是Matlab的绘图系统高度集成比如plotconfusion函数来自深度学习工具箱封装得非常完整几行代码就能出图三是Matlab处理矩阵数据有天然优势因为混淆矩阵本质上就是一个矩阵无论是计算还是展示都和Matlab的底层设计高度匹配。不过这里有个比较容易被忽略的点plotconfusion这个函数主要面向神经网络训练过程中的结果展示如果你用的是SVM、决策树、KNN这类传统机器学习分类器它就不太好直接用了。所以成熟的方案是结合自定义绘图代码用heatmap这类更底层的函数自己拼装一张混淆矩阵图。这个资源包里通常也会包含这种自定义写法因为它更通用。2. 搞懂混淆矩阵的本质后面才不迷糊2.1 从二分类到多分类的扩展逻辑在二分类里混淆矩阵通常是2乘2的四个格子分别叫TP真正例、FP假正例、FN假负例、TN真负例。很多人学到这里就停了一做多分类就不知道怎么套。实际上多分类的扩展逻辑非常直观。对于一个有C个类别的分类器把真实标签当作矩阵的行把预测标签当作矩阵的列格子(i, j)里填的就是“真实是第i类、但被预测成第j类”的样本个数。对角线上的格子越多说明模型判断越准对角线以外的格子则是错误的聚集地。举个例子假设有三类0、1、2。真实标签是[0,0,1,1,2,2]预测标签是[0,0,1,0,2,1]。数一下就得到3乘3的矩阵第一行第一列是2两个真实为0的样本都预测对了第一行第二列是0第一行第三列是0第二行第一列是1一个真实为1的样本被误判为0第二行第二列是1第二行第三列是0第三行第一列是0第三行第二列是1第三行第三列是1。整个过程就是数数没有任何神秘之处。2.2 从混淆矩阵派生出的关键指标光是画出混淆矩阵还不够通常还要从里面提取指标这就是论文里常说的per-class metrics。对类别i来说真正例TP_i就是矩阵第i行第i列的值假正例FP_i是第i列除对角线外所有值的和也就是“别的类被误判成i”的数量假负例FN_i是第i行除对角线外所有值的和也就是“本来是i却被判成别的类”的数量。有了这三个数精确率、召回率、F1都能算出来。这些指标比整体准确率有信息量得多。比如在医学影像分类里某种罕见病的召回率如果只有50%就意味着有一半患者会被漏诊这种情况下整体准确率再高也不能说明模型可用。你在汇报多分类结果时如果能拿出一张混淆矩阵再配上一张指标表说服力立刻不一样。2.3 多分类场景下看图的几个关注点我拿到一张混淆矩阵图一般会做三件事。第一看对角线颜色是否明显深于周围如果整体都是浅色说明模型泛化能力堪忧第二看对角线以外的深色格子聚集在哪这能直接告诉你模型最容易在哪些类之间“打架”比如数字4和9、3和8它们长得太像混淆多很正常第三看每一行或者每一列的分布差异如果某一行整体很浅说明这一类几乎没被正确识别要么是样本量太少要么是特征太弱需要针对性补充数据或者重新设计特征。对这些观察点有了清晰认识后你就不再是“为了画图而画图”而是能把矩阵图真正用起来反哺到模型迭代里。3. 数据组织和工具选型3.1 数据怎么组织才不会白折腾Matlab里最常见的做法是用两个列向量Ytrue和Ypred。Ytrue是真实的类别标签Ypred是模型的预测结果。这两个向量的长度要完全一致而且元素类型要匹配这是画图不出错的大前提。关于标签类型这里有两个流派。一种是用数值标签比如1、2、3……7这类标签在计算指标时最方便但画图时图上的刻度显示就是数字不够直观。另一种是用分类变量也就是categorical类型比如categorical({cat,dog,bird,cat,...})。categorical类型的好处是绘图时Matlab会直接用类别名称做坐标轴刻度标签图更可读。但要注意如果Ytrue是categorical而Ypred是普通double数组调用函数时可能会报维度不匹配所以最好在预处理时统一转换Ytrue categorical(Ytrue); Ypred categorical(Ypred);我在这个资源包里看到过一种比较规范的数据组织方式把真值、预测值和类别名单独存放绘图脚本只负责读取和渲染。这种解耦方式值得借鉴。如果数据散落在Excel里推荐在导入后用readtable读进来再拆分成标签和特征两块。顺序千万不要乱预测结果一定要和真实标签按行对齐错位的话计算出来的矩阵就没有任何意义。3.2 画法方案对比plotconfusion还是自定义heatmap在Matlab里画多分类混淆矩阵主要有两条路线。第一条是用深度学习工具箱里的plotconfusion。这个函数会生成一张带颜色条、带百分比和数量标注的标准图效果挺好看但最大的问题是它要求传入categorical数组而且对工具箱版本有依赖。对传统的分类器比如SVM或者KNN预测输出是double数组你要是直接喂给plotconfusion就有可能会报错让人莫名其妙。第二条是自定义绘制基于heatmap函数或者干脆用imagesc加text自己拼。好处是灵活可控颜色映射、文字内容、坐标轴标签、字体大小都能自己定。这也是很多成熟资源包采用的方案因为通用性更强不依赖特定工具箱而且可以完全控制输出样式。如果你在准备论文插图我强烈建议你掌握这套自定义方案因为这样画出来的图风格跟论文要求能完全对齐。3.3 核心绘图源码思路补全我先把这个资源包里最常见的核心绘图逻辑拆给你看。假设已经有混淆矩阵CM一个N乘N的数值矩阵类别名称列表classNames一个cell数组那么基本的绘图步骤是这样的% 假设CM是N×N的混淆矩阵classNames是类别名称 N length(classNames); figure; imagesc(CM); colormap(parula); % 或者用jet、gray看个人偏好 colorbar; axis square; xticks(1:N); yticks(1:N); xticklabels(classNames); yticklabels(classNames); set(gca, FontSize, 12); % 在格子里填充数字 for i 1:N for j 1:N text(j, i, num2str(CM(i, j)), ... HorizontalAlignment, center, ... FontSize, 11, Color, w); end end这段代码的思路很清晰用imagesc把矩阵画成彩色网格然后用两重循环在每个格子中心写上具体的数字。颜色越深代表数字越大浅色代表数量少。如果你希望颜色越深代表“越差”那可以对CM做逆映射但通常情况下颜色深浅直接反映数值大小就够了。不过这段只是一个基础版本。更高级的版本会考虑归一化比如把每一行除以该行的总数得到“真实类别为i时预测成各个类别的比例”这样在样本不平衡时矩阵的颜色分布更能反映比例关系而不是被大样本类别主导。归一化的代码通常是CM_norm CM ./ sum(CM, 2);然后在imagesc时传入CM_norm但在格子里还是写回原始数量CM(i,j)。这种“颜色用比例、数字用数量”的做法在论文里非常常见既直观又保留原始信息我强烈推荐你采用。4. 案例实操从训练模型到画出完整混淆矩阵4.1 准备一个可复现的分类demo为了让整个流程跑得通我用Matlab自带的fisheriris数据集来演示。这个数据集有150个样本、4个特征、3个类别setosa、versicolor、virginica非常适合做多分类演示。当然这个数据集本身在Matlab里可以通过load fisheriris加载不需要额外下载任何文件。我们先用一个最简单的分类器——多分类线性判别分析或者决策树——跑出预测结果。这里为了方便我直接使用fitcecoc对多分类的SVM来演示load fisheriris; X meas; Y species; rng(42); % 划分训练集和测试集这里用交叉验证方式估计泛化能力先简单用全部数据演示流程 Mdl fitcecoc(X, Y, Learners, svm); Ypred predict(Mdl, X);这段代码训练一个SVM多分类模型然后拿训练数据本身做预测方便展示。实际做实验时你应该用交叉验证或者单独划分测试集不然会过拟合乐观估计效果。4.2 调用plotconfusion画出标准矩阵图因为Y和Ypred都是cell数组字符串类别转换一下就可以直接调用plotconfusionYcat categorical(Y); YpredCat categorical(Ypred); figure; plotconfusion(Ycat, YpredCat);这一行代码输出的图里包含真正的混淆矩阵、每个类别的精确率和召回率、整体准确率排版比较规范。但问题在于这图用的是神经网络工具箱的采样风格颜色和字体不一定符合你的论文要求而且它的文字标注格式、矩阵位置、颜色条位置都是固定死的想改不太方便。所以我把plotconfusion定位成“快速验证”工具在调试阶段用它能快速看个大概真正到画正式插图时还是用自定义方案。4.3 用heatmap画一张符合论文风格的可定制矩阵这里我给出一个更完整的自定义版本% 计算混淆矩阵 CM confusionmat(Y, Ypred); % 类别名称这里Y本身就是字符串类别 classNames categories(categorical(Y)); numClasses length(classNames); % 归一化按行 CM_norm CM ./ sum(CM, 2); figure; h heatmap(classNames, classNames, CM_norm, ... Colormap, parula, ... CellLabelFormat, %.2f, ... FontSize, 12, ... Title, Confusion Matrix (Normalized by Row)); h.XLabel Predicted Class; h.YLabel True Class; h.ColorbarVisible on;这个版本的图坐标轴会直接显示类别名格子里的数值是每行归一化后的比例。它和上一版有本质区别上一版是“数量视角”这一版是“比例视角”。在看分类器对稀有类别的性能时比例视角远比数量视角更有意义。4.4 自动计算每类精确率、召回率与F1画完图后一般还要在论文里再给一张指标表。手动一个个算容易出错写个循环自动跑最稳妥TP diag(CM); FP sum(CM, 1) - TP; FN sum(CM, 2) - TP; precision TP ./ (TP FP); recall TP ./ (TP FN); F1 2 * precision .* recall ./ (precision recall); % 结果汇总表 T table(classNames, precision, recall, F1, ... VariableNames, {Class, Precision, Recall, F1}); disp(T);把这段代码放在画图代码后面你就能同时得到可视化结果和数值指标整个评估模块就闭环了。我亲眼见过不少同学用Excel手工数混淆矩阵费时不说还容易数错这种自动化方式才是正路。5. 扩展到更复杂的数据集和展示策略5.1 手写数字等高类别数场景当类别数增加到10类以上时混淆矩阵图会变得比较密格子里的数字很容易挤在一起。这时候有几种处理技巧第一种格子里只写数字不写百分比并且把字号调小。第二种关闭部分格子里的文字只保留非零值。第三种把图画大比如设置figure的Position参数为[100, 100, 800, 600]。第四种对文本颜色做自适应判断格子颜色深就写白字颜色浅就写黑字这样数字不会被背景色吞掉。下面这段代码演示了自适应文字的写法% 对每个格子根据背景色的亮度决定文字颜色 maxVal max(CM_norm(:)); for i 1:numClasses for j 1:numClasses val CM_norm(i, j); if val maxVal * 0.5 textColor w; else textColor k; end text(j, i, num2str(CM(i, j)), ... HorizontalAlignment, center, ... Color, textColor, FontSize, 9); end end这个技巧对你的模型评估展示特别有用尤其是多分类数量超过8类时黑字写在深色背景上根本看不清若全部用白字写在浅色背景上又发虚。自适应文字可以避免反复手动调格子颜色。5.2 类别不均衡数据的特殊处理如果各类别样本数量差异很大直接看原始数量矩阵会误导人。比如类别A有1000个样本类别B只有20个那么即使B的召回率极低反映在数量矩阵上B这一行的颜色也可能很浅视觉冲击力不强。这时候归一化到行比例非常重要。但行归一化也有副作用它只看“真实类别是i时预测分布如何”看不清“类别i的总量其实很小”。所以稳妥做法是给两个矩阵一个是原始计数矩阵一个按行归一化的比例矩阵。论文中如果只能放一张图我建议放归一化版本然后在图上或正文里注明样本量。另外实验记录时我习惯同时在代码里输出每类的支持样本数即GT中每类数量这样审稿人或导师问起你能立刻回答“为什么这一类看起来很差”的样本量因素。5.3 输出绘图数据让图和表都对得上很多人只把混淆矩阵图导出成图片原始矩阵数据却随手扔了。等到要改颜色、重排版、或者增加统计检验时又要重新跑一遍代码。我的建议是在绘图后立即把CM和CM_norm保存到文件save(confusion_result.mat, CM, CM_norm, classNames, Ytrue, Ypred);这样后续哪怕改图样式也不需要重新训练模型直接加载矩阵数据就能重新渲染。这个习惯能省下不少时间。6. 常见问题与排查技巧实录6.1 画出来的图颜色全是一个色或者全是深色这个情况通常是混淆矩阵里有个别极大值把颜色映射范围拉得太宽导致其他格子的差异看不出来。解决办法是先把数据映射到固定范围比如用caxis或者clim设置[0, 1]如果用的是归一化矩阵。或者干脆用分位数截断把极端值截掉让大部分区域的颜色差异更明显。6.2 类别顺序和预期不一致默认情况下confusionmat函数输出的类别顺序是按字典序或数值大小排列的不一定是你想要的逻辑顺序。比如类别名是“high”“low”“medium”按字典序就会变成high、low、medium画图时看着很别扭。解决办法是显式指定类别顺序classOrder {low, medium, high}; CM confusionmat(Y, Ypred, Order, classOrder);这样矩阵和坐标轴标签就会按你指定的顺序排列图面立刻变得有条理。6.3 plotconfusion报错“Number of vectors incompatible”这个报错最常见的根源是Ytrue和Ypred的类别集合不一致。例如训练时类别标签是1、2、3预测输出里却出现了0或者4。混合数值类型时更容易出现。解决办法是先查看两个向量的unique值确保它们一致如果训练数据里缺少某个类别用categorical并指定categories来补齐Ytrue categorical(Ytrue, 0:9); Ypred categorical(Ypred, 0:9);6.4 图片导出版本分辨率低、发虚Matlab里直接截图显然不行。导出高质量图片时我建议用exportgraphics函数R2020a及以上版本它比print更好用exportgraphics(gcf, confusion_matrix.png, Resolution, 300);如果投期刊要求矢量图可以导出为pdf或者eps格式这样文字和颜色都保持矢量精度。记着在导出前把figure的字体、大小、颜色都调好不然导出来再改就很麻烦。6.5 类别名太长坐标轴标签严重重叠当类别是“Class_A_very_long_name”这类长字符串时x轴标签会相互压在一起图完全没法看。解决方式有几种一是旋转x轴标签h.XTickLabelRotation 45对heatmap。二是改用简短别名比如“Setosa”“Vers”“Virg”再在图例或正文中说明全称。三是把图幅调大。我一般优先用旋转45度加调大图幅这两种改动对图面破坏最小。7. 我在反复实操中总结的几条经验第一次接触这类资源包时我犯过一个低级错误只把资源里的绘图函数当黑盒没去理解它的输入输出格式结果一换到自己的数据就各种报错。后来我把confusionmat的用法、categorical数组的转换、heatmap的参数列表完整过了一遍才真正打通。画多分类混淆矩阵这事说到底分三步第一步把真实标签和预测标签整理成等长的列向量第二步用confusionmat得到矩阵第三步用imagesc或heatmap渲染矩阵并加上数值。资源包里给你的是这套流程的模板但你要根据自己的数据和场景去微调。我后来的习惯是把整个评估流程封装成一个函数输入是Ytrue、Ypred和classNames输出自动包含三样东西——混淆矩阵图png和pdf各一份、指标表Excel一份、归一化矩阵数据mat一份。这样无论做多少组实验评估部分只需要一行调用省下来的时间和精力可以投入到真正重要的模型优化上。最后再提醒一句不要把注意力全放在画图上混淆矩阵背后的指标解读才是你论文里真正有含金量的部分。矩阵图告诉观众“模型错在哪”而你的分析和解释则要告诉他们“为什么错、怎么改进”。工具是手段理解才是目的。本文还有配套的精品资源点击获取