参考博客1: https://blog.csdn.net/sherry_gp/article/details/50560003
感谢博主大大 sherry_gp
参考博客2:https://blog.csdn.net/stu_lavender/article/details/79615474
感谢博主大大: stu_lavender
参考博客3:https://www.csdn.net/gather_25/MtzaMg3sNTE0LWJsb2cO0O0O.html
感谢博主大大
要评估分类的好坏,经常会用到混淆矩阵,因为我的代码是matlab实现的SVM分类,所以我想找一个matlab实现的混淆矩阵,小白一个,多亏了网上有那么多人家写好了分享出来的代码。
主要代码来源于 https://github.com/lipiji/PG_Curve
这个代码包里面有很多函数,用来实现不同的功能,这里我们用到的只是ConfusionMatrices 文件夹下的三个函数,把它们拷出来和其他代码放在同一个文件夹就可以在其他代码中调用函数,来实现画出混淆的功能了。图1是调用关系,所以实际上我们在其他代码中他、调用的只有代码1,即compute_confusion_matrix.m,但是我这里用的并不是github上的compute_confusion_matrix.m,用的是另外一个版本的,只是我觉得他们好像很像。
下面是我选择的compute_confusion_matrix.m,参考博客 https://www.csdn.net/gather_25/MtzaMg3sNTE0LWJsb2cO0O0O.html
,感谢作者大大 何凌霄
当时我很疑惑 num_in_class=[0 num_in_class]; 这个和github上的不太一样 这一行是不是错了,结果把它改掉以后,喜闻乐见地发现报错了,所以还是不要改它原来的代码了。
% 预测标签,每一类的数目,类别数目
function [confusion_matrix]=compute_confusion_matrix(predict_label,num_in_class,name_class)
% predict_label为一维行向量
% num_in_class代表每一类的个数
% name_class代表类名
num_class=length(num_in_class);
num_in_class=[0 num_in_class];
confusion_matrix=size(num_class,num_class);
for ci=1:num_class
for cj=1:num_class
summer=0;%统计对应标签个数
c_start=sum(num_in_class(1:ci))+1;
c_end=sum(num_in_class(1:ci+1));
summer=size(find(predict_label(c_start:c_end)==cj),2); % 统计对应标签个数,注意此处的predict_label可能是数值组成的向量,不是字符串组成的向量
%confusion_matrix(ci,cj)=summer/num_in_class(ci+1);%这个是显示正确率,
confusion_matrix(ci,cj)=summer;%这个是显示图片有多少张,
end
end
draw_cm(confusion_matrix,name_class,num_class);
end
需要注意的是,运行时,可能会报错,说代码3即rotateXLabels.m有问题,这是因为原来的代码不适用于我所使用的MATLAB2017,需要稍加修改,然后我百度到了这个
https://blog.csdn.net/stu_lavender/article/details/79615474 ,很好地解决了这个问题
下面的是我的修改,这个是对代码3某个部分的修改,并非是把代码3变成这样子,啊啊啊啊,以前我真的做过这种事。。。保险起见,所以不敢删东西,注释掉即可,MATLAB快捷键为 选中文字,然后ctrl+R可以加注释,Ctrl+T可以去注释。
这个是github上的rotateXLabels.m 改的
function addListeners( ax )
% Create listeners. We store the array of listeners in the axes to make
% sure that they have the same life-span as the axes they are listening to.
axh = handle( ax );
listeners = [
% handle.listener( axh, findprop( axh, 'FontName' ), 'PropertyPostSet', @onAxesFontChanged )
% handle.listener( axh, findprop( axh, 'FontSize' ), 'PropertyPostSet', @onAxesFontChanged )
% handle.listener( axh, findprop( axh, 'FontWeight' ), 'PropertyPostSet', @onAxesFontChanged )
% handle.listener( axh, findprop( axh, 'FontAngle' ), 'PropertyPostSet', @onAxesFontChanged )
% handle.listener( axh, findprop( axh, 'FontUnits' ), 'PropertyPostSet', @onAxesFontChanged )
% handle.listener( axh, findprop( axh, 'OuterPosition' ), 'PropertyPostSet', @onAxesPositionChanged )
% handle.listener( axh, findprop( axh, 'XLim' ), 'PropertyPostSet', @onAxesLimitsChanged )
% handle.listener( axh, findprop( axh, 'YLim' ), 'PropertyPostSet', @onAxesLimitsChanged )
%之前报错找不到 handle.listener这个函数,所以上网找解决方案,2014以后的都用 addlistener取代上面那个,by wyh
%参考博客 https://blog.csdn.net/stu_lavender/article/details/79615474
addlistener( axh,'FontName', 'PostSet', @onAxesFontChanged )
addlistener( axh,'FontSize' , 'PostSet', @onAxesFontChanged )
addlistener( axh, 'FontWeight' , 'PostSet', @onAxesFontChanged )
addlistener( axh, 'FontAngle' , 'PostSet', @onAxesFontChanged )
addlistener( axh, 'FontUnits', 'PostSet', @onAxesFontChanged )
addlistener( axh, 'OuterPosition' , 'PostSet', @onAxesPositionChanged )
addlistener( axh, 'XLim' , 'PostSet', @onAxesLimitsChanged )
addlistener( axh, 'YLim' , 'PostSet', @onAxesLimitsChanged )
];
setappdata( ax, 'RotateXLabelsListeners', listeners );
end % addListeners
这样以后,就可以了,不会报错了。
但是当初对于我来说,最难的并不是这个,而是有了函数不知道怎么往里面传参数。就好像有了很好的工具但是找不到说明书。。。
调用的形式是这样的,
[confusion_matrix]=compute_confusion_matrix(predict_label,num_in_class,name_class);
在我找到的那个源文件中,有对这4个参数的说明,但是对于我这个纯新手来说,这个还是太难了。。。感觉实在好难啊,卡了好久。
现在做个说明,参数1:predict_label,是一个1xN的行向量,N是测试图片的张数,例如我的测试集有919张图片,那么我的predict_label就是1x919的向量。
在MATLAB工作区中的样子
这个意味着第1张图片被预测为第一类,第6张图片被预测为第二类,以此类推。。。
值得注意的是,这个其实就是你的分类结果,一般到了这一步,前面都有这个变量,没有的话就构造出来,反正你最后要有这个东西,然后把你代码中的这个东西的变量名放在参数1的位置上,当然了,最好在save中保存工作区的文件,保存的东西为.mat格式,这样就可以不用再跑代码,直接下次load它。但是说是这么说,我还没用过load,只用过save命令。。。
参数2:num_in_class,这参数代表了每个类的数目
例如我在分类代码中写:num_in_class=[68,136,170,76,178,71,140,80];意味着我的第一类有68张图片,第2类有136张。。。当然该变量也可以不叫num_in_class,你可以自己取名字,只要知道这是同一个东西,把它放在参数2的位置即可。
参数3:name_class,这个参数代表了每个类的名字,
例如我在分类代码中写
name_class={‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’};
意味着我的第一类叫‘ 1,这个参数三和参数二要对应。
其实我代码里还有一个真实标签,是列向量NX1,例如919x1。但是不知道有没有用。
然后就可以调用这个函数了,结果如图。
我们会发现这个说的是小数,不是最原始的图片数目,为了更加原始,我们修改它compute_confusion_matrix函数,其实就是最后一行直接用summer就好了,不要再除了
%confusion_matrix(ci,cj)=summer/num_in_class(ci+1);%这个是显示正确率,
confusion_matrix(ci,cj)=summer;%这个是显示图片有多少张,
关于保存结果,建议保存为.fig形式,这个是最原始的图片。有了它就可以把它导出为其他各种图片形式,比如jpg格式。具体操作是 用matlab打开fig文件,点“文件”——“导出设置”——设置好以后点击“导出”即可,分辨率可以设置为300或600,这样比qq截图分辨率高很多,而且.fig是最原始的数据,以后如果要在上面临时改字体大小或者标签也很方便,不用再跑一次实验,节省时间和精力。