Извлечь блок из 2d массива - PullRequest
3 голосов
/ 07 марта 2020

Предположим, у вас есть двумерный массив, непрерывно заполненный целыми числами, идущий слева направо и сверху вниз. Следовательно, это будет выглядеть как

[[ 0,  1,  2,  3,  4],
 [ 5,  6,  7,  8,  9],
 [10, 11, 12, 13, 14],
 [15, 16, 17, 18, 19]]

Предположим, теперь у вас есть одномерный массив некоторых целых чисел, показанных в приведенном выше массиве. Допустим, этот массив [6,7,11]. Я хочу извлечь блок / кусок 2D-массива, который содержит элементы списка. С этими двумя входами результат должен быть

[[ 6.,  7.],
 [11., nan]]

(я дополняю np.nan, это не может быть изменено)

Это то, что я написал. Есть ли более простой способ, пожалуйста?

import numpy as np
def my_fun(my_list):
    ids_down = 4
    ids_across = 5
    layout = np.arange(ids_down * ids_across).reshape((ids_down, ids_across))

    ids = np.where((layout >= min(my_list)) & (layout <= max(my_list)), layout, np.nan)
    r,c = np.unravel_index(my_list, ids.shape)
    out = np.nan*np.ones(ids.shape)
    for i, t in enumerate(zip(r,c)):
        out[t] = my_list[i]

    ax1_mask = np.any(~np.isnan(out), axis=1)
    ax0_mask = np.any(~np.isnan(out), axis=0)
    out = out[ax1_mask, :]
    out = out[:, ax0_mask]

    return out

Затем попытка my_fun([6,7,11]) возвращает

[[ 6.,  7.],
 [11., nan]]

Ответы [ 3 ]

2 голосов
/ 07 марта 2020

Это решение 100% NumPy работает как для смежных, так и несмежных массивов разыскиваемых номеров.

a = np.array([[ 0,  1,  2,  3,  4],
              [ 5,  6,  7,  8,  9],
              [10, 11, 12, 13, 14],
              [15, 16, 17, 18, 19]])
n = np.array([6, 7, 11])

Определение местоположения разыскиваемых номеров:

mask = np.isin(a, n)

Выбрать строки и столбцы с нужными номерами:

np.where(mask, a, np.nan)\
       [mask.any(axis=1)][:, mask.any(axis=0)]
#array([[ 6.,  7.],
#       [11., nan]])
2 голосов
/ 07 марта 2020

Один из подходов заключается в поиске ограничивающих рамок , проверяя, какие элементы в массиве содержатся во втором списке. Мы можем использовать scipy.ndimage:

from scipy import ndimage

m = np.isin(a, b)
a_components, _ = ndimage.measurements.label(m, np.ones((3, 3)))
bbox = ndimage.measurements.find_objects(a_components)
out = a[bbox[0]]
np.where(np.isin(out, b), out, np.nan)

array([[ 6.,  7.],
       [11., nan]])

Настройка -

a = np.array([[ 0,  1,  2,  3,  4],
              [ 5,  6,  7,  8,  9],
              [10, 11, 12, 13, 14],
              [15, 16, 17, 18, 19]])

b = np.array([6,7,11])

Или для b = np.array([10,12,16]) мы получим:

m = np.isin(a, b)
a_components, _ = ndimage.measurements.label(m, np.ones((3, 3)))
bbox = ndimage.measurements.find_objects(a_components)
out = a[bbox[0]]
np.where(np.isin(out, b), out, np.nan)

array([[10., nan, 12.],
       [nan, 16., nan]])

Мы также можем адаптировать вышеприведенное для нескольких ограничивающих рамок , выполнив:

b = np.array([5, 11, 8, 14])

m = np.isin(a, b)
a_components, _ = ndimage.measurements.label(m, np.ones((3, 3)))
bbox = ndimage.measurements.find_objects(a_components)

l = []
for box in bbox:
    out = a[box]
    l.append(np.where(np.isin(out, b), out, np.nan))

print(l)

[array([[ 5., nan],
        [nan, 11.]]), 
 array([[ 8., nan],
        [nan, 14.]])]
1 голос
/ 07 марта 2020

Используя преимущества формы c массива шаблонов A, мы можем напрямую преобразовать тестовые значения в координаты:

A = np.arange(20).reshape(4,5)
test = [6,7,11]

y,x = np.unravel_index(test,A.shape)
yl,yr = y.min(),y.max()
xl,xr = x.min(),x.max()
out = np.full((yr-yl+1,xr-xl+1),np.nan)
out[y-yl,x-xl]=test
out
# array([[ 6.,  7.],
#        [11., nan]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...