2

2D配列の入力が与えられたときに、各インデックスの隣接インデックスの最小値の行と列のオフセットを返す関数を書くことになっているという問題があります。行の各インデックスのオフセット用の 1 つの配列と、列のオフセット用の 1 つの配列。たとえば、インデックスの最も低い隣接セルが 1 行下で 1 列右にある場合、オフセットは 1,1 です。一番下の隣接セルが左側にある場合、オフセットは 0、-1 です。隣接するセルの中で最も低いセルである場合、オフセットは 0,0 です。

これを行うためのより速くて正しい方法を見つけることができなかったので、各インデックスを反復処理し、ポイント [i,j] の周囲のインデックスのどれが他のすべての周囲のインデックスよりも低いかを確認する while ループを作成しました。 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

np.argmin周囲のすべての値を 1 つの次元に積み重ねるという E 氏の基本的な考え方は気に入っていますが、積み重ねられた配列を作成し、 の戻り値をインデックスのペアに変換するより良い方法があると思います。

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 に答える