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% 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.:
(Sie sollten dies jedoch mit dem Modul timeit
vergleichen.)
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.
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:
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:
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
):
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.
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.
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%