Python-Speichernutzung von Numpy-Arrays

156

Ich verwende Python, um einige große Dateien zu analysieren, und es treten Speicherprobleme auf. Daher habe ich sys.getsizeof () verwendet, um die Verwendung zu verfolgen, aber das Verhalten bei numpy Arrays ist bizarr. Hier ist ein Beispiel mit einer Karte von Albedos, die ich öffnen muss:

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

Nun, die Daten sind immer noch da, aber die Größe des Objekts, eine Karte mit 3600 x 7200 Pixeln, ist von ~ 200 MB auf 80 Bytes gestiegen. Ich würde gerne hoffen, dass meine Speicherprobleme vorbei sind und einfach alles in numpy Arrays konvertieren, aber ich habe das Gefühl, dass dieses Verhalten, wenn es wahr ist, in irgendeiner Weise gegen ein Gesetz der Informationstheorie oder Thermodynamik oder so etwas verstoßen würde, also bin ich es geneigt zu glauben, dass getizeof () nicht mit numpy Arrays funktioniert. Irgendwelche Ideen?

EddyTheB
quelle
8
In den Dokumenten heißt es sys.getsizeof: "Geben Sie die Größe eines Objekts in Byte zurück. Das Objekt kann ein beliebiger Objekttyp sein. Alle integrierten Objekte geben korrekte Ergebnisse zurück, dies muss jedoch nicht für Erweiterungen von Drittanbietern gelten Implementierungsspezifisch. Es wird nur der direkt dem Objekt zugeordnete Speicherverbrauch berücksichtigt, nicht der Speicherverbrauch der Objekte, auf die es sich bezieht. "
Joel Cornett
1
Dies ist getsizeofein unzuverlässiger Indikator für den Speicherverbrauch, insbesondere für Erweiterungen von Drittanbietern.
Joel Cornett
13
Grundsätzlich besteht das Problem hier darin, dass ein neues Array resizezurückgegeben wird view, kein neues. Sie erhalten die Größe der Ansicht, nicht die tatsächlichen Daten.
mgilson
Zu diesem Zweck sys.getsizeof(albedo.base)wird die Größe der Nichtansicht angegeben.
Eric

Antworten:

236

Sie können array.nbytesfür numpy Arrays verwenden, zum Beispiel:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192
GWW
quelle
Seine sys.getsizeof (a) nach dem Import von sys.
Eddys
2
b.__sizeof__()entsprichtsys.getsizeof(b)
palash
1
round(getsizeof(a) / 1024 / 1024,2)MB
gies0r
13

Das Feld nbytes gibt Ihnen die Größe aller Elemente des Arrays in Bytes in a numpy.array:

size_in_bytes = my_numpy_array.nbytes

Beachten Sie, dass dies keine "Nicht-Element-Attribute des Array-Objekts" misst, sodass die tatsächliche Größe in Bytes einige Bytes größer sein kann.

El Marce
quelle
Diese Antwort erstellt immer noch ein Array. Ich denke, Sie meinen "ohne die Notwendigkeit, von einer Liste in ein Array zu konvertieren". Obwohl es stimmt, dass die Antwort von GWW zuerst eine Liste erstellt und diese dann in ein Array konvertiert, ist dies nebensächlich, da das OP bereits ein Array hat ... Der Punkt ist, wie die Größe eines numpy-Arrays ermittelt wird, also nicht kritisch, wie Sie das Array überhaupt bekommen haben. In ähnlicher Weise könnte man diese Antwort kritisieren, indem man sagt, dass sie ein vorhandenes Array umformt.
Moot
Hallo @Moot, danke für den Kommentar. Die Frage ist, wie man die Größe eines Arrays in Bytes ermittelt. Es stimmt zwar, dass mein Snippet zuerst ein Array erstellt, es kann jedoch nur zum Zweck eines vollständigen Beispiels ausgeführt werden. Ich werde meine Antwort bearbeiten, um dies zu betonen.
El Marce
1

In Python-Notizbüchern möchte ich oft "baumelnde" herausfiltern numpy.ndarray, insbesondere diejenigen, die in gespeichert _1sind._2 usw. , die am Leben zu bleiben nie wirklich gedacht waren.

Ich benutze diesen Code, um eine Liste aller von ihnen und ihrer Größe zu erhalten.

Ich bin mir nicht sicher, ob locals()oder ob globals()es hier besser ist.

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
quelle