Получение соседа элемента внутри массива numpy - PullRequest
3 голосов
/ 28 октября 2019

У меня есть массив, который выглядит следующим образом:

[['A0' 'B0' 'C0']
 ['A1' 'B1' 'C1']
 ['A2' 'B2' 'C2']]

Я хотел бы получить соседей B1, которые равны B0 , C1 , B2 , A1, вместе с их индексами.

Thisвот что я придумал:

import numpy as np


arr = np.array([
    ['A0','B0','C0'],
    ['A1','B1','C1'],
    ['A2','B2','C2'],
])


def get_neighbor_indices(x,y):
    neighbors = []
    try:
        top = arr[y - 1, x]
        neighbors.append((top, (y - 1, x)))
    except IndexError:
        pass
    try:
        bottom = arr[y + 1, x]
        neighbors.append((bottom, (y + 1, x)))
    except IndexError:
        pass
    try:
        left = arr[y, x - 1]
        neighbors.append((left, (y, x - 1)))
    except IndexError:
        pass
    try:
        right = arr[y, x + 1]
        neighbors.append((right, (y, x + 1)))
    except IndexError:
        pass
    return neighbors

Это вернет список кортежей (value, (y, x)).

Есть ли лучший способ сделать это, не полагаясь на попытку / исключение?

Ответы [ 3 ]

5 голосов
/ 28 октября 2019

Вы можете сделать это прямо в NumPy без каких-либо исключений, так как вы знаете размеры вашего массива. Индексы ближайших соседей x, y задаются как

inds = np.array([[x, y]]) + np.array([[1, 0], [-1, 0], [0, 1], [0, -1]])

. Вы можете легко создать маску, которая указывает, какие индексы действительны:

valid = (inds[:, 0] >= 0) & (inds[:, 0] < arr.shape[0]) & \
        (inds[:, 1] >= 0) & (inds[:, 1] < arr.shape[1])

Теперь извлеките значения, которые выwant:

inds = inds[valid, :]
vals = arr[inds[:, 0], inds[:, 1]]

Простейшим возвращаемым значением будет inds, vals, но если вы настаиваете на сохранении своего исходного формата, вы можете преобразовать его в

[v, tuple(i) for v, i in zip(vals, inds)]

Addendum

Вы можете легко изменить это для работы с произвольными измерениями:

def neighbors(arr, *pos):
    pos = np.array(pos).reshape(1, -1)
    offset = np.zeros((2 * pos.size, pos.size), dtype=np.int)
    offset[np.arange(0, offset.shape[0], 2), np.arange(offset.shape[1])] = 1
    offset[np.arange(1, offset.shape[0], 2), np.arange(offset.shape[1])] = -1
    inds = pos + offset
    valid = np.all(inds >= 0, axis=1) & np.all(inds < arr.shape, axis=1)
    inds = inds[valid, :]
    vals = arr[tuple(inds.T)]
    return vals, inds

Учитывая N размерного массива arr и N элементов pos, вы можете создать смещения с помощьюпросто устанавливая каждое измерение последовательно на 1 или -1. Вычисление маски valid значительно упрощается за счет широковещательной передачи inds и arr.shape, а также вызова np.all по каждой строке размера N вместо того, чтобы делать это вручную для каждого измерения. Наконец, преобразование tuple(inds.T) превращает inds в фактический причудливый индекс, присваивая каждому столбцу отдельное измерение. Транспонирование необходимо, потому что массивы повторяются по строкам (dim 0).

1 голос
/ 28 октября 2019

Вы можете использовать это:

def get_neighbours(inds):
    places = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    return [(arr[x, y], (y, x)) for x, y in [(inds[0] + p[0], inds[1] + p[1]) for p in places] if x >= 0 and y >= 0]

get_neighbours(1, 1)
# OUTPUT [('B0', (1, 0)), ('B2', (1, 2)), ('A1', (0, 1)), ('C1', (2, 1))]

get_neighbours(0, 0)
# OUTPUT [('A1', (0, 1)), ('B0', (1, 0))]
0 голосов
/ 28 октября 2019

Как насчет этого?

def get_neighbor_indices(x,y):
    return ( [(arr[y-1,x], (y-1, x))] if y>0 else [] ) + \
           ( [(arr[y+1,x], (y+1, x))] if y<arr.shape[0]-1 else [] ) + \
           ( [(arr[y,x-1], (y, x-1))] if x>0 else [] ) + \
           ( [(arr[y,x+1], (y, x+1))] if x<arr.shape[1]-1 else [] )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...