接收器操作特性 (ROC) 和曲线下面积 (AUC) 是众所周知的概念。我反复使用它们(使用 scikit-learn 之类的库),但从未真正学会如何实现它们。
想到的显而易见的实现是:固定步长 delta,将 0 - 1 的区间除以 delta,对于所有这些阈值,计算 TPR 和 FPR。
从 https://developers.google.com/machine-learning/crash-course/classification/roc-and-auc 中,我了解到“为了计算 ROC 曲线中的点,我们可以使用不同的分类阈值多次评估逻辑回归模型,但这将是低效的。幸运的是,有一种高效的排序可以为我们提供这些信息的基于算法的算法,称为 AUC。” - 这让我想到,对于大量样本,使用哪些算法进行有效的 ROC/AUC 计算?这种高效算法的时间复杂度是多少?
答案 0 :(得分:2)
因此,我研究了 scikit-learn
的实现。我将在这里尝试解释算法。
让我们考虑官方示例:
>>> 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. , 0.5, 0.5, 1. ])
>>> tpr
array([0. , 0.5, 0.5, 1. , 1. ])
>>> thresholds
array([1.8 , 0.8 , 0.4 , 0.35, 0.1 ])
第 1 步:首先要决定的是我们需要多少个阈值点?
scores = [0.1, 0.4, 0.35, 0.8]
,如果我们在 0.35 和 0.4 之间选择一个点,它不会在 ROC 曲线上添加任何新点(与 0.4 相同)。我们可以通过仅选择唯一的阈值(集合)来进一步减少阈值的数量。我们还可以删除任何共线点。复杂度:O(n)
第 2 步:如何计算 TPR 和 FPR?
我们当然可以计算 TPR 和 FPR,方法是考虑每个阈值并计算超过该点的分数,并检查它们的真实标签。
现在,这将是 O(N^2)
。
但是我们可以使用贪婪的方法来提高效率。如果我们对分数数组进行排序会发生什么?
y_score = [0.8, 0.4, 0.35, 0.1]
y_true = [1, 0, 1, 0] # converted to binary
现在,如果我们迭代 y_score
,对于 0.8
,如果我们有 y_true = 1
,那么真正的正数将为 1,因为只有 1 个真正的标签是 {{ 1}}。如果我们移动到 0.4,我们知道 >= 0.8
但对于 0.4,标签是假的,所以仍然,真阳性计数为 1,在 0.35,我们有 0.35 和 0.4 和 0.8 >= 0.35,并且有 2 个真标签,这意味着真正的正数是 2。
现在,我们可以很容易地用累积和来计算。
0.8 and 0.4 >= 0.4
我们可以通过最后一个元素 TPC = [1, 1, 2, 2]
对其进行标准化以获得 TPR。
TPC[-1]
这与 scikit-learn 的输出相同。额外的 TPR = [0.5, 0.5, 1, 1]
阈值用于确保 ROC 从 (0, 0) 开始。
同样,我们可以用 1 + max(score)
计算误报数。
所以,总时间复杂度:1 + index - true positive count
(用于排序)