Matrices très volumineuses utilisant Python et NumPy

86

NumPy est une bibliothèque extrêmement utile, et en l'utilisant, j'ai découvert qu'elle était capable de gérer facilement des matrices assez grandes (10000 x 10000), mais qu'elle commençait à se débattre avec tout ce qui est beaucoup plus grand (en essayant de créer une matrice de 50000 x 50000 échoue). De toute évidence, cela est dû aux énormes besoins en mémoire.

Existe-t-il un moyen de créer d'énormes matrices nativement dans NumPy (disons 1 million par 1 million) d'une manière ou d'une autre (sans avoir plusieurs terrabytes de RAM)?

Peter
la source

Réponses:

91

PyTables et NumPy sont la voie à suivre.

PyTables stockera les données sur disque au format HDF, avec une compression facultative. Mes ensembles de données obtiennent souvent une compression 10x, ce qui est pratique lorsqu'il s'agit de dizaines ou de centaines de millions de lignes. C'est aussi très rapide; mon ordinateur portable de 5 ans peut analyser les données en effectuant une agrégation GROUP BY de type SQL à 1 000 000 lignes / seconde. Pas mal pour une solution basée sur Python!

Accéder à nouveau aux données en tant que recarray NumPy est aussi simple que:

data = table[row_from:row_to]

La bibliothèque HDF prend en charge la lecture des blocs de données pertinents et la conversion en NumPy.

Stephen Simmons
la source
4
Vous devez donc encore diviser vous-même les données en morceaux pour les traiter? C'est juste un moyen de simplifier la conversion vers et à partir de fichiers disque?
endolith
Avez-vous une chance d'élargir votre réponse avec un peu plus de clarté et quelques exemples?
Adam B
56

numpy.arrays sont destinés à vivre dans la mémoire. Si vous souhaitez travailler avec des matrices plus grandes que votre RAM, vous devez contourner cela. Vous pouvez suivre au moins deux approches:

  1. Essayez une représentation matricielle plus efficace qui exploite toute structure spéciale de vos matrices. Par exemple, comme d'autres l'ont déjà souligné, il existe des structures de données efficaces pour les matrices éparses (matrices avec beaucoup de zéros), comme scipy.sparse.csc_matrix.
  2. Modifiez votre algorithme pour travailler sur des sous-matrices . Vous ne pouvez lire à partir du disque que les blocs matriciels actuellement utilisés dans les calculs. Les algorithmes conçus pour s'exécuter sur des clusters fonctionnent généralement par blocs, car les données sont dispersées sur différents ordinateurs et transmises uniquement en cas de besoin. Par exemple, l'algorithme de Fox pour la multiplication matricielle (fichier PDF) .
Roberto Bonvallet
la source
4
3- Entrez dans le paradigme du Big Data et étudiez des solutions comme MapReduce
Medeiros
Pour le numéro 2, comment décidez-vous de la taille de vos morceaux? Existe-t-il un moyen de mesurer la quantité de mémoire libre et de dimensionner vos blocs en fonction de cela?
endolith
30

Vous devriez pouvoir utiliser numpy.memmap pour mapper en mémoire un fichier sur le disque. Avec les nouveaux python et les machines 64 bits, vous devriez avoir l'espace d'adressage nécessaire, sans tout charger en mémoire. Le système d'exploitation ne doit gérer qu'une partie du fichier en mémoire.

Doppler
la source
18
Pouvez-vous donner un exemple de la façon de l'utiliser pour faire quelque chose qui ne tient pas dans la mémoire?
endolith
24

Pour gérer les matrices clairsemées, vous avez besoin du scipypackage qui se trouve au-dessus de numpy- voir ici pour plus de détails sur les options de matrice clairsemée que scipyvous offre.

Alex Martelli
la source
11

Le message de Stefano Borini m'a amené à me demander à quel point ce genre de choses est déjà avancé.

