2013-03-21 5 views
2

У меня есть проблема, в которой мы должны написать функцию, которая при вводе двоичного массива возвращает смещение в строках и столбцах соседнего индекса индекс самого низкого значения; один массив для смещения каждого индекса в строках и один массив для смещения в столбцах. Например, если самая низкая соседняя ячейка индекса находится на одной строке и правее одного столбца, смещение равно 1,1; если нижняя соседняя ячейка находится слева, смещение равно 0, -1; если это самая низкая ячейка из соседних ячеек, то смещение равно 0,0.Поиск наименьшего соседнего индекса в массиве Python

Поскольку я не мог найти более быстрый и правильный способ сделать это, я написал цикл while, который будет перебирать каждый индекс и видеть, какой из окружающих индексов для точки [i, j] был ниже, чем все другие окружающие индексы с использованием a.all():

def findLowNhbr(terrain): 
    """Creates two 2D-arrays the shape of terrain consisting 
    of the offsets (row and column) to the neighbor with the minimum eleveation""" 
    rowOffset = np.zeros_like(terrain) 
    colOffset = np.zeros_like(terrain) 

for i in range(len(terrain)): 
    if i == 0: 
     rowOffset[i] = 0 
     colOffset[i] = 0 
    elif i == (len(terrain)-1): 
     rowOffset[i] = 0 
     colOffset[i] = 0 
    else: 
     for j in range(len(terrain[i])): 
      if j == 0 or j == len(terrain[i])-1: 
       rowOffset[:,j] = 0 
       colOffset[:,j] = 0 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i-1,j-1]).all(): 
       rowOffset[i,j] = -1 
       colOffset[i,j] = -1 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i,j-1]).all(): 
       rowOffset[i,j] = 0 
       colOffset[i,j] = -1 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i+1,j-1]).all(): 
       rowOffset[i,j] = 1 
       colOffset[i,j] = -1 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i-1,j]).all(): 
       rowOffset[i,j] = -1 
       colOffset[i,j] = 0 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i+1,j]).all(): 
       rowOffset[i,j] = 1 
       colOffset[i,j] = 0 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i-1,j+1]).all(): 
       rowOffset[i,j] = -1 
       colOffset[i,j] = 1 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i,j]).all(): 
       rowOffset[i,j] = 0 
       colOffset[i,j] = 1 
      elif (terrain[i-1:i+2,j-1:j+2]>=terrain[i+1,j+1]).all(): 
       rowOffset[i,j] = 1 
       colOffset[i,j] = 1 
      else: 
       rowOffset[i,j] = 0 
       colOffset[i,j] = 0 
return rowOffset, colOffset 

Требуется много времени для запуска, но оно выполняется. Я не могу представить, что я на самом деле делаю это самым эффективным способом; любой вход?

ответ

2

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

import numpy as np 

np.random.seed(0) 
terrain = np.random.rand(10,10) 

offsets = [(i,j) for i in range(-1,2) for j in range(-1,2)] 

stacked = np.dstack(np.roll(np.roll(terrain,i,axis=0),j,axis=1) for i, j in offsets) 

offset_index = np.argmin(stacked,axis=2) 
output = np.array(offsets)[offset_index] 

Разъяснение

  • Стек все смещения в массиве NxMx9
  • Найти индекс минимального элемента (argmin) вдоль этого ЛА й оси axis=2
  • Переходим этот индекс в массиве смещения векторов, используя результат индекса смещения в последней строке

другой, возможно, более чистый способ, чтобы получить все начальные смещения является:

from itertools import product 
offsets = list(product((-1, 0, 1), (-1, 0, 1))) 
1

Мне нравится основная идея г-Э укладок всех окружающих значений в одном измерении, но я думаю, что есть более эффективные способы создания многослойного массива и преобразование возвращения np.argmin к парам индексов:

from numpy.lib.stride_tricks import as_strided 

rows, cols = 100, 100 
win_rows, win_cols = 3, 3 # these two should be odd numbers 
terrain = np.random.rand(rows, cols) 

# This takes a windowed view of the original array, no data copied 
win_terrain = as_strided(terrain, shape=(rows-win_rows+1, cols-win_cols+1, 
             win_rows, win_cols), 
         strides=terrain.strides*2) 
# This makes a copy of the stacked array that will take up x9 times more memory 
# than the original one 
win_terrain = win_terrain.reshape(win_terrain.shape[:2] + (-1,)) 

indices = np.argmax(win_terrain, axis=-1) 
offset_rows, offset_cols = np.unravel_index(indices, 
              dims=(win_rows, win_cols)) 
# For some odd reason these arrays are non-writeable, so -= won't work 
offset_rows = offset_rows - win_rows//2 
offset_cols = offset_cols - win_cols//2 

Результирующие массивы - это только (98, 98), то есть первый и последний столбец и строки отсутствуют, поскольку вокруг них нет полностью определенного окна.

Смежные вопросы