无法使用 3D 掩蔽和索引将值分配给 numpy 数组

Cannot assign values to numpy array using 3D masking and indexing

我有一个 3D 数组,它是一个遮罩。另外,我有一些索引编码应该保存一些值的位置(数组位置)。

一切似乎都运行良好,只是在将值分配到所需位置后输出矩阵仍然为空。

我看不到我在这里遗漏了什么。我也试过 numpy.put 但没有成功。

import numpy as np

# Initialize output matrix (here the results will be stored)
results = np.zeros((67, 67, 45))

# define the mask - where to put the calculated values in the results array
mask = np.random.randint(2, size=(67, 67, 45)).astype(bool)

# store the results only in these positions
index_keep = range(0, 13732)

values = np.ones((13732,))

results[mask][index_keep] = values.copy()

# the results array is still empty
print(results.sum())
#0

当您使用布尔掩码索引数组时,元素将被提取并放入一维数组中。这几乎必须是这种情况,因为蒙版的选定元素在我们的任何维度内都不是均匀的 space。表达式 results[mask] = value 等同于 results.__setitem__(mask, value):显然是对 result 的 in-place 修改。但是 results[mask][index_keep] = value 等同于 result.__getitem__(mask).__setitem__(index_keep, value)。 in-place 操作发生在完全丢弃的临时数组上。

解决方案是使用索引对所需对象进行一次 __setitem__ 调用。一种方法是将 index_keep 应用于 mask。您首先必须将 mask 转换为线性索引,例如np.flatnonzero:

result.ravel()[np.flatnonzero(mask)[index_keep]] = value

只要 ravel returns 一个视图,它就可以工作,在大多数情况下应该如此。如果 result 是一个连续的数组,这将一直有效。如果 result 已经是更大数组的子集,它将无法工作。

这种方法的优点是它只使用一个索引数组,并且适用于任意数量的维度。使用 np.where 可以做同样的事情,但需要更多的临时存储空间。缺点当然是这种方法仅限于连续的数组。

P.S。您几乎可以肯定不需要复制 value。它的元素不会被修改,并且赋值已经将副本复制到 result 的适当位置。制作副本只会创建一个不必要的临时数组,该数组将立即被丢弃。

您可以在 mask 上使用 numpy.where,这样您就可以查看要索引的 results 数组。

x, y, z = np.where(mask)

results[x[index_keep], y[index_keep], z[index_keep]] = values