Ändern von etwas von Iteration über ein numpy Array zu Vektorisierung

Ich versuche, das Stück Code unten durch Vektorisierung zu beschleunigen:

[rows,cols] = flow_direction_np.shape elevation_gain = np.zeros((rows,cols), np.float) for [i, j], flow in np.ndenumerate(flow_direction_np): try: if flow == 32: elevation_gain[i - 1, j - 1] = elevation_gain[i - 1, j - 1] + sediment_transport_np[i, j] elif flow == 64: elevation_gain[i - 1, j] = elevation_gain[i - 1, j] + sediment_transport_np[i, j] elif flow == 128: elevation_gain[i - 1, j + 1] = elevation_gain[i - 1, j + 1] + sediment_transport_np[i, j] elif flow == 16: elevation_gain[i, j - 1] = elevation_gain[i, j - 1] + sediment_transport_np[i, j] elif flow == 1: elevation_gain[i, j + 1] = elevation_gain[i, j + 1] + sediment_transport_np[i, j] elif flow == 2: elevation_gain[i + 1, j + 1] = elevation_gain[i + 1, j + 1] + sediment_transport_np[i, j] elif flow == 4: elevation_gain[i + 1, j] = elevation_gain[i + 1, j] + sediment_transport_np[i, j] elif flow == 8: elevation_gain[i + 1, j - 1] = elevation_gain[i + 1, j - 1] + sediment_transport_np[i, j] except IndexError: elevation_gain[i, j] = 0 

So sieht mein Code mal aus:

 elevation_gain = np.zeros_like(sediment_transport_np) nrows, ncols = flow_direction_np.shape lookup = {32: (-1, -1), 16: (0, -1), 8: (+1, -1), 4: (+1, 0), 64: (-1, 0), 128:(-1, +1), 1: (0, +1), 2: (+1, +1)} # Initialize an array for the "shifted" mask shifted = np.zeros((nrows+2, ncols+2), dtype=bool) # Pad elevation gain with zeros tmp = np.zeros((nrows+2, ncols+2), elevation_gain.dtype) tmp[1:-1, 1:-1] = elevation_gain elevation_gain = tmp for value, (row, col) in lookup.iteritems(): mask = flow_direction_np == value # Reset the "shifted" mask shifted.fill(False) shifted[1:-1, 1:-1] = mask # Shift the mask by the right amount for the given value shifted = np.roll(shifted, row, 0) shifted = np.roll(shifted, col, 1) # Set the values in elevation change to the offset value in sed_trans elevation_gain[shifted] = elevation_gain[shifted] + sediment_transport_np[mask] 

Die Mühe, die ich habe, ist, dass sie mir nicht das gleiche Ergebnis am Ende irgendwelche Vorschläge geben, wo ich falsch gehe?

2 Solutions collect form web for “Ändern von etwas von Iteration über ein numpy Array zu Vektorisierung”

Sie können Ihre Leistung mit np.where erheblich verbessern, um die Indizes zu erhalten, wo Ihre Bedingungen passieren:

 ind = np.where( flow_direction_np==32 ) 

Sie werden sehen, dass ind ein Tupel mit zwei Elementen ist, das erste ist die Indizes der ersten Achse und die zweite der zweiten Achse Ihres flow_direction_np Arrays.

Sie können mit diesen Indizes arbeiten, um die Verschiebungen anzuwenden: i-1 , j-1 und so weiter …

 ind_32 = (ind[0]-1, ind[1]-1) 

Dann benutze man eine ausgezeichnete Indexierung, um die Arrays zu aktualisieren:

 elevation_gain[ ind_32 ] += sediment_transport_np[ ind ] 

BEARBEITEN: Dieses Konzept auf deinen Fall anwenden würde so etwas geben:

 lookup = {32: (-1, -1), 16: ( 0, -1), 8: (+1, -1), 4: (+1, 0), 64: (-1, 0), 128: (-1, +1), 1: ( 0, +1), 2: (+1, +1)} for num, shift in lookup.iteritems(): ind = np.where( flow_direction_np==num ) ind_num = ind[0] + shift[0], ind[1] + shift[1] elevation_gain[ ind_num] += sediment_transport_np[ ind ] 

Der Grund, dass Sie immer unterschiedliche Ergebnisse ist aufgrund der Art und Weise python Handles negative Indizierung.


Für andere Leute lesen, ist diese Frage (und Antwort) ein Follow-up von hier: Iterating durch ein numpy Array und dann Indizierung eines Wertes in einem anderen Array

Zuerst entschuldige ich mich, dass der "vektorisierte" Code so dicht ist wie er ist. Es gibt eine Erklärung in meiner früheren Antwort , also werde ich es hier nicht wiederholen.


Ihr ursprünglicher Code (in der ursprünglichen Frage) ist eigentlich subtil anders als die Version, die Sie hier geschrieben haben.

Im Grunde, bevor Sie hatten

 for [i, j], flow in np.ndenumerate(flow_direction_np): try: if flow == 32: ... elif ... ... 

Und du bekommst einen Indexfehler, wenn i+1 oder j+1 größer war als die Größe des Rasters.

Mach einfach:

 for [i, j], flow in np.ndenumerate(flow_direction_np): try: if flow == 32: ... elif ... ... except IndexError: elevation_change[i, j] = 0 

Ist eigentlich falsch, weil es verschiedene Randbedingungen auf verschiedenen Seiten des Gitters definiert.

Im zweiten Fall, wenn j-1 oder i-1 negativ ist, wird der Wert von der gegenüberliegenden Seite des Gitters zurückgegeben. Wenn jedoch j+1 oder i+1 größer als die Größe des Gitters ist, wird 0 zurückgegeben. (Also die "verschiedenen Randbedingungen").

In der vektorisierten Version des Codes wird 0 zurückgegeben, wenn die Indizes negativ sind und wenn sie über die Grenzen des Rasters hinausgehen.


Als kurzes Beispiel beachten Sie, was mit dem folgenden passiert:

 In [1]: x = [1, 2, 3] In [2]: x[0] Out[2]: 1 In [3]: x[1] Out[3]: 2 In [4]: x[2] Out[4]: 3 In [5]: x[3] --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-5-ed224ad0520d> in <module>() ----> 1 x[3] IndexError: list index out of range In [6]: x[-1] Out[6]: 3 In [7]: x[-2] Out[7]: 2 In [8]: x[-3] Out[8]: 1 In [9]: x[-4] --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-9-f9c639f21256> in <module>() ----> 1 x[-4] IndexError: list index out of range In [10]: 

Beachten Sie, dass negative Indizes bis zur Größe der Sequenz gültig sind und das "entgegengesetzte Ende" der Sequenz zurückgeben. Also, x[3] wirft einen Fehler auf, während x[-1] gerade das andere Ende zurückgibt.

Hoffentlich ist das ein bisschen klarer.

  • Unterschied zwischen frompyfunc und vectorize in numpy
  • Vektorisierung einer Numpy-Slice-Operation
  • Python-Vektorisierung verschachtelt für Schleifen
  • Effiziente Auswertung einer Funktion in jeder Zelle eines NumPy Arrays
  • Vektorisierte Backtest-Erstellung von Pandas DataFrame
  • Produkt einer Sequenz in NumPy
  • Optimiere diese Funktion mit numpy (oder anderen Vektorisierungsmethoden)
  • Kovarianz mit Säulen
  • Wie man eine einfache für Schleife in Python / Numpy vektorisiert
  • Beschreiben von Lücken in einer Zeitreihe Pandas
  • Vektorisierte radix sort mit numpy - kann es schlagen np.sort?
  • Python ist die beste Programmiersprache der Welt.