2017-02-09 4 views
3

I ein leeres Array haben:vektorisierten Summe Array nach Indizes zweiten Array

empty = np.array([0, 0, 0, 0, 0]) 

eine Reihe von Indizes auf Positionen in meinem Array leer

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

und ein Array von Werten entsprechenden

Ich möchte die Werte in 'val' in 'leer' gemäß der von 'ind' angegebenen Position hinzufügen.

Die Nicht-vektorisiert Lösung ist:

for i, v in zip(ind, val): maps[i] += v 
>>> maps 
[ 0. 4. 5. 1. 2.] 

Meine tatsächlichen Arrays sind mehrdimensionale und loooong so habe ich eine NEED FOR SPEED habe ich wirklich eine vektorisiert Lösung wollen, oder eine Lösung, die sehr schnell ist .

Hinweis dies nicht funktioniert:

maps[ind] += val 
>>> maps 
array([ 0., 1., 1., 1., 1.]) 

ich besonders dankbar für eine Lösung wäre, die 2,7 in Python funktioniert, 3.5, 3.6 ohne Schluckauf

+1

es ist wahr, es ein Duplikat ist. aber mein Fragetitel ist viel klarer – user6794223

Antwort

6

Sie können von np.add.at machen, die funktioniert entspricht empty[ind] += val, mit der Ausnahme, dass die Ergebnisse für Elemente gesammelt werden, die mehr als einmal indexiert werden, sodass Sie für diese Indizes ein kumuliertes Ergebnis erhalten.

>>> np.add.at(empty, ind, val) 
>>> empty 
array([0, 4, 5, 1, 2]) 
1

Dies ist im Grunde ein histogram, so im eindimensionalen Fall:

h, b = np.histogram(ind, bins=np.arange(empty.size+1), weights=val) 
empty += h 

Natürlich können Sie nur Nullen haben leer die zweite Anweisung für den Fall auslassen.

+0

Ich entfernte den Teil über 'np.bincount', weil @DanielForsman bereits diese Antwort gab, und ich sah nur nach dem Bearbeiten. –

2

Sie suchen nach e=np.bincount(ind, weights=val, minlength=n), wobei n die Länge Ihres leeren Arrays ist. Auf diese Weise müssen Sie empty nicht initialisieren. Sie müssen nur das erste Mal tun, wie später können Sie tun e+=np.bincount(ind, weights=val)

Dies wird mindestens doppelt so schnell wie np.add.at:

%timeit np.bincount(ind, val, minlength=empty.size) 
The slowest run took 12.69 times longer than the fastest. This could mean that an intermediate result is being cached. 
100000 loops, best of 3: 2.05 µs per loop 

%timeit np.add.at(empty, ind, val) 
The slowest run took 2822.05 times longer than the fastest. This could mean that an intermediate result is being cached. 
100000 loops, best of 3: 4.32 µs per loop 

Wie für mehrdimensionale Indizes, können Sie tun:

np.bincount(np.ravel_multi_index(ind, empty.shape), np.ravel(val), minlength=empty.size).reshape(empty.shape) 

ich bin mir nicht sicher, wie dies mit np.add.at zu tun Geschwindigkeiten vergleichen

+0

Sollte das funktionieren, wenn leer und val multidimensional sind? Bsp .: leer.shape = (5,2,2) und val.shape = (10,2,2)? – user6794223

+1

Nicht wie geschrieben, müssen Sie 'ravel_multi_index' Ihre Indizes,' ravel' 'empty' und' val' und 'reshape' die Endergebnisse. An diesem Punkt ist "np.add.at" wahrscheinlich schneller oder zumindest pythonischer. Aber das hast du nicht gefragt :) –

+0

Es ist nicht das, was ich gefragt habe, du hast Recht. Ich habe nicht erwartet, dass es etwas ausmachen würde. Aber danke! – user6794223