Sehr große Matrizen mit Python und NumPy

85

NumPy ist eine äußerst nützliche Bibliothek, und ich habe festgestellt, dass sie Matrizen verarbeiten kann, die recht groß sind (10000 x 10000), aber mit viel Größerem zu kämpfen haben (beim Versuch, eine Matrix von 50000 x 50000 zu erstellen) schlägt fehl). Dies liegt offensichtlich an den massiven Speicheranforderungen.

Gibt es eine Möglichkeit, riesige Matrizen in NumPy (z. B. 1 Million mal 1 Million) nativ zu erstellen (ohne mehrere Terrabyte RAM zu haben)?

Peter
quelle

Antworten:

91

PyTables und NumPy sind der richtige Weg.

PyTables speichert die Daten auf der Festplatte im HDF-Format mit optionaler Komprimierung. Meine Datensätze werden häufig 10-fach komprimiert, was praktisch ist, wenn es sich um Dutzende oder Hunderte Millionen Zeilen handelt. Es ist auch sehr schnell; Mein 5 Jahre alter Laptop kann Daten mit einer SQL-ähnlichen GROUP BY-Aggregation mit 1.000.000 Zeilen / Sekunde verarbeiten. Nicht schlecht für eine Python-basierte Lösung!

Der erneute Zugriff auf die Daten als NumPy-Recarray ist so einfach wie:

data = table[row_from:row_to]

Die HDF-Bibliothek sorgt dafür, dass die relevanten Datenblöcke eingelesen und in NumPy konvertiert werden.

Stephen Simmons
quelle
4
Sie müssen die Daten also zur Verarbeitung selbst in Blöcke aufteilen? Es ist nur eine Möglichkeit, die Konvertierung von und zu Festplattendateien zu vereinfachen?
Endolith
Gibt es eine Chance, Ihre Antwort mit etwas mehr Klarheit und einigen Beispielen zu erweitern?
Adam B
56

numpy.arrays sollen in Erinnerung bleiben. Wenn Sie mit Matrizen arbeiten möchten, die größer als Ihr RAM sind, müssen Sie das umgehen. Es gibt mindestens zwei Ansätze, denen Sie folgen können:

  1. Versuchen Sie eine effizientere Matrixdarstellung , die jede spezielle Struktur Ihrer Matrizen ausnutzt. Zum Beispiel gibt es, wie andere bereits betont haben, effiziente Datenstrukturen für dünn besetzte Matrizen (Matrizen mit vielen Nullen), wie z scipy.sparse.csc_matrix.
  2. Ändern Sie Ihren Algorithmus, um mit Submatrizen zu arbeiten . Sie können nur die Matrixblöcke von der Festplatte lesen, die derzeit für Berechnungen verwendet werden. Algorithmen, die für die Ausführung auf Clustern entwickelt wurden, funktionieren normalerweise blockweise, da die Daten auf verschiedene Computer verteilt und nur bei Bedarf übergeben werden. Zum Beispiel der Fox-Algorithmus zur Matrixmultiplikation (PDF-Datei) .
Roberto Bonvallet
quelle
4
3- Schritt in das Big-Data-Paradigma und Studienlösungen wie MapReduce
Medeiros
Wie entscheiden Sie für Nummer 2, wie groß Ihre Brocken sein sollen? Gibt es eine Möglichkeit, die Menge an freiem Speicher und die Größe Ihrer Chunks basierend darauf zu messen?
Endolith
30

Sie sollten in der Lage sein, numpy.memmap zu verwenden, um eine Datei auf der Festplatte zu speichern. Bei neueren Python- und 64-Bit-Computern sollten Sie über den erforderlichen Adressraum verfügen, ohne alles in den Speicher laden zu müssen. Das Betriebssystem sollte nur einen Teil der Datei im Speicher behalten.

DopplerShift
quelle
18
Können Sie ein Beispiel dafür geben, wie Sie damit etwas tun können, das nicht in den Speicher passt?
Endolith
24

So behandeln dünn besetzte Matrizen, müssen Sie das scipyPaket , das von oben sitzt numpy- siehe hier , um weitere Informationen über die spärlichen-Matrix - Optionen , die scipyIhnen gibt.

Alex Martelli
quelle
11

Stefano Borinis Post brachte mich dazu zu untersuchen, wie weit so etwas schon ist.

Das ist es. Es scheint im Grunde zu tun, was Sie wollen. Mit HDF5 können Sie sehr große Datenmengen speichern und dann auf dieselbe Weise wie NumPy darauf zugreifen und sie verwenden.

