Uso de memoria Python de matrices numpy

156

Estoy usando Python para analizar algunos archivos grandes y me encuentro con problemas de memoria, así que he estado usando sys.getsizeof () para tratar de hacer un seguimiento del uso, pero su comportamiento con matrices numpy es extraño. Aquí hay un ejemplo que involucra un mapa de albedos que tengo que abrir:

>>> import numpy as np
>>> import struct
>>> from sys import getsizeof
>>> f = open('Albedo_map.assoc', 'rb')
>>> getsizeof(f)
144
>>> albedo = struct.unpack('%df' % (7200*3600), f.read(7200*3600*4))
>>> getsizeof(albedo)
207360056
>>> albedo = np.array(albedo).reshape(3600,7200)
>>> getsizeof(albedo)
80

Bueno, los datos todavía están allí, pero el tamaño del objeto, un mapa de 3600x7200 píxeles, ha pasado de ~ 200 Mb a 80 bytes. Me gustaría esperar que mis problemas de memoria hayan terminado y simplemente convertir todo en matrices numpy, pero siento que este comportamiento, si es cierto, violaría de alguna manera alguna ley de la teoría de la información o la termodinámica, o algo así, así que estoy inclinados a creer que getsizeof () no funciona con matrices numpy. ¿Algunas ideas?

EddyTheB
fuente
8
De los documentos en adelante sys.getsizeof: "Devuelve el tamaño de un objeto en bytes. El objeto puede ser cualquier tipo de objeto. Todos los objetos integrados devolverán resultados correctos, pero esto no tiene que ser cierto para las extensiones de terceros, ya que es implementación específica. Solo se tiene en cuenta el consumo de memoria directamente atribuido al objeto, no el consumo de memoria de los objetos a los que se refiere ".
Joel Cornett
1
Esto hace getsizeofun indicador poco confiable del consumo de memoria, especialmente para extensiones de terceros.
Joel Cornett
13
Básicamente, el problema aquí es que resizeestá devolviendo un view, no una nueva matriz. Obtiene el tamaño de la vista, no los datos reales.
mgilson
Con ese fin, sys.getsizeof(albedo.base)dará el tamaño de la no vista.
Eric

Respuestas:

236

Puede usar array.nbytespara matrices numpy, por ejemplo:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192
GWW
fuente
Su sys.getsizeof (a), después de importar sys.
eddys
2
b.__sizeof__()es equivalente asys.getsizeof(b)
palash
1
round(getsizeof(a) / 1024 / 1024,2)obtener MB
gies0r
13

El campo nbytes le dará el tamaño en bytes de todos los elementos de la matriz en un numpy.array:

size_in_bytes = my_numpy_array.nbytes

Tenga en cuenta que esto no mide los "atributos que no son elementos del objeto de matriz", por lo que el tamaño real en bytes puede ser unos bytes mayor que este.

El marce
fuente
Esta respuesta todavía crea una matriz, por lo que creo que quiere decir "sin la necesidad de convertir de una lista a una matriz". Aunque es cierto que la respuesta de GWW primero crea una lista y luego la convierte en una matriz, eso no viene al caso, ya que el OP ya tiene una matriz ... El punto es cómo obtener el tamaño de una matriz numpy, por lo que no es crítico cómo obtuviste la matriz en primer lugar. De manera similar, se podría criticar esta respuesta diciendo que reforma una matriz existente.
Moot
Hola @Moot, gracias por el comentario. La pregunta es sobre cómo obtener el tamaño en bytes de una matriz. Si bien es cierto que mi fragmento primero crea una matriz, solo tiene el propósito de tener un ejemplo completo que se pueda ejecutar. Editaré mi respuesta para enfatizar esto.
El Marce
1

En los cuadernos pitón menudo me quiere filtrar 'colgando' numpy.ndarray's, en particular los que están almacenados en _1, _2etc que nunca fueron realmente para mantenerse con vida.

Utilizo este código para obtener una lista de todos ellos y su tamaño.

No estoy seguro si locals()o globals()es mejor aquí.

import sys
import numpy
from humanize import naturalsize

for size, name in sorted(
    (value.nbytes, name)
    for name, value in locals().items()
    if isinstance(value, numpy.ndarray)):
  print("{:>30}: {:>8}".format(name, naturalsize(size)))
Herbert
fuente