NumPy - выбор подматрицы из другого двумерного массива - PullRequest
2 голосов
/ 18 февраля 2020

Это мой оригинальный 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]]

Допустим, я хочу вернуть 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]])

Это точка, в которой я застрял. Как я могу вернуть подматрицу с этой логической маской? Если я сделаю A[A == 8], он вернет плоский массив из 8, например,

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

Другой способ - получить номера строк и столбцов с помощью np.where(A == 8), который возвращает (array([5, 5, 5, 6, 6, 6, 7, 7, 7]), array([3, 4, 5, 3, 4, 5, 3, 4, 5])). Как я могу вернуть матрицу, используя их?

Есть ли лучший подход к этой проблеме?

Ответы [ 3 ]

1 голос
/ 18 февраля 2020

Вы можете захватывать индексы row и column и после этого возвращать подматрицу из этих индексов только с использованием np.ix_ метода:

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 возвращает отсортированные массивы, вы можете заполнить пробелы, составляющие 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)]
1 голос
/ 18 февраля 2020

Как упоминалось в комментариях, A[A==some_value] правильно возвращает массив значений ранга 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))
0 голосов
/ 18 февраля 2020

Вы можете попробовать следующее

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