SingleNegationElimination
quelle
9
Eine bessere Wahl könnte PyTables sein. Es ist höher als die HDF5-Kernfunktionalität (H5Py ist kaum mehr als die von Python aus zugängliche Low-Level-API). Auch die Beta- Version 2.2 der letzten Woche enthält Tools für dieses Problem: pytables.org/moin/ReleaseNotes/Release_2.2b1 Es wurde Expr hinzugefügt, eine Klasse [die] Ausdrücke (wie '3 * a + 4 * b') auswerten kann, die mit beliebig großen Werten arbeiten Arrays bei der Optimierung der Ressourcen [...]. Es ähnelt dem Numexpr-Paket, akzeptiert jedoch zusätzlich zu NumPy-Objekten auch festplattenbasierte homogene Arrays wie die Objekte Array, CArray, EArray und Column PyTables.
AFoglia
5

Stellen Sie sicher, dass Sie ein 64-Bit-Betriebssystem und eine 64-Bit-Version von Python / NumPy verwenden. Beachten Sie, dass Sie auf 32-Bit-Architekturen normalerweise 3 GB Speicher adressieren können (wobei etwa 1 GB durch speicherabgebildete E / A und dergleichen verloren geht).

Mit 64-Bit- und Things-Arrays, die größer als der verfügbare RAM sind, können Sie mit virtuellem Speicher davonkommen, obwohl die Dinge langsamer werden, wenn Sie tauschen müssen. Speicherzuordnungen (siehe numpy.memmap) sind auch eine Möglichkeit, mit großen Dateien auf der Festplatte zu arbeiten, ohne sie in den Speicher zu laden. Sie müssen jedoch über einen 64-Bit-Adressraum verfügen, damit dies von großem Nutzen ist. PyTables erledigt das meiste auch für Sie.

dwf
quelle
4

Manchmal besteht eine einfache Lösung darin, einen benutzerdefinierten Typ für Ihre Matrixelemente zu verwenden. Basierend auf dem von Ihnen benötigten Nummernkreis können Sie ein Handbuch verwenden, das dtypespeziell für Ihre Artikel kleiner ist. Da Numpy standardmäßig den größten Objekttyp berücksichtigt, kann dies in vielen Fällen hilfreich sein. Hier ist ein Beispiel:

In [70]: a = np.arange(5)

In [71]: a[0].dtype
Out[71]: dtype('int64')

In [72]: a.nbytes
Out[72]: 40

In [73]: a = np.arange(0, 2, 0.5)

In [74]: a[0].dtype
Out[74]: dtype('float64')

In [75]: a.nbytes
Out[75]: 32

Und mit benutzerdefiniertem Typ:

In [80]: a = np.arange(5, dtype=np.int8)

In [81]: a.nbytes
Out[81]: 5

In [76]: a = np.arange(0, 2, 0.5, dtype=np.float16)

In [78]: a.nbytes
Out[78]: 8
Kasravnd
quelle
3

Fragen Sie sich, wie Sie mit einer 2.500.000.000-Elementmatrix ohne Terabyte RAM umgehen sollen?

Die Möglichkeit, 2 Milliarden Elemente ohne 8 Milliarden Byte RAM zu verarbeiten, besteht darin, die Matrix nicht im Speicher zu halten.

Das bedeutet viel ausgefeiltere Algorithmen, um es in Teilen aus dem Dateisystem abzurufen.

S.Lott
quelle
7
Nicht wahr. Wenn 99,99% (für ein realistisches Beispiel) der Elemente Null sind, können alle Daten der Matrix gespeichert werden. Es ist nicht erforderlich, 4 Bytes für jede Null zu verbrauchen, wenn Sie nur eine Liste der vorhandenen (row, column, value)Einträge speichern können .
Eric Wilson
6
@ EricWilson: Wo in der Frage wurde darauf hingewiesen, dass die Matrix spärlich war? Das habe ich total vermisst. Können Sie das Angebot machen?
S.Lott
1

Wenn wir mit großen Matrizen arbeiten, implementieren wir sie normalerweise als Sparse-Matrizen .

Ich weiß nicht, ob Numpy spärliche Matrizen unterstützt, aber ich habe dies stattdessen gefunden.

Nick Dandoulakis
quelle
1

Soweit ich über Numpy Bescheid weiß, nein, aber ich könnte mich irren.

Ich kann Ihnen diese alternative Lösung vorschlagen: Schreiben Sie die Matrix auf die Festplatte und greifen Sie in Blöcken darauf zu. Ich schlage Ihnen das HDF5-Dateiformat vor. Wenn Sie es transparent benötigen, können Sie die ndarray-Schnittstelle erneut implementieren, um Ihre auf der Festplatte gespeicherte Matrix in den Speicher zu paginieren. Seien Sie vorsichtig, wenn Sie die Daten so ändern, dass sie wieder auf der Festplatte synchronisiert werden.

Stefano Borini
quelle
Was ist, wenn ich auf eine ganze Matrix von 57600 mal 57600 zugreifen möchte?
Gunjan Naik