2018年学习的遗留文章。
基本说明
由于近来在研究关于eye fixation以及saliency detection,之前在object detection中使用较多的是mAP, 而这里使用的更多的是ROC(Reciever OPeration Characteristic)曲线和AUC评价分类器的性能。该分类器实际上是可以解决多类分类问题的(后续进行说明), 然而其在解决二分类问题时还是存在一定优势的(后续进行说明),此文章中首先介绍ROC、AUC基本概念,然后介绍了如何计算得到ROC以及利用ROC计算得到AUC。该文章的主要参考资料为:http://alexkong.net/2013/06/introduction-to-auc-and-roc/ 。写作时间为2018年1月19日。
ROC曲线基本概念
首先直观地看一看ROC曲线的基本表征形式:
在ROC曲线的示例图上可以看到,ROC曲线的横坐标为FPR(False Positive Rate), 纵坐标为TPR(True Positive Rate), 其中FPR的定义为 False Positive / Sample Numbers, 以及TPR定义为 True Positive / Sample Numbers。
其中虚线y=x上的点表示,期都是随机猜测策略的分类器结果,也就是False Positive Rate和True Positive Rate两种score结果是一样的,比如(0.5, 0.5)表示的是该分类器随机对于一半的样本猜测其为正样本,另外一半样本为负样本。
ROC曲线的绘制
对于一个分类器的固定的数据样本,实际上只能得到一个点。但是ROC曲线实际上是上述情况下多个点绘制而成的曲线,因此需要进行多点配置。因而我们可以设置不同的confidence的值或者score作为threshold进行negative samples 和 positive samples之间的区分。
如下所示:
我们通过这20个样本得到20组FPR和TPR,然后绘制的ROC曲线如下:
AUC的概念与计算
AUC(Area Under Curve)直观上表示为ROC与正X轴之间围成的面积。其作为一个数值,可以定量地描述一个模型性能的好坏。AUC在 scikit-learn上的结果为 http://scikit-learn.org/stable/modules/generated/sklearn.metrics.auc.html 。
根据Fawcett, 2006,AUC的含义为 ‘The AUC value is equivalent to the probability that a randomly chosen positive example is ranked higher than a randomly chosen negative example.’, 也就是说,AUC是一个概率值,当随机挑选一个正样本以及一个负样本,当前的分类算法根据计算得到的score值将这个正样本排在负样本前面的表征值(一般为概率值)就是AUC值。
AUC优劣分析
AUC的劣势显而易见,当针对多分类任务时,其threshold并不好定义,没有一套成熟以及成型的规范,因此不常用与多分类任务,之后可以考虑多分类任务问题。
而AUC的优势则在于,‘当测试集中的正负样本的分布变化时,ROC曲线能够保持不变’。在实际的数据集中经常会出现类不平衡现象,也就是正负样本的比例过于不协调,而且测试数据中的正负样本的分布也可能随着时间变化。
以下就是ROC曲线在样本不均衡下的稳定性与Precision Recall的稳定性对比,可以有:
在上图中,(a)和©为ROC曲线,(b)和(d)为Precision-Recall曲线。(a)和(b)展示的是分类其在原始测试集(正负样本分布平衡)的结果,©和(d)是将测试集中负样本的数量增加到原来的10倍后,分类器的结果。可以明显的看出,ROC曲线基本保持原貌,而Precision-Recall曲线则变化较大。
参考资料
-
Davis, J., & Goadrich, M. (2006, June). The relationship between Precision-Recall and ROC curves. In Proceedings of the 23rd international conference on Machine learning (pp. 233-240). ACM. ↩
-
(Fawcett, 2006),Fawcett, T. (2006). An introduction to ROC analysis. Pattern recognition letters, 27(8), 861-874.
相关代码
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
# Import some data to play with
iris = datasets.load_iris()
X = iris.data
y = iris.target
# Binarize the output
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]
# Add noisy features to make the problem harder
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]
# 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)
# Compute ROC curve and ROC area for each class
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"])
##############################################################################
# Plot of a ROC curve for a specific class
plt.figure()
lw = 2
plt.plot(fpr[2], tpr[2], color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc[2])
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
##############################################################################
# Plot ROC curves for the multiclass problem
# 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
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()