schnellere Alternative zu numpy.where?

8

Ich habe ein 3D-Array, das mit ganzen Zahlen von 0 bis N gefüllt ist. Ich brauche eine Liste der Indizes, die dem entsprechen, wo das Array gleich 1, 2, 3, ... N ist. Ich kann es mit np.where tun folgt:

%Vor%

aber das ist ziemlich langsam. Nach dieser Frage schnelle Python-Numpy wo Funktionalität? Es sollte möglich sein, die Indexsuche ziemlich schnell zu beschleunigen, aber ich konnte die dort vorgeschlagenen Methoden nicht auf mein Problem, die tatsächlichen Indizes zu bekommen, übertragen. Was wäre der beste Weg, um den oben genannten Code zu beschleunigen?

Als Add-On: Ich möchte die Indizes später speichern, für die es sinnvoll ist, np.ravel_multi_index zu verwenden, um die Größe von 3 Indizes auf nur 1 zu reduzieren, d. h. mit:

%Vor%

, die näher an z.B. Matlabs Suchfunktion. Kann dies direkt in eine Lösung integriert werden, die np.where nicht verwendet?

    
jacob 22.10.2015, 13:15
quelle

4 Antworten

6

Ich denke, dass ein vektorisierter Standardansatz für dieses Problem sehr speicherintensiv sein würde - für int64-Daten würde es O (8 * N * data.size) Bytes oder ~ 22 Gigs Speicher für das Beispiel benötigen oben gegeben. Ich gehe davon aus, dass das keine Option ist.

Sie können einige Fortschritte machen, indem Sie eine spärliche Matrix verwenden, um die Speicherorte der eindeutigen Werte zu speichern. Zum Beispiel:

%Vor%

Dies nutzt schnellen Code innerhalb des Sparse-Matrixkonstruktors aus, um die Daten in einer nützlichen Weise zu organisieren und eine dünn besetzte Matrix zu konstruieren, wobei Zeile i nur die Indizes enthält, bei denen die abgeflachten Daten gleich i sind.

Um es auszuprobieren, werde ich auch eine Funktion definieren, die Ihre einfache Methode ausführt:

%Vor%

Die zwei Funktionen liefern die gleichen Ergebnisse für die gleiche Eingabe:

%Vor%

Und die Sparse-Methode ist eine Größenordnung schneller als die einfache Methode für Ihr Dataset:

%Vor%

Der andere Vorteil der Sparse-Methode ist, dass die Matrix M eine sehr kompakte und effiziente Möglichkeit darstellt, alle relevanten Informationen für die spätere Verwendung zu speichern, wie im Add-on-Teil Ihrer Frage erwähnt. Hoffe, das ist nützlich!

Edit: Ich erkannte, dass es einen Bug in der ursprünglichen Version gab: Es scheiterte, wenn irgendwelche Werte in dem Bereich nicht in den Daten erscheinen: das ist jetzt oben behoben.

    
jakevdp 22.10.2015, 16:54
quelle
5

Ich habe darüber nachgedacht und festgestellt, dass es einen intuitiveren (aber etwas langsameren) Ansatz gibt, dies mit Pandas groupby() zu lösen. Bedenken Sie Folgendes:

%Vor%

Dies liefert das gleiche Ergebnis wie get_indices_simple von meiner vorherigen Antwort:

%Vor%

Und dieser Pandas-Ansatz ist nur etwas langsamer als der weniger intuitive Matrix-Ansatz:

%Vor%     
jakevdp 23.10.2015 21:29
quelle
4

Hier ist ein vektorisierter Ansatz -

%Vor%     
Divakar 22.10.2015 14:22
quelle
2

Grundsätzlich haben die meisten Antworten auf die andere Frage die Nachricht "indirekte Sortierung verwenden".

Wir können die linearen Indizes (so ähnlich wie find in MATLAB) entsprechend i = [0..N] mit einem Aufruf von numpy.argsort über das abgeflachte Array erhalten:

%Vor%

Aber dann bekommen wir ein einziges großes Array; Welche Indizes gehören zu welchem i ? Wir teilen das Array der Indizes auf Basis der Anzahl der einzelnen i auf:

%Vor%

Wenn Sie die 3D-Indizes irgendwo noch benötigen, können Sie numpy.unravel_index verwenden.

    
user2379410 25.10.2015 16:43
quelle

Tags und Links