一次将多个掩码应用于 Numpy 数组

Apply multiple masks at once to a Numpy array

有没有办法一次将多个掩码应用于多维 Numpy 数组?

例如:

X = np.arange(12).reshape(3, 4)
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11]])
m0 = (X>0).all(axis=1) # array([False,  True,  True])
m1 = (X<3).any(axis=0) # array([ True,  True,  True, False])

# In one step: error
X[m0, m1]
# IndexError: shape mismatch: indexing arrays could not 
#             be broadcast together with shapes (2,) (3,) 

# In two steps: works (but awkward)
X[m0, :][:, m1]
# array([[ 4,  5,  6],
#        [ 8,  9, 10]])

尝试:

>>> X[np.ix_(m0, m1)]
array([[ 4,  5,  6],
       [ 8,  9, 10]])

来自docs

Combining multiple Boolean indexing arrays or a Boolean with an integer indexing array can best be understood with the obj.nonzero() analogy. The function ix_ also supports boolean arrays and will work without any surprises.

另一种解决方案(也是直接来自文档但不太直观的 IMO):

>>> X[m0.nonzero()[0][:, np.newaxis], m1]
array([[ 4,  5,  6],
       [ 8,  9, 10]])

错误告诉你需要做什么:掩码尺寸需要一起广播。您可以在源头解决此问题:

m0 = (X>0).all(axis=1, keepdims=True)
m1 = (X<3).any(axis=0, keepdims=True)

>>> X[m0 & m1]
array([ 4,  5,  6,  8,  9, 10])

您真的只需要将 keepdims 应用到 m0,因此您可以将掩码保留为 1D:

>>> X[m0[:, None] & m1]
array([ 4,  5,  6,  8,  9, 10])

您可以重塑成想要的形状:

>>> X[m0[:, None] & m1].reshape(np.count_nonzero(m0), np.count_nonzero(m1))
array([[ 4,  5,  6],
       [ 8,  9, 10]])

另一种选择是将掩码转换为索引:

>>> X[np.flatnonzero(m0)[:, None], np.flatnonzero(m1)]
array([[ 4,  5,  6],
       [ 8,  9, 10]])