如何在MATLAB中绘制CNN的精确率-召回率曲线?
解决PR曲线绘制及精确率计算异常的问题
我来帮你梳理下这里可能踩的坑,以及正确的做法:
核心问题:你只计算了单个阈值下的指标,而PR曲线需要多阈值数据
精确率-召回率(PR)曲线的本质是展示不同分类阈值下,模型精确率和召回率的变化关系。你现在的代码只算了一组TP/TN/FP/FN,对应的是某一个固定阈值(比如默认的0.5)下的结果,自然没法画出完整的PR曲线,而且如果这个阈值下的计算本身有问题,结果就会不符合预期。
先排查你的TP/TN计算逻辑错误
从你的代码来看,大概率是把CNN的输出分数(连续概率值)当成了二分类标签来计算了:
idx = (ACTUAL()==1); tp = sum(ACTUAL(idx)==PREDICTED(idx));
如果PREDICTED是CNN输出的原始分数(比如sigmoid输出的0~1概率),那ACTUAL(idx)都是1,而PREDICTED(idx)是连续的概率值,几乎不可能等于1,这会导致tp的计算结果严重偏小,进而让精确率计算完全错误。
正确的PR曲线绘制步骤(以Matlab为例)
假设你的ACTUAL是0/1真实标签,SCORES是CNN输出的正类概率分数(二分类下用sigmoid,多分类下取正类的softmax概率),按照以下步骤来:
- 生成一系列不同的分类阈值
- 对每个阈值,计算对应的精确率和召回率
- 绘制所有(召回率, 精确率)的点,连成曲线
示例代码:
% 假设你已经有了真实标签和CNN输出的正类分数 ACTUAL = [1,0,1,1,0,...]; % 你的真实标签向量 SCORES = [0.8,0.3,0.9,0.6,0.2,...]; % CNN输出的正类概率,和ACTUAL长度一致 % 生成0到1之间的101个阈值(步长0.01) thresholds = linspace(0, 1, 101); % 初始化存储精确率和召回率的数组 precisions = zeros(size(thresholds)); recalls = zeros(size(thresholds)); total_pos = sum(ACTUAL == 1); % 正样本总数,避免重复计算 for i = 1:length(thresholds) thresh = thresholds(i); % 根据当前阈值得到二分类预测标签 pred_labels = SCORES > thresh; % 计算TP/FP/FN tp = sum(ACTUAL & pred_labels); fp = sum(~ACTUAL & pred_labels); fn = sum(ACTUAL & ~pred_labels); % 计算精确率和召回率,处理除以0的情况(防止报错) precisions(i) = tp / max(tp + fp, 1); % 分母为0时设为1(或根据需求调整) recalls(i) = tp / max(total_pos, 1); end % 绘制PR曲线 figure; plot(recalls, precisions, 'b-', 'LineWidth', 1.5); xlabel('Recall'); ylabel('Precision'); title('Precision-Recall Curve'); grid on; % 可选:计算平均精度AP(PR曲线下的面积,衡量模型整体性能) ap = trapz(recalls, precisions); disp(['Average Precision (AP): ', num2str(ap)]);
额外注意事项
- 确保
SCORES是正类的概率值,而不是经过阈值判断后的0/1标签 - 处理除以0的情况:当没有预测为正的样本时(tp+fp=0),精确率通常设为1;当没有正样本时,召回率设为0(根据实际场景调整)
- PR曲线的x轴是召回率(Recall=tp/(tp+fn)),y轴是精确率(Precision=tp/(tp+fp)),不要搞反轴
内容的提问来源于stack exchange,提问作者user123456789
相关产品推荐
相关产品推荐

