Matrices muy grandes usando Python y NumPy

86

NumPy es una biblioteca extremadamente útil, y al usarla descubrí que es capaz de manejar matrices que son bastante grandes (10000 x 10000) fácilmente, pero comienza a tener problemas con cualquier cosa mucho más grande (tratando de crear una matriz de 50000 x 50000). falla). Obviamente, esto se debe a los enormes requisitos de memoria.

¿Hay alguna manera de crear matrices enormes de forma nativa en NumPy (digamos 1 millón por 1 millón) de alguna manera (sin tener varios terrabytes de RAM)?

Pedro
fuente

Respuestas:

91

PyTables y NumPy son el camino a seguir.

PyTables almacenará los datos en el disco en formato HDF, con compresión opcional. Mis conjuntos de datos a menudo obtienen una compresión de 10x, lo que es útil cuando se trata de decenas o cientos de millones de filas. También es muy rápido; mi computadora portátil de 5 años puede procesar datos haciendo una agregación GROUP BY similar a SQL a 1,000,000 filas / segundo. ¡Nada mal para una solución basada en Python!

Acceder de nuevo a los datos como recarray NumPy es tan sencillo como:

data = table[row_from:row_to]

La biblioteca HDF se encarga de leer los fragmentos de datos relevantes y convertirlos a NumPy.

Stephen Simmons
fuente
4
Entonces, ¿aún tiene que dividir los datos en trozos usted mismo para procesarlos? ¿Es solo una forma de simplificar la conversión hacia y desde archivos de disco?
endolito
¿Alguna posibilidad de que pueda ampliar su respuesta con un poco más de claridad y algunos ejemplos?
Adam B
56

numpy.arrays están destinados a vivir en la memoria. Si desea trabajar con matrices más grandes que su RAM, debe solucionarlo. Hay al menos dos enfoques que puede seguir:

  1. Pruebe una representación matricial más eficiente que aproveche cualquier estructura especial que tengan sus matrices. Por ejemplo, como ya han señalado otros, existen estructuras de datos eficientes para matrices dispersas (matrices con muchos ceros), como scipy.sparse.csc_matrix.
  2. Modifique su algoritmo para trabajar en submatrices . Puede leer desde el disco solo los bloques de matriz que se están utilizando actualmente en los cálculos. Los algoritmos diseñados para ejecutarse en clústeres generalmente funcionan en bloques, ya que los datos se distribuyen en diferentes computadoras y solo se pasan cuando es necesario. Por ejemplo, el algoritmo de Fox para la multiplicación de matrices (archivo PDF) .
Roberto Bonvallet
fuente
4
3- Ingrese al paradigma de Big Data y estudie soluciones como MapReduce
Medeiros
Para el número 2, ¿cómo decides el tamaño de tus trozos? ¿Hay alguna forma de medir la cantidad de memoria libre y dimensionar sus fragmentos en función de eso?
endolito
30

Debería poder usar numpy.memmap para mapear en memoria un archivo en el disco. Con Python más nuevo y una máquina de 64 bits, debe tener el espacio de direcciones necesario, sin cargar todo en la memoria. El sistema operativo debe manejar solo mantener parte del archivo en la memoria.

Desplazamiento Doppler
fuente
19
¿Puede dar un ejemplo de cómo usarlo para hacer algo que no cabe en la memoria?
endolito
24

Para manejar matrices dispersas, necesita el scipypaquete que se encuentra en la parte superior numpy; consulte aquí para obtener más detalles sobre las opciones de matriz dispersa que scipyle brinda.

Alex Martelli
fuente
11

La publicación de Stefano Borini me hizo ver qué tan avanzado está este tipo de cosas.

Eso es todo. Parece hacer básicamente lo que quieres. HDF5 le permitirá almacenar conjuntos de datos muy grandes y luego acceder a ellos y usarlos de la misma manera que lo hace NumPy.

SingleNegationElimination
fuente
9
Una mejor opción podría ser PyTables. Es un nivel más alto que la funcionalidad principal de HDF5 (H5Py es poco más que la API de bajo nivel accesible desde Python). También la versión beta 2.2 de la semana pasada tiene herramientas para este problema: pytables.org/moin/ReleaseNotes/Release_2.2b1 Se agregó Expr, una clase [que] puede evaluar expresiones (como '3 * a + 4 * b') que operan en matrices optimizando los recursos [...]. Es similar al paquete Numexpr, pero además de los objetos NumPy, también acepta matrices homogéneas basadas en disco, como los objetos Array, CArray, EArray y Column PyTables.
AFoglia
5

Asegúrate de estar usando un sistema operativo de 64 bits y una versión de Python / NumPy de 64 bits. Tenga en cuenta que en las arquitecturas de 32 bits puede abordar normalmente 3 GB de memoria (con aproximadamente 1 GB perdido en E / S mapeadas en memoria y demás).

Con arreglos de 64 bits y otros más grandes que la RAM disponible, puede salirse con la memoria virtual, aunque las cosas se volverán más lentas si tiene que intercambiar. Además, los mapas de memoria (consulte numpy.memmap) son una forma de trabajar con archivos grandes en el disco sin cargarlos en la memoria, pero nuevamente, debe tener un espacio de direcciones de 64 bits para trabajar para que esto sea de mucha utilidad. PyTables también hará la mayor parte de esto por usted.

dwf
fuente
4

A veces, una solución simple es utilizar un tipo personalizado para sus elementos de matriz. Según el rango de números que necesite, puede utilizar un manual dtypey especialmente más pequeño para sus artículos. Dado que Numpy considera el tipo de objeto más grande de forma predeterminada, esta podría ser una idea útil en muchos casos. Aquí hay un ejemplo:

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

Y con tipo personalizado:

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
fuente
3

¿Está preguntando cómo manejar una matriz de elementos de 2.500.000.000 sin terabytes de RAM?

La forma de manejar 2 mil millones de elementos sin 8 mil millones de bytes de RAM es no mantener la matriz en la memoria.

Eso significa algoritmos mucho más sofisticados para recuperarlo del sistema de archivos en partes.

S. Lot
fuente
7
No es verdad. Si el 99,99% (para un ejemplo realista) de los elementos son cero, entonces todos los datos de la matriz se pueden guardar en la memoria. No es necesario utilizar hasta 4 bytes por cada cero, cuando solo puede almacenar una lista de (row, column, value)las entradas que existen.
Eric Wilson
6
@EricWilson: ¿En qué parte de la pregunta sugirió que la matriz era escasa? Lo extrañaba totalmente. ¿Puede proporcionar la cotización?
S.Lott
1

Por lo general, cuando tratamos con matrices grandes, las implementamos como matrices dispersas .

No sé si numpy admite matrices dispersas, pero encontré esto en su lugar.

Nick Dandoulakis
fuente
1

Por lo que sé sobre numpy, no, pero podría estar equivocado.

Puedo proponerle esta solución alternativa: escriba la matriz en el disco y acceda a ella en trozos. Te sugiero el formato de archivo HDF5. Si lo necesita de forma transparente, puede volver a implementar la interfaz ndarray para paginar su matriz almacenada en disco en la memoria. Tenga cuidado si modifica los datos para sincronizarlos nuevamente en el disco.

Stefano Borini
fuente
¿Qué sucede si quiero acceder a una matriz completa de 57600 por 57600?
Gunjan naik