将 ndarray 的大多数元素设置为零的好方法是什么?

What's a good way of setting most elements of an ndarray to zero?

我有一个 ndarray 有 10,000 行和 75 列,另一个有相同的行数和 3 列。第二个有整数值。

我想得到一个 10,000 行和 75 列的数组,所有元素都设置为零,除了每行中的元素由第二个数组的相应行中的值索引。

所以从 z_arrayi_array 开始,我想以 a_array

结束
>>> z_array
array([[10, 11, 12, 13, 14, 15],
       [10, 11, 12, 13, 14, 15],
       [10, 11, 12, 13, 14, 15],
       [10, 11, 12, 13, 14, 15]])
>>> i_array
array([[0, 2],
       [3, 1],
       [1, 4],
       [2, 3]])
>>> a_array
array([[10,  0, 12,  0,  0,  0],
       [ 0, 11,  0, 13,  0,  0],
       [ 0, 11,  0,  0, 14,  0],
       [ 0,  0, 12, 13,  0,  0]])

我可以看到两种解决方法:要么从一个全为零的数组开始,然后复制 z_array 中的相关元素;或者从 z_array 开始并将所有不相关的元素设置为零。请注意,不相关元素的数量通常远远大于相关元素的数量。

无论哪种方式,是否有进行多项分配的好方法,或者我只需要循环遍历它们?或者有第三种方法吗?

我想知道我是否可以以某种方式使用 numpy.ufunc.at? 我可以看到如何获取相关元素的索引列表,例如

>>> index_list = [[i, val] for (i, x) in enumerate(i_array) for val in x ]
index_list
[[0, 0], [0, 2], [1, 3], [1, 1], [2, 1], [2, 4], [3, 2], [3, 3]]

对于不相关的元素,获取它们的方法稍微复杂一些。但是这些列表会很大!!

你可以使用 masked arrays

import numpy as np

def mask_array(z_array, i_array):
    ROWS, COLS = np.shape(z_array)

    # Fill in the mask
    mask = np.zeros((ROWS, COLS))
    for i in range(ROWS):
        np.add.at(mask[i,:], i_array[i], 1)
    mask = mask > 0
    mask = ~mask

    m_array = np.ma.array(z_array, mask=mask, fill_value = 0)
    return np.ma.filled(m_array)

a_array = mask_array(z_array, i_array)

为了区分z_array的元素,我定义为:

array([[ 10,  11,  12,  13,  14,  15],
       [110, 111, 112, 113, 114, 115],
       [210, 211, 212, 213, 214, 215],
       [310, 311, 312, 313, 314, 315]])

那么一种可能的解决方案是创建一个用零填充的数组,使用 zeros_like 然后 运行 基于 ndenumerate 方法的循环:

result = np.zeros_like(z_array)
for (r, c), x in np.ndenumerate(i_array):
    result[r, x] = z_array[r, x]

对于我的(更改的)源数据,结果是:

array([[ 10,   0,  12,   0,   0,   0],
       [  0, 111,   0, 113,   0,   0],
       [  0, 211,   0,   0, 214,   0],
       [  0,   0, 312, 313,   0,   0]])

您似乎在寻找类似于 np.put_along_axis

的内容

以你那里的例子为例,如果你运行:np.put_along_axis(z_array, i_array, 0, axis=1)

z_array = [[ 0 11  0 13 14 15]
 [10  0 12  0 14 15]
 [10  0 12 13  0 15]
 [10 11  0  0 14 15]]

输出与你想要的相反。

要获得您想要的内容,请将 z_array 的副本创建为 a_array。然后,比较这些矩阵并保留 z_array 元素非零的值。

a_array = copy.copy(z_array)
np.put_along_axis(z_array, i_array, 0, axis=1)
a_array[(z_array != 0)] = 0

这给出了您预期的输出:

a_array = [[10  0 12  0  0  0]
 [ 0 11  0 13  0  0]
 [ 0 11  0  0 14  0]
 [ 0  0 12 13  0  0]]

np.put_along_axis documentation

查看此 以了解更多组合矩阵的选项 (np.where)