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

Python NumPy-从另一个二维数组中选择子矩阵,python,arrays,numpy,math,linear-algebra,Python,Arrays,Numpy,Math,Linear Algebra,这是我原来的2d阵列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,

这是我原来的2d阵列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]]
假设我想在中间返回一个8的3x3子矩阵。我用这个表达式制作了一个布尔掩码
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]])
这就是我被困的地方。如何返回带有布尔掩码的子矩阵?如果我执行
A[A==8]
,它将返回一个8的平面数组,如下所示

array([8, 8, 8, 8, 8, 8, 8, 8, 8])
另一种方法是使用
np获取行数和列数,其中(A==8)
返回
(数组([5,5,5,6,6,6,7,7,7])、数组([3,4,5,3,4,5,3,4,5])
。如何使用它们返回矩阵


有没有更好的方法解决这个问题?

如评论中所述,
A[A==some\u value]
正确地返回值的秩1数组
some\u value
。这是有意义的,因为并非总是将值
某些值
组织在一个块中(例如
某些值=2
),或者值的数量
某些值
无法放入2D数组中

但是,如果确定存在这样的块,则可以执行以下操作来获得它:

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))

您可以捕获
索引,然后仅使用以下方法从这些索引返回子矩阵:

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

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
返回已排序的数组,因此您可以通过以下方式填补空白:构造
x
y

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]])

像这样的布尔索引返回1d结果。通常,这种索引不会返回一个整洁的值块。但是如果你知道结果会是这样的块,那就重新塑造它们。@hpaulj我不知道它的形状是否符合预期,因为你并不总是有矩形,例如
A[A==2]
。现在,如果确定
8
仅显示在块中,则可以使用
argmin/argmax
检测形状。
 array([[8, 8, 8],
        [8, 8, 8],
        [8, 8, 8]])