使用NumPy遮蔽数组实现高效的内存利用

3
我有一个庞大的ndarray(大约是(1e3, 1e3, 1e3)),我想对进行操作,包括但不限于对第0轴的特定元素进行操作(对于第1和第2轴的每个元素)。也就是说,有(1e3, 1e3)个元素,我希望在某些时候屏蔽它们或剔除它们。
最简单的做法是构造一个掩码数组,例如:
Z = np.zeros_like(X, dtype=bool)
# assume `inds` is some indexing array which will target
#    the particular (1e3 x 1e3) elements I'm interested in
Z[inds] = True
Y = np.ma.masked_array(X, mask=Z)

但是这样会额外使用1GB的内存来构建掩码数组。 有没有办法在不构建第二个 10^9 元素的掩码数组的情况下完成这个任务呢?例如,是否可以为掩码构建一个稀疏矩阵?


1
不行;scipy.sparse没有实现任何掩码功能。同时,np.ma不能使用sparse矩阵。请注意,np.ma在计算时,会将掩码值填充为无害的值(例如0或1),或者压缩数组到1维并省略掩码值。如果适用的话,您可以直接执行这些步骤。 - hpaulj
@hpaulj 谢谢!非常有帮助。对于像 np.ma.std 这样的函数,它如何处理掩码值?如果没有 axis 参数,那么数组被展平了...但是如果有 axis 参数——它既不能展平,也不能填充 0,对吧? - DilithiumMatrix
看起来我们需要学习 numpy/ma/core.pynp.ma.std 使用 ma 的 std 方法,该方法使用 var,而 var 又使用 meanmean 又使用 sumcountma.sum 使用了 filled(0)。看起来 count~mask 上使用了 sum - 即按轴计算未屏蔽值的数量。 - hpaulj
@hpaulj 哎呀……好吧,是的,这个想法很有道理! - DilithiumMatrix
1个回答

1
如果你只想取“干净”的切片,而不是仅从某些“行”中取一些元素,则可以使用数字索引而不是掩码。

E.g.:

arr = np.array([[[1,2,3,4], [5,6,7,8]], [[9,8,9,8], [7,6,7,6]]])
sub_idx = np.array([0,2])
sub_arr = arr[:, :, sub_idx]

这是一个 arr 的子集复制,即最后一维中的第0个和第2个“切片”:
array([[[1, 3],
        [5, 7]],

       [[9, 9],
        [7, 7]]])

请注意,定义要使用的索引的数组仅为一维,严重降低了其内存需求。(当然,在您的情况下,复制仍占用大量内存。)
还要注意,这会给你一个副本,因此您对结果(sub_arr)所做的任何更改都不会反映在原始数组中。要做到这一点,您需要将数组复制回来:
sub_arr[:] = 0 # Manipulate the values
arr[sub_idx] = sub_arr

嗯,是的,我想我可以只存储那些子数组值,并根据需要将它们清零并替换掉...这种方法并不适用于所有情况(即有时您确实希望忽略该元素而不是将其设置为零;例如计算标准偏差或其他一些情况)--- 但对于我的情况可能有效,感谢您的建议。 - DilithiumMatrix
我并不是说你必须将它们设为零 - 那只是我操作子数组的示例。 - acdr
当然,但我认为有些问题没有适用的填充值。 - DilithiumMatrix

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