NumPy - 从另一个二维数组中选择一个子矩阵

NumPy - Selecting a submatrix from another 2d array

这是我原来的二维数组A

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 2, 2, 2, 2, 2, 2, 0, 0, 0],
 [0, 2, 2, 2, 2, 2, 2, 0, 0, 0],
 [0, 2, 2, 2, 2, 2, 2, 0, 0, 0],
 [0, 2, 2, 2, 2, 2, 2, 0, 0, 0],
 [0, 2, 2, 8, 8, 8, 2, 0, 0, 0],
 [0, 2, 2, 8, 8, 8, 2, 0, 0, 0],
 [0, 0, 0, 8, 8, 8, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

假设我想 return 一个 3x3 中间为 8 的子矩阵。我用这个表达式 A == 8 做了一个布尔掩码,它看起来像这样。

array([[False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False,  True,  True,  True, False, False, False,
        False],
       [False, False, False,  True,  True,  True, False, False, False,
        False],
       [False, False, False,  True,  True,  True, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False],
       [False, False, False, False, False, False, False, False, False,
        False]])

这就是我卡住的地方。我如何 return 具有该布尔掩码的子矩阵?如果我这样做 A[A == 8],它 return 是一个像这样的 8 平面数组

array([8, 8, 8, 8, 8, 8, 8, 8, 8])

另一种方法是使用 np.where(A == 8) 获取行号和列号,其中 returns (array([5, 5, 5, 6, 6, 6, 7, 7, 7]), array([3, 4, 5, 3, 4, 5, 3, 4, 5]))。我如何 return 矩阵使用它们?

这个问题有更好的方法吗?

如评论中所述,A[A==some_value] 正确地 returns 一个 rank-1 值数组 some_value。这是有道理的,因为值 some_value 并不总是组织在一个块中(例如 some_value = 2),或者值 some_value 的数量无法放入二维数组。

但是如果你确定有这样的块,你可以通过以下方式获取:

import numpy as np

inds = np.where(A==8)
slice_x = slice(inds[0].min(), inds[0].max() + 1)  # slice(6, 9, None)
slice_y = slice(inds[1].min(), inds[1].max() + 1)  # slice(3, 6, None)

A[slice_x, slice_y]

# array([[8, 8, 8],
#        [8, 8, 8],
#        [8, 8, 8]])

或者,您可以使用 scipy.ndimage.find_objects 获取切片:

from scipy import ndimage

slice_x, slice_y = ndimage.find_objects(A==8)[0]  # (slice(6, 9, None), slice(3, 6, None))

您可以捕获 rowcolumn 索引,然后仅使用 np.ix_ 方法从这些索引捕获 return 子矩阵:

x, y = np.where(A==8) #[5 5 5 6 6 6 7 7 7], [3 4 5 3 4 5 3 4 5]
x, y = np.unique(x), np.unique(y) # [5,6,7], [3,4,5]
print(A[np.ix_(x, y)]) #prints [[8 8 8], [8 8 8], [8 8 8]]

这甚至在更一般的情况下也应该有效,尽管并不总是如预期的那样:

def submatrix(A):
    x, y = np.where(A==8)
    x, y = np.unique(x), np.unique(y)
    return A[np.ix_(x, y)]

>>> A = np.array([
[8, 2, 8, 2, 8, 0],
[2, 8, 8, 8, 2, 0],
[2, 8, 4, 8, 3, 0],
[0, 8, 8, 8, 0, 0],
[8, 0, 8, 0, 8, 0],
[0, 0, 0, 0, 0, 0]])
>>> submatrix(A)
array([[8, 2, 8, 2, 8],
       [2, 8, 8, 8, 2],
       [2, 8, 4, 8, 3],
       [0, 8, 8, 8, 0],
       [8, 0, 8, 0, 8]])
>>> A = np.array([
[8, 2, 8, 2, 8, 0],
[2, 2, 8, 8, 2, 0],
[2, 2, 4, 3, 3, 0],
[0, 2, 8, 8, 0, 0],
[8, 0, 8, 0, 8, 0],
[0, 0, 0, 0, 0, 0]])
>>> submatrix(A) # skipping empty rows and columns
array([[8, 8, 2, 8],
       [2, 8, 8, 2],
       [0, 8, 8, 0],
       [8, 8, 0, 8]])

由于 np.unique returns 已排序数组,您可以像这样填充构建 xy 的空白:

def submatrix(A):
    x, y = np.where(A==8)
    x, y = np.unique(x), np.unique(y)
    x, y = np.arange(x[0], x[-1]+1), np.arange(y[0], y[-1]+1)
    return A[np.ix_(x, y)]

您可以尝试以下方法

 data = A[np.any(A==8,axis=1)]
 data.T[np.all(data==8,axis=0)]

这应该给,

 array([[8, 8, 8],
        [8, 8, 8],
        [8, 8, 8]])