比numpy.where更节省内存的选项是什么?

4

我有一个非常大的数组(包含数百万个元素),我需要根据几个不同的条件选取其中的一小部分(几百个)。目前我正在使用 np.where,类似于:

for threshold in np.arange(0,1,.1):
    x=np.random.random(5000000)
    y=np.random.random(5000000)
    z=np.random.random(5000000)
    inds=np.where((x < threshold) & (y > threshold) & (z > threshold) & (z < threshold+0.1))

DoSomeJunk(a[inds], b[inds], c[inds])

然后稍后使用ipts从各种数组中提取正确的点。 但是,在np.where行上,我遇到了MemoryError。 我已经在几篇其他相关帖子中看到过np.where可能会占用内存并复制数据的情况。
在那里有多个&符号是否意味着数据被多次复制?有没有更有效的方法来切片数据,既减少内存压力,又保留我想要的索引列表,以便我可以将相同的切片在以后的多个位置中使用?
请注意,我发布的这个示例实际上不会生成错误,但结构类似于我所拥有的。

1
尝试使用np.logical_and并将结果应用于它,以便仅基于此获取一个小子集:-- your_array [np.logical_and(iens < maxe, iangsdet_ofst > (11.25 * azpt), iangsdet_ofst < (11.25 * (azpt + 1))] - Youcef Benyettou
不同数组的形状是什么(iensazpt,...)?一种选择是批处理操作,取大数组的切片并相应地移动 np.where 的结果。此外,您可以考虑使用 Numba 加速循环代替向量化操作,尽管您事先不知道结果数量。 - jdehesa
从名称上看不清楚,但你使用 where 的方式并不是它的正确用法。对于你正在做的事情,numpy.nonzero 可能会提高一点性能。(这并没有真正回答你有关复制的问题,但还是想加上这句话) - Paul H
我试图稍微整理一下这个例子。这并不会真正产生内存错误,但在结构上与我实际代码中的情况类似... - Alex
1
(x<.3) 会生成一个与 x 形状相同的布尔数组。(x<.3)&(y<.3) 将产生一个新的布尔数组,其形状取决于 xy 如何相互广播。因此,如果 xy 和/或 z 很大,则构建条件数组可能会占用大量内存。我认为 nonzero 本身并不会使用更多的内存 - 只需要返回其结果所需的空间即可。 - hpaulj
显示剩余2条评论
1个回答

2

在每种情况下,您都会创建一个临时的布尔数组,其大小与xyz相同。为了优化这一点,您可以迭代地创建掩码:


for threshold in np.arange(0,1,.1):
    x=np.random.random(5000000)
    y=np.random.random(5000000)
    z=np.random.random(5000000)
    inds = x < threshold
    inds &= y > threshold
    inds &= z > threshold
    inds &= z < threshold+0.1

DoSomeJunk(a[inds], b[inds], c[inds])

针对这个例子,这将把内存使用从160 MB减少到40 MB。最初的回答。

好的,那么为了澄清一下,我也可以使用 inds = np.where(inds & (the next check)) 来迭代嵌套 wheres,并且这样做会更节省内存吗?在 where 和你那里的布尔数组之间有什么具体的原因吗? - Alex
你的示例中的 np.where 调用是多余的,因为你可以使用布尔数组进行高级索引来索引一个数组。换句话说,a[inds]a[np.where(inds)] 完全等价,但后者需要创建一个新的数组。 - user545424
你可以在这里阅读更多关于布尔索引的内容:https://docs.scipy.org/doc/numpy/user/basics.indexing.html#boolean-or-mask-index-arrays。 - user545424

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接