Effizient summieren Sie ein kleines numpy Array, das über ein ginormous numpy Array gesendet wird?

8

Ich möchte eine indizierte Gewichtssumme über eine große (1.000.000 x 3.000) boolesches numpy-Array. Das große boolesche Array ändert sich selten, aber die Gewichte kommen zur Abfragezeit, und ich brauche Antworten sehr schnell, ohne das ganze große Array zu kopieren, oder das kleines Gewicht-Array auf die Größe des großen Arrays.

Das Ergebnis sollte ein Array mit 1.000.000 Einträgen sein, von denen jeder die Summe der Gewichtungsfeldeinträge, die der True dieser Zeile entsprechen Werte.

Ich habe mich mit maskierten Arrays beschäftigt, aber sie scheinen ein Gebäude zu erstellen Gewichte Array die Größe meiner großen booleschen Array.

Der folgende Code gibt die richtigen Ergebnisse, aber ich kann mir diese Kopie nicht leisten während des Multiplikationsschritts. Die Multiplikation ist nicht einmal notwendig, da Das Werte-Array ist boolesch, aber es behandelt zumindest die Übertragung richtig.

Ich bin neu zu tapfer und liebe es, aber ich werde es für jetzt aufgeben dieses besondere Problem. Ich habe genug gelernt, um zu wissen, um zu bleiben weg von allem, was in Python Schleifen.

Mein nächster Schritt wird sein, diese Routine in C zu schreiben (was die hinzugefügt hat Vorteil, dass ich Speicher durch die Verwendung von Bits anstelle von Bytes speichern kann, indem der Weg.)

Es sei denn einer von euch numpy Gurus kann mich von Cython retten?

%Vor%     
Jesse Montrose 19.04.2012, 00:36
quelle

4 Antworten

4

Das Punktprodukt (oder inneres Produkt) ist was Sie wollen. Es erlaubt Ihnen, eine Matrix der Größe m×n und einen Vektor der Länge n zu nehmen und sie zu einem Vektor der Länge m zu multiplizieren, wobei jeder Eintrag die gewichtete Summe einer Zeile der Matrix mit den Einträgen von ist der Vektor als Gewichte.

Numpy implementiert dies als array1.dot(array2) (oder numpy.dot(array1, array2) in älteren Versionen). z.B.:

%Vor%

(Sie sollten dies jedoch mit dem Modul timeit vergleichen.)

    
huon 19.04.2012, 01:17
quelle
3

Es ist wahrscheinlich, dass dbaupp die richtige Antwort ist. Aber nur um der Vielfalt willen ist hier eine andere Lösung, die Speicher spart. Dies funktioniert auch bei Vorgängen, die kein integriertes numpy -Äquivalent enthalten.

%Vor%

numpy.lib.stride_tricks.as_strided ist eine wunderbare kleine Funktion! Sie können shape und strides Werte angeben, die es einem kleinen Array erlauben, ein viel größeres Array nachzuahmen. Beachten Sie - es gibt hier keine vier Zeilen; es sieht einfach so aus:

%Vor%

Anstatt also ein riesiges Array an MaskedArray zu übergeben, können Sie einen kleineren übergeben. (Wie Sie jedoch bereits bemerkt haben, funktioniert numpy masking genau so, wie Sie es erwarten würden; Wahrheitsmasken, anstatt zu enthüllen, also müssen Sie values invertiert speichern.) Wie Sie sehen können, MaskedArray kopiert keine Daten; es spiegelt nur was in weights_stretched ist:

%Vor%

Jetzt können wir es einfach an die Summe übergeben:

%Vor%

Ich habe numpy.dot und das obige gegen ein 1.000.000 x 30 Array verglichen. Dies ist das Ergebnis eines relativ modernen MacBook Pro ( numpy.dot ist dot1 ; meiner ist dot2 ):

%Vor%

Wie Sie sehen, ist die integrierte numpy -Lösung schneller. Aber stride_tricks ist unabhängig davon wert, darüber zu wissen, also verlasse ich das.

    
senderle 19.04.2012 02:07
quelle
1

Würde das für Sie funktionieren?

%Vor%

Dies verwendet sum() , um die row * weights -Werte sofort zu summieren, so dass Sie nicht den Speicher benötigen, um alle Zwischenwerte zu speichern. Dann sammelt das Listenverständnis alle Werte.

Sie haben gesagt, dass Sie alles vermeiden wollen, was "in Python läuft". Dies macht zumindest das Schleifen mit den C-Eingeweiden von Python statt einer expliziten Python-Schleife, aber es kann nicht so schnell wie eine NumPy-Lösung sein, da diese kompiliertes C oder Fortran verwendet.

    
steveha 19.04.2012 01:16
quelle
0

Ich glaube nicht, dass Sie so etwas brauchen. Und 1000000 bei 3000 ist eine riesige Reihe; das passt höchstwahrscheinlich nicht in deinen Arbeitsspeicher.

Ich würde es so machen:

Nehmen wir an, Ihre Daten befinden sich ursprünglich in einer Textdatei:

%Vor%

Mein Code:

%Vor%

Ergebnis:

%Vor%

BEARBEITEN:

Ich denke, ich habe die Frage beim ersten Mal ein wenig falsch verstanden und das Ganze zusammenfassen lassen. Hier ist die Lösung, die die genaue Lösung gibt, nach der OP sucht:

%Vor%

Ergebnis:

%Vor%     
Akavall 19.04.2012 01:20
quelle

Tags und Links