2

我有一个问题,我们应该编写一个函数,当给定二维数组的输入时,它将返回每个索引的最低值相邻索引的行和列中的偏移量;一个数组表示每个索引的偏移量(以行为单位),一个数组表示每个索引的偏移量(以列为单位)。例如,如果索引的最低相邻单元格在下一行右一列,则偏移量为 1,1;如果最低相邻单元格在左侧,则偏移量为 0,-1;如果它是其相邻单元格中的最低单元格,则偏移量为 0,0。

因为我找不到更快和正确的方法来执行此操作,所以我编写了一个 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

运行需要很长时间,但它确实运行。我无法想象我实际上是在以最有效的方式做到这一点。任何输入?

4

2 回答 2

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)))
于 2013-03-21T12:20:29.977 回答
1

我喜欢 E 先生将所有周围值堆叠在一个维度中的基本想法,但我认为有更好的方法来创建堆叠数组并将返回的值转换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),即缺少第一列和最后一列和行,因为它们周围没有完全定义的窗口。

于 2013-03-21T15:51:17.973 回答