1.二分类问题的混淆矩阵(confusion matrix)以及precision、recall:
真实情况 | 预测结果(正例positive) | 预测结果(反例negative) |
---|---|---|
正例(true) | TP(真正例) | FN(假反例) |
反例(false) | FP(假正例) | TN(真反例) |
precision = TP / (TP + FP): 预测为正例中,有多少真的是正例,也就是我判别为正例中有多大比例是对的。
recall = TP / (TP + FN):所有正样本中,有多少被我判别成了正例,也就是正例中我召回了多少比例。
2.ROC曲线和AUC
2.1 ROC曲线和AUC曲线概念:
ROC曲线:受试者工作特性曲线(Receiver Operating Characteristic Curve)。横轴是假正例率(False Positive Rate, fpr),纵轴是真正例率(True Positive Rate, tpr)。
横轴:FPR = FP / (TN + FP):负样本中预测为正样本的比例。分母就是负样本的数量。
纵轴:TPR = TP / (TP + FN):正样本中预测为正样本的比例,其实就是recall。分母就是正样本的数量。
AUC:Area under ROC curve,即ROC曲线下的面积。
2.2 ROC的评判标准:
1.若一个分类器的ROC曲线被另一个分类器的ROC曲线完全“包住”,则后者性能优于前者
2.若两个分类器的ROC曲线发生交叉,则难以一般性地断言两者孰优孰劣。如果一定要进行比较,可以比较AUC大小。
2.3 ROC的绘制:
- 给定数据集包含m个正例,n个反例,根据分类器的预测概率进行降序排序,然后将分类阈值设置为最大:即所有预测结果都是反例,FPR和TPR都为0,也就是原点。
- 将分类阈值按照之前降序排列的顺序依次赋值,相当于每次只增加一个样本进行考察:如果当前样本是真正例,则纵坐标tpr += 1/m, 即(fpr, tpr)–> (fpr, tpr+1/m);如果当前样本是假正例,则横坐标fpr += 1/n,即(fpr, tpr) –> (fpr+1/n, tpr)。
- 依次连接各点即得ROC曲线。
对角线对应随机猜测模型。如果曲线经过点(0,1)则对应理想分类器。
现实任务中测试数据集是有限的,无法产生光滑的ROC曲线,只能绘制出类似上图的阶梯状的曲线。
3.关于ROC曲线的几点讨论
3.1 为什么可以用ROC曲线度量分类器的好坏?
在周志华老师的《机器学习》中是这么说的:
分类器的概率预测结果直接决定了学习器的泛化能力,在不同的应用任务中,我们可根据任务需求来采用不同的截断点,例如更重视precision,则阈值可以设置的大一点;如果更重视recall,则阈值设置小一点。因此,排序本身的质量好坏,体现了综合考虑学习器在不同任务下的“期望泛化性能”的好坏,或者说,“一般情况下”泛化性能的好坏。ROC曲线则是从这个角度出发来研究学习器泛化性能的有力工具。
4. 实例:sklearn绘制ROC曲线(sklearn上的两个demo)
4.1 二分类问题ROC曲线绘制
# -*- coding: utf-8 -*-
#!/usr/bin/env python
'''
5折交叉检验的ROC曲线图及平均ROC曲线图
'''
import numpy as np
from scipy import interp
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 StratifiedKFold
# 使用iris数据集,只保留类别0和类别1,共2类
iris = datasets.load_iris()
X = iris.data
y = iris.target
X, y = X[y != 2], y[y != 2]
n_samples, n_features = X.shape
# 加噪音
random_state = np.random.RandomState(0)
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]
# 设置分类器、交叉检验、绘制ROC曲线
cv = StratifiedKFold(n_splits=6)
classifier = svm.SVC(kernel='linear', probability=True,
random_state=random_state)
mean_tpr = 0.0
mean_fpr = np.linspace(0, 1, 100)
colors = cycle(['cyan', 'indigo', 'seagreen', 'yellow', 'blue', 'darkorange'])
lw = 2
i = 0
for (train, test), color in zip(cv.split(X, y), colors):
probas_ = classifier.fit(X[train], y[train]).predict_proba(X[test])
# 计算fpr, tpr, auc
fpr, tpr, thresholds = roc_curve(y[test], probas_[:, 1])
mean_tpr += interp(mean_fpr, fpr, tpr)
mean_tpr[0] = 0.0
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, lw=lw, color=color,
label='ROC fold %d (area = %0.2f)' % (i, roc_auc))
i += 1
plt.plot([0, 1], [0, 1], linestyle='--', lw=lw, color='k',
label='Luck')
mean_tpr /= cv.get_n_splits(X, y)
mean_tpr[-1] = 1.0
mean_auc = auc(mean_fpr, mean_tpr)
plt.plot(mean_fpr, mean_tpr, color='g', linestyle='--',
label='Mean ROC (area = %0.2f)' % mean_auc, lw=lw)
plt.xlim([-0.05, 1.05])
plt.ylim([-0.05, 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()
4.2 多分类问题ROC曲线绘制
# -*- coding: utf-8 -*-
#!/usr/bin/env python
'''
只绘制了多分类问题其中一类的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
# 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"])
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()