如何在 sklearn 中获取用于二进制分类的 roc auc

Posted

技术标签:

【中文标题】如何在 sklearn 中获取用于二进制分类的 roc auc【英文标题】:How to get roc auc for binary classification in sklearn 【发布时间】:2020-07-06 00:45:27 【问题描述】:

我有二进制分类问题,我想计算结果的 roc_auc。为此,我使用 sklearn 以两种不同的方式完成了它。我的代码如下。

代码 1:

from sklearn.metrics import make_scorer
from sklearn.metrics import roc_auc_score

myscore = make_scorer(roc_auc_score, needs_proba=True)

from sklearn.model_selection import cross_validate
my_value = cross_validate(clf, X, y, cv=10, scoring = myscore)
print(np.mean(my_value['test_score'].tolist()))

我得到的输出是0.60

代码 2:

y_score = cross_val_predict(clf, X, y, cv=k_fold, method="predict_proba")

from sklearn.metrics import roc_curve, auc
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(2):
    fpr[i], tpr[i], _ = roc_curve(y, y_score[:,i])
    roc_auc[i] = auc(fpr[i], tpr[i])
print(roc_auc)

我得到的输出是0: 0.41, 1: 0.59

我很困惑,因为我在两个代码中得到了两个不同的分数。请让我知道为什么会发生这种差异以及正确的做法是什么。

如果需要,我很乐意提供更多详细信息。

【问题讨论】:

k_fold 的值是多少?并请解释您在代码 2 中究竟要做什么。为什么 auc(roc_curve(y, y_score[:,i])) 应该给出一个有效的 AUC 值? @desertnaut 谢谢你的评论。我明白了, k_fold 值是不同的。但是,即使使用相同的 k_fold,我也会得到一些不同的值。代码 1:0.5864040216803137 和代码 2:0: 0.41393184645202347, 1: 0.5860681535479765 :) 请查看我更新的评论,并确保您实际上是在比较苹果和苹果 @desertnaut 我的第二个代码的来源来自这些 SO 问题:***.com/questions/43043271/…、***.com/questions/45641409/… 请让我知道您的想法。谢谢你:) 发布一些数据和完整的代码。在您使用的情况 1 中,cv=10,在情况 2 中使用一些 KFolds。以获得相同的结果。使用相同的数据,相同的数据预处理和相同的 sklearn 版本。 【参考方案1】:

您似乎使用了另一个答案中的部分代码,所以我想也回答这个问题。

对于二元分类情况,您有 2 个类,一个是正类。

例如查看here。 pos_label 是正类的标签。当pos_label=None时,如果y_true-1, 10, 1中,则pos_label设置为1,否则会报错..

import matplotlib.pyplot as plt
from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.multiclass import OneVsRestClassifier
from sklearn.model_selection import cross_val_predict
from sklearn.linear_model import LogisticRegression
import numpy as np

iris = datasets.load_iris()
X = iris.data
y = iris.target
mask = (y!=2)
y = y[mask]
X = X[mask,:]
print(y)
[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 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]

positive_class = 1

clf = OneVsRestClassifier(LogisticRegression())
y_score = cross_val_predict(clf, X, y, cv=10 , method='predict_proba')

fpr = dict()
tpr = dict()
roc_auc = dict()
fpr[positive_class], tpr[positive_class], _ = roc_curve(y, y_score[:, positive_class])
roc_auc[positive_class] = auc(fpr[positive_class], tpr[positive_class])
print(roc_auc)

1: 1.0

from sklearn.metrics import make_scorer
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_validate

myscore = make_scorer(roc_auc_score, needs_proba=True)

clf = OneVsRestClassifier(LogisticRegression())
my_value = cross_validate(clf, X, y, cv=10, scoring = myscore)
print(np.mean(my_value['test_score'].tolist()))
1.0

【讨论】:

我怀疑OP的2nd block中的不同结果是由于positive class的定义不同,但无法轻易证明 奈。可能是这样。 @makis 非常感谢您的回答。我发现它非常有用。我还有一个关于交叉验证的问题,我认为您可能有一些好主意来解决它。问题是:***.com/questions/60851341/… 请让我知道您对此的想法。谢谢你:) @makis 当我设置positive_class = 1 时,您的第一个代码中出现错误。我的y_bin 如下所示。 [[1], [0], [0], ..., [1]]。我得到的错误是IndexError: index 1 is out of bounds for axis 1 with size 1。只是想知道是否有办法解决这个问题。我期待着您的回音。谢谢你:) 我在块 1 中的代码中有一个类型。现在它已修复。

以上是关于如何在 sklearn 中获取用于二进制分类的 roc auc的主要内容,如果未能解决你的问题,请参考以下文章

sklearn 多类 svm 函数

如何在 Sklearn 的随机森林分类器中将训练模型用于另一个数据集?

当预测变量不是二进制时,Sklearn 朴素贝叶斯伯努利分类器如何工作?

sklearn 除了文本之外的其他输入用于文本分类

sklearn 多类 roc auc 分数

如何在 sklearn 中对不平衡数据集执行交叉验证