如何用多个一维布尔数组索引多维NumPy数组?

jm2pwxwz  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(104)

假设我有一个NumPy数组A,维度为n,可能非常大,并假设我有k * 一维布尔掩码M1, ..., Mk
我想从A中提取一个n维数组B,它包含A的所有元素,这些元素位于所有掩码的“外部-AND“为True的索引处。
.但我想这样做,而不是首先形成(可能非常大的)所有掩码的“外部-AND“,并且不必从每个轴提取指定的元素,一次一个轴,因此在此过程中创建(可能很多)中间副本。
下面的例子演示了从上面描述的A中提取元素的两种方法:

from functools import reduce
import numpy as np

m = 100

for _ in range(m):
    n = np.random.randint(0, 10)
    k = np.random.randint(0, n + 1)

    A_shape = tuple(np.random.randint(0, 10, n))

    A = np.random.uniform(-1, 1, A_shape)
    M_lst = [np.random.randint(0, 2, dim).astype(bool) for dim in A_shape]

    # Creating shape of B:
    B_shape = tuple(map(np.count_nonzero, M_lst)) + A_shape[len(M_lst):]
    # size of B:
    B_size = np.prod(B_shape)

    # --- USING "OUTER-AND" OF ALL MASKS --- #
    # Creating "outer-AND" of all masks:
    M = reduce(np.bitwise_and, (np.expand_dims(M, tuple(np.r_[:i, i+1:n])) for i, M in enumerate(M_lst)), True)
    # extracting elements from A and reshaping to the correct shape:
    B1 = A[M].reshape(B_shape)
    # Checking that the correct number of elements was extracted
    assert B1.size == B_size
    # THE PROBLEM WITH THIS METHOD IS THE POSSIBLY VERY LARGE OUTER-AND OF ALL THE MASKS!

    # --- USING ONE MASK AT A TIME --- #
    B2 = A
    for i, M in enumerate(M_lst):
        B2 = B2[tuple(slice(None) for _ in range(i)) + (M,)]
    assert B2.size == np.prod(B_shape)
    assert B2.shape == B_shape
    # THE PROBLEM WITH THIS METHOD IS THE POSSIBLY LARGE NUMBER OF POSSIBLY LARGE INTERMEDIATE COPIES!

    assert np.all(B1 == B2)

    # EDIT 1:
    # USING np.ix_ AS SUGGESTED BY Chrysophylaxs
    i = np.ix_(*M_lst)
    B3 = A[i]
    assert B3.shape == B_shape
    assert B3.size == B_size
    assert np.prod(list(map(np.size, i))) == B_size

print(f'All three methods worked all {m} times')

有没有更聪明(更有效)的方法来做到这一点,可能使用现有的NumPy函数?

disbfnqx

disbfnqx1#

IIUC,你要找的是np.ix_一个例子:

import numpy as np

arr = np.arange(60).reshape(3, 4, 5)

x = [True, False, True]
y = [False, True, True, False]
z = [False, True, False, True, False]

out = arr[np.ix_(x, y, z)]

输出:

array([[[ 6,  8],
        [11, 13]],

       [[46, 48],
        [51, 53]]])

相关问题