在 sklearn 中使用 Leave-One-Out 交叉验证的 ROC 曲线

Posted

技术标签:

【中文标题】在 sklearn 中使用 Leave-One-Out 交叉验证的 ROC 曲线【英文标题】:ROC curve with Leave-One-Out Cross validation in sklearn 【发布时间】:2020-01-05 11:35:08 【问题描述】:

我想使用leave-one-out cross validation绘制分类器的ROC曲线

好像有人问过here类似的问题,但没有任何答案。

在另一个问题here 中表示:

为了通过 LeaveOneOut 获得有意义的 ROC AUC,您需要 计算每个折叠的概率估计值(每个折叠只包含 一个观察),然后计算所有这些集合上的 ROC AUC 概率估计。

此外,在官方 scikit-learn 网站上也有一个类似的示例,但使用了 KFold 交叉验证 (https://scikit-learn.org/stable/auto_examples/model_selection/plot_roc_crossval.html#sphx-glr-auto-examples-model-selection-plot-roc-crossval-py)。


所以对于留一法交叉验证案例,我正在考虑收集测试集上的所有概率预测(当时一个样本),并在获得所有预测概率之后我的折叠,计算和绘制 ROC 曲线。

这看起来可以吗?我没有看到任何其他方法可以实现我的目标。

这是我的代码:

from sklearn.svm import SVC
import numpy as np, matplotlib.pyplot as plt,  pandas as pd
from sklearn.model_selection import cross_val_score,cross_val_predict,  KFold,  LeaveOneOut, StratifiedKFold
from sklearn.metrics import roc_curve, auc
from sklearn import datasets

# Import some data to play with
iris = datasets.load_iris()
X_svc = iris.data
y = iris.target
X_svc, y = X_svc[y != 2], y[y != 2]

clf = SVC(kernel='linear', class_weight='balanced', probability=True, random_state=0)
kf = LeaveOneOut()

all_y = []
all_probs=[]
for train, test in kf.split(X_svc, y):
    all_y.append(y[test])
    all_probs.append(clf.fit(X_svc[train], y[train]).predict_proba(X_svc[test])[:,1])
all_y = np.array(all_y)
all_probs = np.array(all_probs)

fpr, tpr, thresholds = roc_curve(all_y,all_probs)
roc_auc = auc(fpr, tpr)
plt.figure(1, figsize=(12,6))
plt.plot(fpr, tpr, lw=2, alpha=0.5, label='LOOCV ROC (AUC = %0.2f)' % (roc_auc))
plt.plot([0, 1], [0, 1], linestyle='--', lw=2, color='k', label='Chance level', alpha=.8)
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.grid()
plt.show()

【问题讨论】:

【参考方案1】:

我相信代码是正确的,拆分也是。为了验证实现和结果,我添加了几行代码:

from sklearn.model_selection import cross_val_score,cross_val_predict,  KFold,  LeaveOneOut, StratifiedKFold
from sklearn.metrics import roc_curve, auc
from sklearn import datasets

# Import some data to play with
iris = datasets.load_iris()
X_svc = iris.data
y = iris.target
X_svc, y = X_svc[y != 2], y[y != 2]

clf = SVC(kernel='linear', class_weight='balanced', probability=True, random_state=0)
kf = LeaveOneOut()
if kf.get_n_splits(X_svc) == len(X_svc):
    print("They are the same length, splitting correct")
else:
    print("Something is wrong")
all_y = []
all_probs=[]
for train, test in kf.split(X_svc, y):
    all_y.append(y[test])
    all_probs.append(clf.fit(X_svc[train], y[train]).predict_proba(X_svc[test])[:,1])
all_y = np.array(all_y)
all_probs = np.array(all_probs)
#print(all_y) #For validation 
#print(all_probs) #For validation

fpr, tpr, thresholds = roc_curve(all_y,all_probs)
print(fpr, tpr, thresholds) #For validation
roc_auc = auc(fpr, tpr)
plt.figure(1, figsize=(12,6))
plt.plot(fpr, tpr, lw=2, alpha=0.5, label='LOOCV ROC (AUC = %0.2f)' % (roc_auc))
plt.plot([0, 1], [0, 1], linestyle='--', lw=2, color='k', label='Chance level', alpha=.8)
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.grid()
plt.show()

If 行仅用于确保拆分为n 次,其中n 是给定数据集的观察次数。这是因为正如文档所述,LeaveOneOut 与Kfold(n_splits=n) and LeaveOneOut(p=1) 的工作方式相同。 同样,在打印预测的概率值时,它们也很好,可以理解曲线。恭喜你的 1.00AUC!

【讨论】:

以上是关于在 sklearn 中使用 Leave-One-Out 交叉验证的 ROC 曲线的主要内容,如果未能解决你的问题,请参考以下文章

在安卓设备中使用 sklearn

在 Python 中使用 sklearn 使用 MAE 训练线性模型

sklearn中SVM的实现

使用 sklearn 在嵌套交叉验证中使用 GroupKFold

在 sklearn 中使用 DictVectorizer 后如何获得分类特征的重要性

使用 sklearn 在数据中保持零