在scikit中,您可以使用
计算二元分类器的曲线下面积roc_auc_score( Y, clf.predict_proba(X)[:,1] )
我只对假阳性率小于0.1的曲线部分感兴趣。
考虑到这样的阈值误报率,我该如何计算AUC 只有曲线部分达到阈值?
以下是几个ROC曲线的示例,例如:
scikit learn docs展示了如何使用roc_curve
>>> import numpy as np
>>> 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)
>>> fpr
array([ 0. , 0.5, 0.5, 1. ])
>>> tpr
array([ 0.5, 0.5, 1. , 1. ])
>>> thresholds
array([ 0.8 , 0.4 , 0.35, 0.1 ]
有一种简单的方法可以从这个到AUC吗?
似乎唯一的问题是如何在fpr = 0.1时计算tpr值,因为roc_curve并不一定能给你这个。
答案 0 :(得分:7)
假设我们从
开始import numpy as np
from sklearn import metrics
现在我们设置真y
和预测scores
:
y = np.array([0, 0, 1, 1])
scores = np.array([0.1, 0.4, 0.35, 0.8])
(注意y
已经从问题中减少了1。这是无关紧要的:无论是预测1,2还是0,1,都可以获得完全相同的结果(fpr,tpr,阈值等),但是如果不使用0,1,则一些sklearn.metrics
函数是拖动。)
让我们来看看AUC:
>>> metrics.roc_auc_score(y, scores)
0.75
如你的例子所示:
fpr, tpr, thresholds = metrics.roc_curve(y, scores)
>>> fpr, tpr
(array([ 0. , 0.5, 0.5, 1. ]), array([ 0.5, 0.5, 1. , 1. ]))
这给出了以下图:
plot([0, 0.5], [0.5, 0.5], [0.5, 0.5], [0.5, 1], [0.5, 1], [1, 1]);
通过构造,有限长度 y 的ROC将由矩形组成:
对于足够低的阈值,所有内容都将被归类为否定。
随着阈值持续增加,在离散点,一些负面分类将变为正数。
因此,对于有限 y ,ROC将始终以一系列连接的水平和垂直线为特征,从(0,0)到 (1,1)。
AUC是这些矩形的总和。这里,如上所示,AUC是0.75,因为矩形具有0.5 * 0.5 + 0.5 * 1 = 0.75的面积。
在某些情况下,人们选择通过线性插值计算AUC。假设 y 的长度远大于为FPR和TPR计算的实际点数。然后,在这种情况下,线性插值是可能之间的点的近似值。在某些情况下,人们也会遵循猜想,如果 y 足够大,则两者之间的点将被线性插值。 sklearn.metrics
不使用这个猜想,为了得到与sklearn.metrics
一致的结果,有必要使用矩形,而不是梯形求和。
让我们自己编写函数来直接从fpr
和tpr
计算AUC:
import itertools
import operator
def auc_from_fpr_tpr(fpr, tpr, trapezoid=False):
inds = [i for (i, (s, e)) in enumerate(zip(fpr[: -1], fpr[1: ])) if s != e] + [len(fpr) - 1]
fpr, tpr = fpr[inds], tpr[inds]
area = 0
ft = zip(fpr, tpr)
for p0, p1 in zip(ft[: -1], ft[1: ]):
area += (p1[0] - p0[0]) * ((p1[1] + p0[1]) / 2 if trapezoid else p0[1])
return area
此函数采用FPR和TPR,以及一个可选参数,说明是否使用梯形求和。运行它,我们得到:
>>> auc_from_fpr_tpr(fpr, tpr), auc_from_fpr_tpr(fpr, tpr, True)
(0.75, 0.875)
对于矩形求和,我们得到与sklearn.metrics
相同的结果,对于梯形求和得到不同的更高的结果。
所以,现在我们只需看看如果我们以0.1的FPR终止,FPR / TPR点会发生什么。我们可以使用bisect
module
import bisect
def get_fpr_tpr_for_thresh(fpr, tpr, thresh):
p = bisect.bisect_left(fpr, thresh)
fpr = fpr.copy()
fpr[p] = thresh
return fpr[: p + 1], tpr[: p + 1]
这是如何工作的?它只是检查thresh
中fpr
的插入点的位置。给定FPR的属性(它必须从0开始),插入点必须在水平线上。因此,在此之前的所有矩形都应该不受影响,应该删除此之后的所有矩形,并且应该缩短这个矩形。
让我们应用它:
fpr_thresh, tpr_thresh = get_fpr_tpr_for_thresh(fpr, tpr, 0.1)
>>> fpr_thresh, tpr_thresh
(array([ 0. , 0.1]), array([ 0.5, 0.5]))
最后,我们只需要从更新版本中计算出AUC:
>>> auc_from_fpr_tpr(fpr, tpr), auc_from_fpr_tpr(fpr, tpr, True)
0.050000000000000003, 0.050000000000000003)
在这种情况下,矩形和梯形求和都给出相同的结果。请注意,一般情况下,他们不会。为了与sklearn.metrics
保持一致,应使用第一个。
答案 1 :(得分:2)
我实施了目前最好的答案,并没有在所有情况下都给出正确的结果。我重新实现并测试了下面的实现。我还利用了内置的梯形AUC功能,而不是从头开始重新创建。
def line(x_coords, y_coords):
"""
Given a pair of coordinates (x1,y2), (x2,y2), define the line equation. Note that this is the entire line vs. t
the line segment.
Parameters
----------
x_coords: Numpy array of 2 points corresponding to x1,x2
x_coords: Numpy array of 2 points corresponding to y1,y2
Returns
-------
(Gradient, intercept) tuple pair
"""
if (x_coords.shape[0] < 2) or (y_coords.shape[0] < 2):
raise ValueError('At least 2 points are needed to compute'
' area under curve, but x.shape = %s' % p1.shape)
if ((x_coords[0]-x_coords[1]) == 0):
raise ValueError("gradient is infinity")
gradient = (y_coords[0]-y_coords[1])/(x_coords[0]-x_coords[1])
intercept = y_coords[0] - gradient*1.0*x_coords[0]
return (gradient, intercept)
def x_val_line_intercept(gradient, intercept, x_val):
"""
Given a x=X_val vertical line, what is the intersection point of that line with the
line defined by the gradient and intercept. Note: This can be further improved by using line
segments.
Parameters
----------
gradient
intercept
Returns
-------
(x_val, y) corresponding to the intercepted point. Note that this will always return a result.
There is no check for whether the x_val is within the bounds of the line segment.
"""
y = gradient*x_val + intercept
return (x_val, y)
def get_fpr_tpr_for_thresh(fpr, tpr, thresh):
"""
Derive the partial ROC curve to the point based on the fpr threshold.
Parameters
----------
fpr: Numpy array of the sorted FPR points that represent the entirety of the ROC.
tpr: Numpy array of the sorted TPR points that represent the entirety of the ROC.
thresh: The threshold based on the FPR to extract the partial ROC based to that value of the threshold.
Returns
-------
thresh_fpr: The FPR points that represent the partial ROC to the point of the fpr threshold.
thresh_tpr: The TPR points that represent the partial ROC to the point of the fpr threshold
"""
p = bisect.bisect_left(fpr, thresh)
thresh_fpr = fpr[:p+1].copy()
thresh_tpr = tpr[:p+1].copy()
g, i = line(fpr[p-1:p+1], tpr[p-1:p+1])
new_point = x_val_line_intercept(g, i, thresh)
thresh_fpr[p] = new_point[0]
thresh_tpr[p] = new_point[1]
return thresh_fpr, thresh_tpr
def partial_auc_scorer(y_actual, y_pred, decile=1):
"""
Derive the AUC based of the partial ROC curve from FPR=0 to FPR=decile threshold.
Parameters
----------
y_actual: numpy array of the actual labels.
y_pred: Numpy array of The predicted probability scores.
decile: The threshold based on the FPR to extract the partial ROC based to that value of the threshold.
Returns
-------
AUC of the partial ROC. A value that ranges from 0 to 1.
"""
y_pred = list(map(lambda x: x[-1], y_pred))
fpr, tpr, _ = roc_curve(y_actual, y_pred, pos_label=1)
fpr_thresh, tpr_thresh = get_fpr_tpr_for_thresh(fpr, tpr, decile)
return auc(fpr_thresh, tpr_thresh)
答案 2 :(得分:1)
这取决于FPR是 x -axis还是 y -axis(独立或因变量)。
如果它是 x ,计算是微不足道的:只计算范围[0.0,0.1]。
如果 y ,则首先需要解决 y = 0.1 的曲线。这会将x轴划分为需要计算的区域,以及高度为0.1的简单矩形区域。
为了说明,假设您在两个范围内找到超过0.1的函数:[x1,x2]和[x3,x4]。计算曲线下面积
的面积[0, x1]
[x2, x3]
[x4, ...]
为此,在找到的两个区间内添加y = 0.1下的矩形:
area += (x2-x1 + x4-x3) * 0.1
这就是你需要的东西吗?
答案 3 :(得分:1)
仅在[0.0,0.1]范围内计算fpr和tpr值。
然后,您可以使用numpy.trapz评估部分AUC(pAUC),如下所示:
pAUC = numpy.trapz(tpr_array, fpr_array)
此函数使用复合梯形法则来评估曲线下的面积。
答案 4 :(得分:1)
Python sklearn roc_auc_score()
现在允许您设置max_fpr
。您可以设置max_fpr=0.1
,该函数将为您计算AUC。 https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html
答案 5 :(得分:0)
@eleanora认为你使用sklearn的通用metrics.auc方法的冲动是正确的(这就是我所做的)。获得tpr和fpr点集后应该很简单(并且可以使用scipy的插值方法逼近任一系列中的精确点)。