Utilisation de la mémoire Python des tableaux numpy

156

J'utilise python pour analyser certains fichiers volumineux et je rencontre des problèmes de mémoire, j'ai donc utilisé sys.getsizeof () pour essayer de garder une trace de l'utilisation, mais son comportement avec les tableaux numpy est bizarre. Voici un exemple impliquant une carte d'albédos que je dois ouvrir:

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

Eh bien, les données sont toujours là, mais la taille de l'objet, une carte de 3600x7200 pixels, est passée d'environ 200 Mo à 80 octets. J'espère que mes problèmes de mémoire sont terminés et que je convertis simplement tout en tableaux numpy, mais je pense que ce comportement, s'il est vrai, violerait d'une certaine manière une loi de la théorie de l'information ou de la thermodynamique, ou quelque chose comme ça, alors je suis enclin à croire que getsizeof () ne fonctionne pas avec les tableaux numpy. Des idées?

EddyTheB
la source
8
À partir de la documentation sys.getsizeof: "Renvoie la taille d'un objet en octets. L'objet peut être n'importe quel type d'objet. Tous les objets intégrés renverront des résultats corrects, mais cela ne doit pas nécessairement être vrai pour les extensions tierces. spécifique à l'implémentation. Seule la consommation de mémoire directement attribuée à l'objet est prise en compte, et non la consommation de mémoire des objets auxquels il fait référence. "
Joel Cornett
1
Cela rend getsizeofun indicateur peu fiable de la consommation de mémoire, en particulier pour les extensions tierces.
Joel Cornett
13
Fondamentalement, le problème ici est de resizerenvoyer un viewtableau, pas un nouveau tableau. Vous obtenez la taille de la vue, pas les données réelles.
mgilson
À cette fin, sys.getsizeof(albedo.base)donnera la taille de la non-vue.
Eric

Réponses:

236

Vous pouvez utiliser array.nbytespour les tableaux numpy, par exemple:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192
GWW
la source
Son sys.getsizeof (a), après avoir effectué l'importation sys.
eddys
2
b.__sizeof__()équivaut àsys.getsizeof(b)
palash le
1
round(getsizeof(a) / 1024 / 1024,2)pour obtenir MB
gies0r
13

Le champ nbytes vous donnera la taille en octets de tous les éléments du tableau dans un numpy.array:

size_in_bytes = my_numpy_array.nbytes

Notez que cela ne mesure pas les «attributs non élémentaires de l'objet tableau», de sorte que la taille réelle en octets peut être supérieure de quelques octets.

El Marce
la source
Cette réponse crée toujours un tableau, donc je pense que vous voulez dire "sans avoir besoin de convertir une liste en tableau". Bien qu'il soit vrai que la réponse de GWW crée d'abord une liste puis la convertit en tableau, ce n'est pas pertinent, puisque l'OP a déjà un tableau ... Le but est de savoir comment obtenir la taille d'un tableau numpy, donc ce n'est pas critique comment vous avez obtenu le tableau en premier lieu. On pourrait également critiquer cette réponse en disant qu'elle remodèle un tableau existant.
Moot
Bonjour @Moot, merci pour le commentaire. La question est de savoir comment obtenir la taille en octets d'un tableau. S'il est vrai que mon extrait de code crée d'abord un tableau, ce n'est que dans le but d'avoir un exemple complet qui peut être exécuté. Je modifierai ma réponse pour souligner cela.
El Marce
1

Dans les ordinateurs portables de python Je veux souvent filtrer « ballants » numpy.ndarray« s, en particulier ceux qui sont stockés dans _1, _2, etc. qui ont jamais été vraiment destiné à rester en vie.

J'utilise ce code pour obtenir une liste de tous et de leur taille.

Je ne sais pas si locals()ou globals()est mieux ici.

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