1 ROC曲线图
1.1 理解ROC曲线图中的四个点和一条线
image.png
- 左上角点 (0,1),即FPR=0且TPR=1,即FP= FN=0,所有的样本都正确分类,这是一个最完美的分类器,
- 右下角点(1,0),即FPR=1且TPR=0,即TN=0且TP=0,所有的样本分类错误,这是一个最糟糕的分类器。
- 左下角点 (0,0),即FPR=TPR=0,即FP=TP=0,分类器实际上预测所有的样本都为负样本。没有负样本预测错误(也就是负样本全部预测正确),正样本全部预测错误。
- 右上角点(1,1),即FPR=TPR=1,即FN=TN=0,分类器实际上预测所有的样本都为正样本。负样本全部预测错误,正样本全部预测正确。
- ROC曲线图中的虚线y=x上的点:这条对角线上的点其实表示的是一个采用随机猜测策略的分类器的结果,例如(0.5,0.5),表示该分类器随机对于一半的样本猜测其为正样本,另外一半的样本为负样本。
说明:ROC曲线越接近左上角,该分类器的性能越好。
1.2 理解AUC的值
AUC(Area Under Curve)被定义为ROC曲线下的面积,由于ROC曲线一般都处于y=x这条直线的上方,所以AUC的取值范围在0.5和1之间。使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。
1.3 ROC计算
计算ROC曲线的函数roc_curve定义如下:
sklearn.metrics.roc_curve(y_true, y_score, pos_label=None, sample_weight=None, drop_intermediate=True)
参数 :
1. y_true : 数组,shape = [样本数] 。二分类标签,取值为{0,1}或{-1,1},否则应该显式地指出正类的pos_label。
2. y_score : 数组, shape = [样本数], 目标得分,可以是positive类的概率估计。
3. pos_label:int or str, 指出positive标签值。
4. sample_weight: 顾名思义,样本的权重,可选参数。
5. drop_intermediate: boolean, optional (default=True):是否丢弃一些不出现在绘制的ROC曲线上的次优阈值,这有助于创建更轻的ROC曲线。
返回值 :
1. fpr : array, shape = [>2] ,数组,随阈值上涨的假阳性率
2. tpr : array, shape = [>2] ,数组,随阈值上涨的真正例率
3. thresholds : array, shape = [n_thresholds] ,数组,对预测值排序后的score列表,作为阈值,排序从大到小。
求解示例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import metrics
y = np.array([1, 1, 2, 2])
scores = np.array([0.1, 0.4, 0.35, 0.8])
fpr, tpr, thresholds = metrics.roc_curve(y, scores, pos_label=2)
roc_auc = metrics.auc(fpr, tpr)
print("fpr:", fpr)
print("tpr:", tpr)
print("thresholds:", thresholds)
# Plot all ROC curves
plt.figure()
lw = 2
plt.plot(fpr, tpr, color='darkorange',
lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.02])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
输出:
fpr: [0. 0. 0.5 0.5 1. ]
tpr: [0. 0.5 0.5 1. 1. ]
thresholds: [1.8 0.8 0.4 0.35 0.1 ]
image.png
说明:
该示例有4个样本,参数说明如下:
- y:样本的真值
- pos_label=2:表明取值为2的样本是正样本。
- scores:预测出的某样本是正样本的概率。
- fpr、tpr:每个(fpr[i], tpr[i])都表示ROC曲线上的一个点,一共求解出了4个点。
- thresholds:求解(fpr[i], tpr[i])时使用的阈值。
求解步骤:
可以看出,阈值thresholds就是对概率scores进行了排序(倒序)。不断改变阈值,得到ROC曲线上不同的点。步骤如下:
- threshold取1.8(=1.0+0.8):也就是说预测概率大于等于1.8时,我们将样本预测为正样本。那么4个样本的预测结果为[1, 1, 1, 1]。负样本全部预测正确,正样本全部预测错误。从而得到ROC曲线上一个点(0, 0)
- threshold取0.8:也就是说预测概率大于等于0.8时,我们将样本预测为正样本。那么4个样本的预测结果为[1, 1, 1, 2]。负样本全部预测正确,正样本一个预测正确。从而得到ROC曲线上一个点(0, 0.5)
- threshold取0.4:预测概率大于等于0.4时,认为是正样本。预测结果为[1, 2, 1, 2]。负样本一个预测错误,正样本一个预测正确,从而得到ROC上面的(0.5, 0.5)点。
- threshold取0.35:预测概率大于等于0.35时,认为是正样本。得到预测结果[1, 2, 2, 2]。负样本一个预测错误,正样本全部预测正确,从而得到(0.5, 1)
- threshold取0.1:预测大于等于0.1时,就认为是正样本。尽管召回率很高,但预测结果再次变差,把所有样本都预测为了正样本,从而得到(1, 1)点。
1.3.1 二分类ROC曲线
删除IRIS数据集中第三类数据,利用二分类进行分类:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
# ----------------------
# 一、加载数据
# ----------------------
iris = datasets.load_iris()
dataX = iris.data
dataY = iris.target
# 去掉第三类,变为2分类
dataX, dataY = dataX[dataY != 2], dataY[dataY != 2]
# 添加一些噪音特征,将原始4维特征变为804维特征
random_state = np.random.RandomState(0)
n_samples, n_features = dataX.shape
dataX = np.c_[dataX, random_state.randn(n_samples, 200 * n_features)]
# 构建训练集和测试集
trainX, testX, trainY, testY = train_test_split(dataX, dataY, test_size=.3, random_state=0)
# ----------------------
# 二、构建SVM分类模型:
# 计算roc值,可以使用有decision_function方法的评估器来计算,也可以使用predict_proba来计算
# ----------------------
svm = svm.SVC(kernel='linear', probability=True, random_state=random_state)
svm.fit(trainX, trainY)
# y_score = svm.predict_proba(testX)[:, 1]
y_score = svm.decision_function(testX)
# 计算真正类的 ROC curve 和 ROC area
fpr, tpr, threshold = roc_curve(testY, y_score, pos_label=1)
roc_auc = auc(fpr, tpr)
# ----------------------
# 二、绘制ROC曲线图
# ----------------------
plt.figure()
lw = 1
plt.plot(fpr, tpr, color='darkorange', lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.02])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
输出:
image.png
说明:二分类只显示真正类的ROC曲线。
1.3.2 多分类ROC曲线
多分类求解每一类时都分别按照每个类划分为若干个子类,从而求解混淆矩阵。
”’python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
from scipy import interp
def plotMulticlassROC(testY, predProb, class_name=[], microFlag=True, macroFlag=True):
“””
绘制ROC曲线
:param testY: 真实类别one-hot矢量矩阵:[n_samples,n_classes]
:param predProb: 预测类别概率矢量矩阵:[n_samples,n_classes]
:param microFlag: True表示绘制micro-average,False表示不绘制
:param macroFlag: True表示绘制macro-average,False表示不绘制
:return: None
“””
# 计算各个类的ROC曲线和面积
n_class = testY.shape[1]
if class_name == [] or len(class_name) != n_class:
class_name = [it for it in range(n_class)]
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_class):
fpr[i], tpr[i], _ = roc_curve(testY[:, i], predProb[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
# 绘制每一个子类
cmap = plt.get_cmap('gnuplot')
# colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
colors = [cmap(i) for i in np.linspace(0.1, 0.9, n_class)]
lw = 1
for i, color in zip(range(n_class), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.4f})'
''.format(class_name[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])
# 计算 micro-average ROC 曲线和面积
if microFlag:
fpr["micro"], tpr["micro"], _ = roc_curve(testY.ravel(), predProb.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])
# 绘制 micro-average
plt.plot(fpr["micro"], tpr["micro"],
label='micro-average ROC curve (area = {0:0.4f})'
''.format(roc_auc["micro"]),
color='deeppink', linestyle=':', linewidth=2)
# 计算 macro-average ROC 曲线和面积
if macroFlag:
# 聚合所有的FPR
all_fpr = np.unique(np.concatenate([fpr[i] for i in range(n_class)]))
# Then interpolate all ROC curves at this points
mean_tpr = np.zeros_like(all_fpr)
for i in range(n_class):
mean_tpr += interp(all_fpr, fpr[i], tpr[i])
# Finally average it and compute AUC
mean_tpr /= n_class
fpr["macro"] = all_fpr
tpr["macro"] = mean_tpr
roc_auc["macro"] = auc(fpr["macro"], tpr["macro"])
plt.plot(fpr["macro"], tpr["macro"],
label='macro-average ROC curve (area = {0:0.4f})'
''.format(roc_auc["macro"]),
color='navy', linestyle=':', linewidth=2)
plt.xticks(np.arange(0, 1.1, 0.1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic to multi-class')
plt.legend(loc="lower right")
plt.show()
if name == ‘main‘:
from sklearn import svm, datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
# ---------------------------
# 加载数据
# ---------------------------
iris = datasets.load_iris()
X = iris.data
y = iris.target
# 转换为one-hot矢量
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]
# 添加噪声特征,将原始3维特征扩展为63维特征
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
trainX, testX, trainY, testY = train_test_split(X, y, test_size=.5, random_state=0)
# ---------------------------
# 构建分类器
# ---------------------------
# Learn to predict each class against the other
clf = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,
random_state=random_state))
clf.fit(trainX, trainY)
predProb = clf.decision_function(testX)
# predProb = clf.predict_proba(testX)
class_name = ["iris_1", "iris_2", "iris_3"]
plotMulticlassROC(testY, predProb, class_name)
”’
输出:
image.png
https://www.jianshu.com/p/a2a4919b2c87
Python量化投资网携手4326手游为资深游戏玩家推荐:《《神都夜行录》:【维护公告】10月10日维护公告:枫染秋飒霜夜行,犹记初逢照影来!》