sklearn或python中更快的AUC

sklearn或python中更快的AUC,python,scikit-learn,data-science,auc,Python,Scikit Learn,Data Science,Auc,我有超过50万对真实标签和预测分数(每个1d数组的长度不同,长度可能在10000-30000之间),我需要计算AUC。现在,我有一个for循环调用: # Simple Example with two pairs of true/predicted values instead of 500,000 from sklearn import metrics import numpy as np pred = [None] * 2 pred[0] = np.array([3,2,1]) pred[

我有超过50万对真实标签和预测分数(每个1d数组的长度不同,长度可能在10000-30000之间),我需要计算AUC。现在,我有一个for循环调用:

# Simple Example with two pairs of true/predicted values instead of 500,000
from sklearn import metrics
import numpy as np

pred = [None] * 2
pred[0] = np.array([3,2,1])
pred[1] = np.array([15,12,14,11,13])

true = [None] * 2
true[0] = np.array([1,0,0])
true[1] = np.array([1,1,1,0,0])

for i in range(2):
    fpr, tpr, thresholds = metrics.roc_curve(true[i], pred[i])
    print metrics.auc(fpr, tpr)
然而,处理整个数据集并计算每个真实/预测对的AUC大约需要1-1.5小时。有没有更快/更好的方法

更新

每个500k条目都可以具有形状(1,10k+)。我知道我可以把它并行化,但我被困在一台只有两个处理器的机器上,所以我的时间实际上只能有效地减少到30-45分钟,这还是太长了。我发现AUC计算本身很慢,希望找到一种比sklearn更快的AUC算法。或者,至少,找到一种更好的方法对AUC计算进行矢量化,以便它可以跨多行广播

有没有更快/更好的方法

由于每个true/pred对的计算都是独立的(如果我了解您的设置),您应该能够通过使用有效地并行计算来减少总处理时间:

import multiprocessing as mp

def roc(v):
    """ calculate one pair, return (index, auc) """
    i, true, pred = v
    fpr, tpr, thresholds = metrics.roc_curve(true, pred, drop_intermediate=True)
    auc = metrics.auc(fpr, tpr)
    return i, auc

pool = mp.Pool(3) 
result = pool.map_async(roc, ((i, true[i], pred[i]) for i in range(2)))
pool.close()
pool.join()
print result.get()
=>
[(0, 1.0), (1, 0.83333333333333326)]
这里
Pool(3)
创建一个包含3个进程的池,
.map\u async
映射所有true/pred对,并调用
roc
函数,一次传递一对。索引将被发送以映射回结果

如果true/pred对太大,无法序列化并发送到进程,则在调用
roc
之前,您可能需要将数据写入一些外部数据结构,只传递引用
i
,并在处理之前从
roc
中读取每对
true[i]/pred[i]
的数据

自动管理进程的调度。为了降低内存占用的风险,您可能需要传递
池(..,maxstasksperchild=1)
参数,该参数将为每个true/pred对启动一个新进程(根据需要选择任何其他数字)

更新

我被困在一台只有两个处理器的机器上

这自然是一个限制因素。然而,考虑到云计算资源的可用性非常合理,你只需要支付你实际需要的时间,你可能需要在硬件上考虑替代方案,然后再花上几个小时优化一个可以如此有效地并行化的计算。这本身就是一种奢侈,真的

有没有更快/更好的方法

由于每个true/pred对的计算都是独立的(如果我了解您的设置),您应该能够通过使用有效地并行计算来减少总处理时间:

import multiprocessing as mp

def roc(v):
    """ calculate one pair, return (index, auc) """
    i, true, pred = v
    fpr, tpr, thresholds = metrics.roc_curve(true, pred, drop_intermediate=True)
    auc = metrics.auc(fpr, tpr)
    return i, auc

pool = mp.Pool(3) 
result = pool.map_async(roc, ((i, true[i], pred[i]) for i in range(2)))
pool.close()
pool.join()
print result.get()
=>
[(0, 1.0), (1, 0.83333333333333326)]
这里
Pool(3)
创建一个包含3个进程的池,
.map\u async
映射所有true/pred对,并调用
roc
函数,一次传递一对。索引将被发送以映射回结果