Ça y est. Il semble faire essentiellement ce que vous voulez. HDF5 vous permettra de stocker de très grands ensembles de données, puis d'y accéder et de les utiliser de la même manière que NumPy.

SingleNegationElimination
la source
9
Un meilleur choix pourrait être PyTables. C'est un niveau supérieur à la fonctionnalité HDF5 de base (H5Py n'est guère plus que l'API de bas niveau accessible depuis Python). La version 2.2 bêta de la semaine dernière a également des outils pour résoudre ce problème: pytables.org/moin/ReleaseNotes/Release_2.2b1 Ajout d' Expr , une classe [qui] peut évaluer des expressions (comme '3 * a + 4 * b') qui fonctionnent sur des tableaux tout en optimisant les ressources [...]. Il est similaire au package Numexpr, mais en plus des objets NumPy, il accepte également les tableaux homogènes basés sur disque, comme les objets Array, CArray, EArray et Column PyTables.
AFoglia le
5

Assurez-vous que vous utilisez un système d'exploitation 64 bits et une version 64 bits de Python / NumPy. Notez que sur les architectures 32 bits, vous pouvez généralement adresser 3 Go de mémoire (avec environ 1 Go de perte pour les E / S mappées en mémoire et autres).

Avec des baies 64 bits et des objets plus grands que la RAM disponible, vous pouvez vous en sortir avec la mémoire virtuelle, bien que les choses ralentissent si vous devez échanger. De plus, les cartes mémoire (voir numpy.memmap) sont un moyen de travailler avec d'énormes fichiers sur le disque sans les charger en mémoire, mais encore une fois, vous devez disposer d'un espace d'adressage de 64 bits pour que cela soit d'une grande utilité. PyTables fera également la plupart de cela pour vous.

dwf
la source
4

Parfois, une solution simple consiste à utiliser un type personnalisé pour vos éléments de matrice. En fonction de la plage de nombres dont vous avez besoin, vous pouvez utiliser un manuel dtypeet spécialement plus petit pour vos articles. Étant donné que Numpy considère le plus grand type d'objet par défaut, cela peut être une idée utile dans de nombreux cas. Voici un exemple:

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

Et avec un type personnalisé:

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
la source
3

Demandez-vous comment gérer une matrice d'élément de 2 500 000 000 sans téraoctets de RAM?

La façon de gérer 2 milliards d'éléments sans 8 milliards d'octets de RAM est de ne pas garder la matrice en mémoire.

Cela signifie des algorithmes beaucoup plus sophistiqués pour le récupérer du système de fichiers en morceaux.

S.Lott
la source
7
Pas vrai. Si 99,99% (pour un exemple réaliste) des éléments sont nuls, alors toutes les données de la matrice peuvent être conservées en mémoire. Il n'est pas nécessaire d'utiliser jusqu'à 4 octets pour chaque zéro, lorsque vous pouvez simplement stocker une liste de (row, column, value)pour les entrées qui existent.
Eric Wilson
6
@EricWilson: Où dans la question suggérait-il que la matrice était clairsemée? Cela m'a totalement manqué. Pouvez-vous fournir le devis?
S.Lott
1

Habituellement, lorsque nous traitons de grandes matrices, nous les implémentons sous forme de matrices clairsemées .

Je ne sais pas si numpy prend en charge les matrices clairsemées, mais j'ai trouvé cela à la place.

Nick Dandoulakis
la source
1

Autant que je sache sur numpy, non, mais je peux me tromper.

Je peux vous proposer cette solution alternative: écrire la matrice sur le disque et y accéder par blocs. Je vous suggère le format de fichier HDF5. Si vous en avez besoin de manière transparente, vous pouvez réimplémenter l'interface ndarray pour paginer votre matrice stockée sur disque en mémoire. Faites attention si vous modifiez les données pour les synchroniser à nouveau sur le disque.

Stefano Borini
la source
Et si je veux accéder à une matrice entière de 57600 par 57600?
Gunjan naik