前面,我们提到了混淆矩阵,以及根据混淆矩阵进一步计算得到的敏感度(召回率)、特异度、精确度、准确度、F1 Score等等。那他们的前提都是要首先确定一个截断阈值。
【模型评估】混淆矩阵(confusion_matrix)之 TP、FP、TN、FN;敏感度、特异度、准确率、精确率
这个截断阈值选取多少比较合适呢?这里就需要引入ROC曲线了,一个衡量模型整体性能的参数。
一、什么是ROC(Receiver Operating Characteristic)
在上一章计算混淆矩阵时候,我们提到:混淆矩阵的绘制严重依赖一个固定的截断阈值,大于这个阈值的是阳性,反之则是阴性。
在确定该阈值的前提下,才能确定混淆矩阵的数值,这种对模型评价方式是片面的,不够全局的,没有从整体上评价一个模型的性能。
此时,迫切需要一中评价方式,能够更加全面的对模型进行评估。既然一个截断阈值的评价是片面的,那么我尽可能的多取一些阈值,综合起来评价,那是不是就可以避免这个问题呢?于是就出现的ROC曲线,如下所示:
其中:
- 横轴:
False Positive Rate
(假阳率,FPR=1-特异度) - 纵轴:
True Positive Rate
(真阳率,TPR=敏感度)
连接(0,0)和(1,1)绿色曲线上的任意一点,是在该阈值下,对应的混淆矩阵下的假阳性率和真阳性率。例如图中的(0.1,0.8),即该阈值 t 下,假阳性率为0.1,真阳性率为0.8。
连接这条曲线上的任意一个点,就对应着在该截断阈值下的假阳性率和真阳性率。其中
- 最优的点取在左上角
- 曲线右下包围的面积,叫做AUC值
二、如何绘制ROC曲线
那后面,我们就针对这样一个思路,开始绘制一个分类任务中的ROC曲线出来。整理下绘制思路:
- 获取每一张评估图像的标注类别gt、预测该真实类别的预测置信度score;
- 对于某一个类,遍历分数0-1,分1000个截断阈值,分别计算在该阈值下,该类的混淆矩阵,进一步计算得到假阳性率和真阳性率
- 横坐标是假阳性率(1-特异度),纵坐标是真阳性率(敏感度),绘制ROC曲线
- 计算AUC值
2.1、sklearn绘制简单ROC
思路就是上面这样一个心路历程,但是现在基本上各个库都已经帮你封装好了,只需要准备好对应的数据格式,调用函数即可,无需重复造轮子了。下面就是调用sklear的函数,直接绘制ROC和AUC 值。如下:
import numpy as np
from sklearn.metrics import roc_curve, auc
y = np.array([1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1])
scores = np.array([0.1, 0.4, 0.35, 0.8, 0.9, 0.7, 0.6, 0.4, 0.2, 0.1, 0.2, 0.9, 0.8, 0.65, 0.85, 0.67, 0.75, 0.74, 0.36, 0.85, 0.48, 0.95, 1, 0.65,
0.85, 0.75, 0.95, 0.84, 0.74, 0.58, 0.95])
fpr, tpr, thresholds = roc_curve(y, scores, pos_label=1)
print(fpr)
print(tpr)
print(thresholds)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, lw=1, label="COVID vs NotCOVID, AUC=%0.3f)" % (roc_auc))
plt.xlim([0.00, 1.0])
plt.ylim([0.00, 1.0])
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC")
plt.legend(loc="lower right")
plt.savefig(r"./ROC.png")
print("ok")
其实,到这里基本上已经够绘制ROC曲线了,无论是单个类别,还是多个类别。pos_label
是哪个,其他的都是negative
,依次来绘制ROC曲线即可。
2.2、多分类的ROC曲线绘制到一起
有多个类别的时候,喜欢把不同的类,ROC
汇总到一张图里面,这样可以相互对比,下面提供了一张绘制方式留作参考。同时也是鸢尾花项目的训练和测试过程,有所启发。
# 引入必要的库
import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle
from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from scipy import interp
# 加载数据
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 将标签二值化
y = label_binarize(y, classes=[0, 1, 2])
# 设置种类
n_classes = y.shape[1]
# 训练模型并预测
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
# shuffle and split training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.5,random_state=0)
# Learn to predict each class against the other
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,
random_state=random_state))
y_score = classifier.fit(X_train, y_train).decision_function(X_test)
# 计算每一类的ROC
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
# Compute micro-average ROC curve and ROC area(方法二)
fpr["micro"], tpr["micro"], _ = roc_curve(y_test.ravel(), y_score.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])
# Compute macro-average ROC curve and ROC area(方法一)
# First aggregate all false positive rates
all_fpr = np.unique(np.concatenate([fpr[i] for i in range(n_classes)]))
# Then interpolate all ROC curves at this points
mean_tpr = np.zeros_like(all_fpr)
for i in range(n_classes):
mean_tpr += interp(all_fpr, fpr[i], tpr[i])
# Finally average it and compute AUC
mean_tpr /= n_classes
fpr["macro"] = all_fpr
tpr["macro"] = mean_tpr
roc_auc["macro"] = auc(fpr["macro"], tpr["macro"])
# Plot all ROC curves
lw=2
plt.figure()
plt.plot(fpr["micro"], tpr["micro"],
label='micro-average ROC curve (area = {0:0.2f})'
''.format(roc_auc["micro"]),
color='deeppink', linestyle=':', linewidth=4)
plt.plot(fpr["macro"], tpr["macro"],
label='macro-average ROC curve (area = {0:0.2f})'
''.format(roc_auc["macro"]),
color='navy', linestyle=':', linewidth=4)
colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(n_classes), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'
''.format(i, roc_auc[i]))
plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Some extension of Receiver operating characteristic to multi-class')
plt.legend(loc="lower right")
plt.show()
保存的图像,如下:
2.3、绘制FROC曲线
当评估检测算法性能时,常用的指标之一是接收者操作特性曲线(Receiver Operating Characteristic Curve,ROC曲线
)。ROC曲线以真阳性率(True Positive Rate,TPR)作为纵轴,以假阳性率(False Positive Rate,FPR)作为横轴。它显示了在不同阈值下,算法的敏感性和特异性之间的权衡关系。
而放射学检测任务中,通常关注的是感兴趣区域(Region of Interest,ROI)
的检测情况,这些ROI往往是病灶或异常区域。相较于ROC曲线,放射学检测任务更关注的是假阳性检测的数量,因为在医学领域,减少误检率尤为重要。
为了解决放射学检测任务的特殊性,提出了自由响应工作特性曲线(Free-response Receiver Operating Characteristic Curve,FROC曲线)
,它是一种用于评估医学图像检测算法性能的指标。FROC曲线以敏感性(Sensitivity
)作为纵轴,以平均假阳性数(Average False Positives Per Image,AFPI
)作为横轴。
在FROC曲线中,每个点代表了在特定假阳性数下的敏感性。与ROC曲线不同,FROC曲线的纵轴不是真阳性率,而是敏感性。AFPI表示平均每幅图像的假阳性数,它可以帮助评估算法在不同任务中的表现。
通过绘制FROC曲线,可以更准确地评估放射学检测算法在不同假阳性检测水平下的性能。一般来说,FROC曲线上的点越靠近左上角,表示算法在更低的假阳性率下能够获得较高的敏感性,从而被认为是更优秀的算法。
总结而言,FROC曲线是用于评估医学图像检测算法性能的一种指标,它关注在不同假阳性检测水平下的敏感性表现,帮助评估算法在放射学检测任务中的性能。
from sklearn import metrics
import matplotlib.pylab as plt
GTlist = [1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
Problist = [0.99, 0.98, 0.97, 0.93, 0.85, 0.80, 0.79, 0.75, 0.70, 0.65,
0.64, 0.63, 0.55, 0.54, 0.51, 0.49, 0.30, 0.2, 0.1, 0.09,
0.1, 0.5, 0.6, 0.7, 0.8, 0.5, 0.2, 0.3, 0.2, 0.5]
# num of image
totalNumberOfImages = 2
numberOfDetectedLesions = sum(GTlist)
totalNumberOfCandidates = len(Problist)
fpr, tpr, thresholds = metrics.roc_curve(GTlist, Problist, pos_label=1)
# FROC
fps = fpr * (totalNumberOfCandidates - numberOfDetectedLesions) / totalNumberOfImages
sens = tpr
print(fps)
print(sens)
plt.plot(fps, sens, color='b', lw=2)
plt.legend(loc='lower right')
# plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([fps.min(), fps.max()])
plt.ylim([0, 1.1])
plt.xlabel('Average number of false positives per scan') # 横坐标是fpr
plt.ylabel('True Positive Rate') # 纵坐标是tpr
plt.title('FROC performence')
plt.show()
展示结果:
2.4、MedCalc统计软件绘制ROC
MedCalc
是一款医学专用的统计计算软件,在研究医学领域有较为广泛的应用,软件不大,而功能却很强大,用图形化的界面直观明了的显示所统计的结果,这里就简单介绍下medcalc的统计教程。
官方下载地址:(只有15天试用期。由于不能乱传播,仅用作学习使用。若想获得免费版本,评论备注信息,留下邮箱)。官方地址:Download MedCalc Version 20.106
下面已绘制ROC曲线为例,进行介绍,步骤如图所示:
绘制的结果如下:
这也是绘制ROC的一种方式,比较快捷。只要准备好需要的数据,既可以直接绘制。注意,这里统计预测分数时候,阈值一定要取的比较低,比如0.01。这样在绘制曲线时候,阈值的选择面才会大。
百度文档对这块进行了详述,更多内容去看这里:MedCalc常用统计教程
2.5、目标检测中,基于Bbox阈值的ROC曲线
(这个暂时欠着,在处理中,可以先透露一些步骤):
-
读取的是预测的csv文件,包括file name, cls, score, box,预测结果里面多了一个置信度分数score
-
以标注gt作为标准,对预测pd的box进行iou的判断,如果大于设定的阈值,即暂时判定该gt的这个box,为tp(为何说暂定,因为这一个gt box,可能会被多个pd box的iou所匹配,所以需要找到iou最大的那个),没有被匹配的gt box判定为fn
-
根据置信度分数,进行0-1,分1000个截断阈值进行判断,依次遍历所有的预测框:
- iou阶段,已经得到了混淆矩阵,tp、fp、tn、fn的
- 用置信度阈值再过一遍,tp中大于阈值的,还是tp;小于阈值的,就预测为了negative,但是之前是positive的,于是就变成fn
- fp中大于阈值的,还是fp;小于阈值的,就预测为了negative,之前是negative的,于是就变成tn
- tn=GT_negative-fp
- fn=GT_positive-tp
-
统计下来,横纵轴坐标,绘制曲线,即可得到ROC曲线;
-
计算AUC值(近似为矩形面积累加)
代码正在整理说明,如果你们有好的建议,欢迎评论区讨论。
三、AUC值
AUC 是 ROC 曲线下面的面积,AUC 可以解读为从所有正例中随机选取一个样本 A,再从所有负例中随机选取一个样本 B,分类器将 A 判为正例的概率比将 B 判为正例的概率大的可能性。
也就是:任意取一个正样本和负样本,正样本得分大于负样本的概率。
AUC 反映的是分类器对样本的排序能力。AUC 越大,自然排序能力越好,即分类器将越多的正例排在负例之前。
- AUC = 1,代表完美分类器
- 0.5 < AUC < 1,优于随机分类器
- 0 < AUC < 0.5,差于随机分类器
AUC的公式:
问1:数据不平衡,对AUC有影响吗?
答1:数据不平衡对 auc 影响不大(ROC曲线下的面积,ROC的横纵坐标分别是真阳性率和1-真阴性率)。
问2:还有什么指标可以针对不平衡数据进行评估?
答2:还可以使用 PR(Precision-Recall )曲线。
四、总结
ROC(Receiver Operating Characteristic)
曲线是一种用于评估二分类模型性能的图形表示方法。它以真阳性率(True Positive Rate,TPR)为纵轴,以假阳性率(False Positive Rate,FPR)为横轴,展示了在不同分类阈值下,模型的敏感性和特异性之间的权衡。
关键概念:
- 真阳性(True Positive,TP):被模型正确地划分为正类的样本。
- 假阳性(False Positive,FP):被模型错误地划分为正类的负类样本。
- 真阴性(True Negative,TN):被模型正确地划分为负类的样本。
- 假阴性(False Negative,FN):被模型错误地划分为负类的正类样本。
这块参考链接:
绘制ROC曲线的步骤:
- 使用不同的分类阈值对样本进行预测,并计算出对应的TPR和FPR。
- 根据不同的分类阈值,将TPR和FPR绘制在坐标轴上。
- 连接各个点,形成ROC曲线。
ROC曲线的特点:
- 曲线越靠近左上角,表示模型具有更高的敏感性和更低的特异性,即在较低的假阳性率下能够获得较高的真阳性率,被认为是更优秀的模型。
- 对角线代表随机猜测的情况,处于对角线上方的曲线表示模型的性能好于随机猜测。
- ROC曲线下的面积(Area Under the ROC Curve,AUC)是一个综合评估模型性能的指标,AUC越大,模型性能越好。
ROC曲线的应用:
- 选择最佳分类阈值:根据应用需求,可以选择对应特定TPR和FPR的分类阈值。
- 比较不同模型:通过比较ROC曲线和AUC值,可以评估不同模型的性能。
- 模型调优:通过调整模型参数或特征选择,改变ROC曲线形状,提高模型性能。
总而言之,ROC曲线是评估二分类模型性能的一种重要工具,通过展示敏感性和特异性之间的权衡关系,帮助选择最佳分类阈值和比较不同模型的性能。
AP也是常用的一个综合评价工具,那么AP是怎么定义和如何实现的呢?这是下节我们需要讨论的内容,期待。