如果true/pred对太大,无法序列化并发送到进程,则在调用
roc
之前,您可能需要将数据写入一些外部数据结构,只传递引用
i
,并在处理之前从
roc
中读取每对
true[i]/pred[i]
的数据

自动管理进程的调度。为了降低内存占用的风险,您可能需要传递
池(..,maxstasksperchild=1)
参数,该参数将为每个true/pred对启动一个新进程(根据需要选择任何其他数字)

更新

我被困在一台只有两个处理器的机器上

这自然是一个限制因素。然而,考虑到云计算资源的可用性非常合理,你只需要支付你实际需要的时间,你可能需要在硬件上考虑替代方案,然后再花上几个小时优化一个可以如此有效地并行化的计算。这本身就是一种奢侈,真的

找到更好的方法对AUC计算进行矢量化,以便它可以跨多行广播

可能不会-sklearn已经使用有效的numpy操作来计算相关部分:

# -- calculate tps, fps, thresholds
# sklearn.metrics.ranking:_binary_clf_curve()
(...)
distinct_value_indices = np.where(np.logical_not(isclose(
        np.diff(y_score), 0)))[0]
threshold_idxs = np.r_[distinct_value_indices, y_true.size - 1]
# accumulate the true positives with decreasing threshold
tps = (y_true * weight).cumsum()[threshold_idxs]
if sample_weight is not None:
    fps = weight.cumsum()[threshold_idxs] - tps
else:
    fps = 1 + threshold_idxs - tps
return fps, tps, y_score[threshold_idxs]

# -- calculate auc
# sklearn.metrics.ranking:auc()
...
area = direction * np.trapz(y, x)
...
您可以通过分析这些函数并删除可以事先更有效地应用的操作来优化这一点。对扩展到500万行的示例输入进行快速分析,可以发现一些潜在的瓶颈(标记为
>
):

#您的。。。函数roc()中包装的循环
%prun-s累积roc
在5.005秒内进行722次函数调用(718次基本调用)
排序人:累计时间
ncalls tottime percall cumtime percall文件名:lineno(函数)
1    0.000    0.000    5.005    5.005 :1()
1 0.000 0.000 5.005 5.005:1(roc)
2 0.050.025 5.004 2.502排名。py:417(roc_曲线)
2 0.694 0.347 4.954 2.477排名。py:256(二元曲线)
>>>2 0.000 0.000 2.356 1.178 fromnumeric.py:823(argsort)
>>>2.356 1.178 2.356 1.178{“numpy.ndarray”对象的“argsort”方法}
6 0.062 0.010 0.961 0.160阵列顶部。py:96(唯一)
>>>6 0.750 0.125 0.750 0.125{“numpy.ndarray”对象的“排序”方法}
>>>2 0.181 0.090 0.570 0.285数字。py:2281(isclose)
2 0.244 0.122 0.386 0.193数字。py:2340(不超过)
2 0.214 0.107 0.214 0.107{“numpy.ndarray”对象的方法“cumsum”}
找到更好的方法对AUC计算进行矢量化,以便它可以跨多行广播

可能不会-sklearn已经使用有效的numpy操作来计算相关部分:

# -- calculate tps, fps, thresholds
# sklearn.metrics.ranking:_binary_clf_curve()
(...)
distinct_value_indices = np.where(np.logical_not(isclose(
        np.diff(y_score), 0)))[0]
threshold_idxs = np.r_[distinct_value_indices, y_true.size - 1]
# accumulate the true positives with decreasing threshold
tps = (y_true * weight).cumsum()[threshold_idxs]
if sample_weight is not None:
    fps = weight.cumsum()[threshold_idxs] - tps
else:
    fps = 1 + threshold_idxs - tps
return fps, tps, y_score[threshold_idxs]

# -- calculate auc
# sklearn.metrics.ranking:auc()
...
area = direction * np.trapz(y, x)
...
您可以通过分析这些函数并删除可以事先更有效地应用的操作来优化这一点。