Как выбрать все местоположения уникальных элементов в массиве NumPy 2D с рамкой вокруг них? - PullRequest
3 голосов
/ 10 октября 2011

У меня есть двумерный массив NumPy. Я хочу найти «каждое» местоположение всех уникальных элементов.Мы можем найти уникальные элементы, используя numpy.unique(numpyarray.).Здесь начинается сложная часть.Теперь я должен знать все места для каждого уникального элемента.Давайте рассмотрим следующий пример.

array([[1, 1, 2, 2],\
       [1, 1, 2, 2],\
       [3, 3, 4, 4],\
       [3, 3, 4, 4]])

Результат должен быть

1, (0,0),(1,1)
2, (0,2),(1,2)
3, (2,0),(3,1)
4, (2,2),(3,3)

Как это сделать и что может быть подходящим способом для хранения и перебора значений.

ЭтоСледует отметить, что все уникальные значения будут смежными друг с другом.Единственными пробелами между ними могут быть только нули.Давайте рассмотрим другой вариант

 array([[1, 0, 1, 2, 2],\
        [1, 0, 1, 2, 2],\
        [3, 0, 3, 4, 4],\
        [3, 0, 3, 4, 4]])

Результат должен быть

1, (0,0),(1,2)
2, (0,3),(1,4)
3, (2,0),(3,2)
4, (2,3),(3,4)

Пропускать зеросами на границах нужно.

1 Ответ

3 голосов
/ 10 октября 2011

Простой способ перебора - просто использовать numpy.where.

Например, если вы просто хотите ограничить поле :

import numpy as np

x = np.array([[1,1,2,2],
              [1,1,2,2],
              [3,3,4,4],
              [3,3,4,4]])

for val in np.unique(x):
    rows, cols = np.where(x == val)
    rowstart, rowstop = np.min(rows), np.max(rows)
    colstart, colstop = np.min(cols), np.max(cols)
    print val, (rowstart, colstart), (rowstop, colstop) 

Это будет работать и для примера с нулями.

Если массив большой, и у вас уже есть scipy, вы можете вместо этого использовать scipy.ndimage.find_objects, как предложил @unutbu.

В конкретном случае вашего примера, где ваши уникальные значения являются последовательными целыми числами, вы можете напрямую использовать find_objects. Он ожидает массив, в котором каждое последовательное целое число, отличное от 0, представляет объект, которому необходимо вернуть ограничивающий прямоугольник. (0 игнорируется, именно так, как вы хотите.) Однако, как правило, вам необходимо выполнить предварительную обработку для преобразования произвольных уникальных значений в последовательные целые числа.

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

import numpy as np
import scipy.ndimage as ndimage

x = np.array([[1, 0, 1, 2, 2],
              [1, 0, 1, 2, 2],
              [3, 0, 3, 4, 4],
              [3, 0, 3, 4, 4]])

for i, item in enumerate(ndimage.find_objects(x), start=1):
    print i, item

Это будет выглядеть немного иначе, чем вы могли бы ожидать. Это slice объекты, поэтому значение «max» всегда будет на единицу больше, чем «max» в предыдущем примере. Это сделано для того, чтобы вы могли просто нарезать данный кортеж, чтобы получить данные.

1026 * Е.Г. *

for i, item in enumerate(ndimage.find_objects(x), start=1):
    print i, ':'
    print x[item], '\n'

Если вы действительно хотите запускать и останавливать, просто сделайте что-то вроде этого:

    for i, (rowslice, colslice) in enumerate(ndimage.find_objects(x), start=1):
        print i, 
        print (rowslice.start, rowslice.stop - 1),
        print (colslice.start, colslice.stop - 1)

Если ваши уникальные значения не являются последовательными целыми числами, вам необходимо выполнить небольшую предварительную обработку, как я уже упоминал ранее. Вы можете сделать что-то вроде этого:

import numpy as np
import scipy.ndimage as ndimage

x = np.array([[1.1, 0.0, 1.1, 0.9, 0.9],
              [1.1, 0.0, 1.1, 0.9, 0.9],
              [3.3, 0.0, 3.3, 4.4, 4.4],
              [3.3, 0.0, 3.3, 4.4, 4.4]])
ignored_val = 0.0
labels = np.zeros(data.shape, dtype=np.int)

i = 1
for val in np.unique(x):
    if val != ignored_val:
        labels[x == val] = i
        i += 1

# Now we can use the "labels" array as input to find_objects
for i, item in enumerate(ndimage.find_objects(labels), start=1):
    print i, ':'
    print x[item], '\n'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...