我试图快速检查列表中有多少项低于一系列阈值,类似于这里描述的操作,但很多次都是这样。这一点是在机器学习模型上做一些诊断,比sci kit learn内置的模型(ROC曲线等)更深入一些。
想象一下,preds
是一个预测列表(概率介于0和1之间)。事实上,我将拥有超过100万个,这就是为什么我试图加快速度。
这会产生一些虚假分数,通常分布在0到1之间。
fake_preds = [np.random.normal(0, 1) for i in range(1000)]
fake_preds = [(pred + np.abs(min(fake_preds)))/max(fake_preds + np.abs(min(fake_preds))) for pred in fake_preds]
现在,我这样做的方法是循环通过100个阈值水平,并检查在任何给定阈值下有多少预测较低:
thresholds = [round(n,2) for n in np.arange(0.01, 1.0, 0.01)]
thresh_cov = [sum(fake_preds < thresh) for thresh in thresholds]
这大约需要1.5秒才能完成10公里(比生成虚假预测的时间要短),但你可以想象,如果预测的次数更多,这需要更长的时间。我需要做几千次来比较不同的模型。
有没有想过如何让第二个代码块更快?我在想,一定有一种方法可以对预测进行排序,使计算机更容易检查阈值(类似于SQL场景中的索引),但除了sum(伪preds)之外,我想不出任何其他方法
提前感谢您的帮助!
您可以在这里重新塑造阈值
以启用广播。首先,这里有一些可能的更改,以创建摆脱循环的fake_preds
和阈值
。
np.random.seed(123)
fake_preds = np.random.normal(size=1000)
fake_preds = (fake_preds + np.abs(fake_preds.min())) \
/ (np.max(fake_preds + np.abs((fake_preds.min()))))
thresholds = np.linspace(.01, 1, 100)
那么你要做的是在一行中完成:
print(np.sum(np.less(fake_preds, np.tile(thresholds, (1000,1)).T), axis=1))
[ 2 2 2 2 2 2 5 5 6 7 7 11 11 11 15 18 21 26
28 34 40 48 54 63 71 77 90 100 114 129 143 165 176 191 206 222
240 268 288 312 329 361 392 417 444 479 503 532 560 598 615 648 671 696
710 726 747 768 787 800 818 840 860 877 891 902 912 919 928 942 947 960
965 970 978 981 986 987 988 991 993 994 995 995 995 997 997 997 998 998
999 999 999 999 999 999 999 999 999 999]
演练:
fake_preds
具有形状(1000,1)。您需要将阈值
处理成与此兼容的形状。(参见一般广播规则。)
可广播的第二个形状是
print(np.tile(thresholds, (1000,1)).T.shape)
# (100, 1000)
一种方法是使用numpy。直方图
。
thresh_cov=np.histogram(fake_preds,len(阈值))
从timeit
,我得到:
%timeit my_cov = np.histogram(fake_preds, len(thresholds))[0].cumsum()
169 µs ± 6.51 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit thresh_cov = [sum(fake_preds < thresh) for thresh in thresholds]
172 ms ± 1.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
方法#1
您可以排序预测
数组,然后使用searchsorted
或np。数字化
,就像这样-
np.searchsorted(np.sort(fake_preds), thresholds, 'right')
np.digitize(thresholds, np.sort(fake_preds))
如果你不介意变异预测
数组,可以使用:伪preds进行排序。排序()
然后使用假preds
代替np。排序(假preds)
。这应该更有效,因为我们将避免使用任何额外的内存。
方法#2
现在,如果阈值是从0
到1
的100
,那么这些阈值将是0.01
的倍数。因此,我们可以简单地进行数字化,将每一个100
放大,并将其转换为ints
,这可以相当直接地作为bin
输入到np。bincount
。然后,要获得所需的结果,请使用cumsum
,如下所示-
np.bincount((fake_preds*100).astype(int),minlength=99)[:99].cumsum()
接近-
def searchsorted_app(fake_preds, thresholds):
return np.searchsorted(np.sort(fake_preds), thresholds, 'right')
def digitize_app(fake_preds, thresholds):
return np.digitize(thresholds, np.sort(fake_preds) )
def bincount_app(fake_preds, thresholds):
return np.bincount((fake_preds*100).astype(int),minlength=99)[:99].cumsum()
对10000
元素进行运行时测试和验证-
In [210]: np.random.seed(0)
...: fake_preds = np.random.rand(10000)
...: thresholds = [round(n,2) for n in np.arange(0.01, 1.0, 0.01)]
...: thresh_cov = [sum(fake_preds < thresh) for thresh in thresholds]
...:
In [211]: print np.allclose(thresh_cov, searchsorted_app(fake_preds, thresholds))
...: print np.allclose(thresh_cov, digitize_app(fake_preds, thresholds))
...: print np.allclose(thresh_cov, bincount_app(fake_preds, thresholds))
...:
True
True
True
In [214]: %timeit [sum(fake_preds < thresh) for thresh in thresholds]
1 loop, best of 3: 1.43 s per loop
In [215]: %timeit searchsorted_app(fake_preds, thresholds)
...: %timeit digitize_app(fake_preds, thresholds)
...: %timeit bincount_app(fake_preds, thresholds)
...:
1000 loops, best of 3: 528 µs per loop
1000 loops, best of 3: 535 µs per loop
10000 loops, best of 3: 24.9 µs per loop
这是searchsorted
的2700x
加速,以及bincount
的57000x
加速!对于更大的数据集,bincount
和searchsorted
之间的差距肯定会增加,因为bincount
不需要排序。
问题内容: 这是一个类似问题的后续问题,该问题询问最佳书写方式 似乎共识是关于 但是,我认为如果只删除一些项目,则大多数项目都将被复制到同一对象中,这可能很慢。在回答另一个相关问题时,有人建议: 但是,此处将搜索列表长度为O(N)的项目。可能我们的局限在于列表以数组而不是链接列表的形式表示,因此删除项目将需要在列表之后移动所有内容。但是,这里建议将collections.dequeue表示为双链表
我有一个
假设我们有一个函数,它返回100万个长度为30的整数向量,每个向量的条目都很小(比如-100到100之间)。进一步假设输出只有大约30000个唯一向量,其余是重复的。检索唯一输出向量列表的良好数据结构和算法是什么?优选地,当3%的唯一向量的比例大致恒定时,该解决方案应缩放良好。 这个问题主要是关于数据结构的,但我计划使用 STL 在 C 中实现它,所以也欢迎任何关于实现的提示。 朴素算法是存储已知
我有一个<代码>列表 Java8似乎提供了一种通过流来实现的方法。更基本的方法呢? 谢谢
问题内容: 如果我有任意顺序的卡片套装列表,如下所示: 我想返回一个没有 有没有简单的方法可以做到这一点? 问题答案: 如果您不需要单独
问题内容: 如果要尝试在列表中查找某项的索引,则可以采用几种不同的方法来完成,这就是我所知道的最快的方法 另一种方式不是pythonic且速度较慢 第一种方法无疑是更快的方法,但是如果您想更快地进行操作,那该怎么办呢?对于第一个索引使用方法 速度很快,但无法处理多个索引如何加快速度? 问题答案: 假设您想要一个列表作为输出:对于我的测试,所有选项似乎都表现出相似的时间性能,列表理解最快(几乎没有)