我有超过50万对真实标签和预测分数(每个1d阵列的长度变化,长度可以在10,000-30,000之间),我需要计算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计算,以便可以跨多行广播。
答案 0 :(得分:1)
有更快/更好的方法吗?
由于每个true / pred对的计算是独立的(如果我理解你的设置),你应该能够通过使用multiprocessing
来减少总处理时间,从而有效地并行化计算:
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_async
映射所有true / pred对并调用roc
函数,一次传递一对。发送索引以映射结果。
如果true / pred对太大而不能序列化并发送到进程,则可能需要在调用roc
之前将数据写入某个外部数据结构,只传递引用i
并在处理前从true[i]/pred[i]
内读取每对roc
的数据。
Pool自动管理进程的安排。为了降低内存耗尽的风险,您可能需要传递Pool(...., maxtasksperchild=1)
参数,该参数将为每个true / pred对启动一个新进程(根据您的需要选择任何其他数字)。
<强>更新强>
我被困在只有两个处理器的机器上
自然这是一个限制因素。但是,考虑到以非常合理的成本获得云计算资源,您只需支付实际需要的时间,您可能需要在花费数小时优化可以如此有效并行化的计算之前考虑硬件中的替代方案。真的,这本身就是奢侈品。
答案 1 :(得分:0)
找到一种更好的方法来矢量化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)
...
您可以通过分析这些功能并删除可以提前更有效地应用的操作来优化此功能。快速分析缩放到5M行的示例输入可以发现一些潜在的瓶颈(标记为>>>
):
# your for ... loop wrapped in function roc()
%prun -s cumulative roc
722 function calls (718 primitive calls) in 5.005 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 5.005 5.005 <string>:1(<module>)
1 0.000 0.000 5.005 5.005 <ipython-input-51-27e30c04d997>:1(roc)
2 0.050 0.025 5.004 2.502 ranking.py:417(roc_curve)
2 0.694 0.347 4.954 2.477 ranking.py:256(_binary_clf_curve)
>>>2 0.000 0.000 2.356 1.178 fromnumeric.py:823(argsort)
>>>2 2.356 1.178 2.356 1.178 {method 'argsort' of 'numpy.ndarray' objects}
6 0.062 0.010 0.961 0.160 arraysetops.py:96(unique)
>>>6 0.750 0.125 0.750 0.125 {method 'sort' of 'numpy.ndarray' objects}
>>>2 0.181 0.090 0.570 0.285 numeric.py:2281(isclose)
2 0.244 0.122 0.386 0.193 numeric.py:2340(within_tol)
2 0.214 0.107 0.214 0.107 {method 'cumsum' of 'numpy.ndarray' objects}