Wykorzystanie pamięci w Pythonie przez tablice numpy

156

Używam Pythona do analizy niektórych dużych plików i mam problemy z pamięcią, więc używam sys.getsizeof (), aby śledzić użycie, ale jego zachowanie z tablicami numpy jest dziwne. Oto przykład obejmujący mapę albedo, którą muszę otworzyć:

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

Cóż, dane nadal tam są, ale rozmiar obiektu, mapy o rozdzielczości 3600x7200 pikseli, wzrósł z ~ 200 Mb do 80 bajtów. Chciałbym mieć nadzieję, że problemy z pamięcią się skończyły i po prostu przekonwertować wszystko na tablice numpy, ale czuję, że to zachowanie, jeśli jest prawdą, w jakiś sposób naruszy jakieś prawo teorii informacji lub termodynamiki, czy coś, więc jestem skłonny wierzyć, że getsizeof () nie działa z tablicami numpy. Jakieś pomysły?

EddyTheB
źródło
8
W dokumentacji sys.getsizeof: „Zwróć rozmiar obiektu w bajtach. Obiekt może być obiektem dowolnego typu. Wszystkie obiekty wbudowane zwrócą poprawne wyniki, ale nie musi to obowiązywać w przypadku rozszerzeń innych firm. specyficzne dla implementacji. Uwzględniane jest tylko zużycie pamięci bezpośrednio przypisane do obiektu, a nie zużycie pamięci przez obiekty, do których się odnosi. "
Joel Cornett
1
To sprawia, getsizeofże wskaźnik zużycia pamięci jest zawodny, szczególnie w przypadku rozszerzeń innych firm.
Joel Cornett
13
Zasadniczo problem polega na tym, że resizezwraca a view, a nie nową tablicę. Otrzymujesz rozmiar widoku, a nie rzeczywiste dane.
mgilson
W tym celu sys.getsizeof(albedo.base)poda rozmiar braku widoku.
Eric

Odpowiedzi:

236

Możesz użyć array.nbytesdla numpy tablic, na przykład:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192
GWW
źródło
Jego sys.getsizeof (a), po wykonaniu importu sys.
eddys
2
b.__sizeof__()jest odpowiednikiemsys.getsizeof(b)
palash
1
round(getsizeof(a) / 1024 / 1024,2)aby zdobyć MB
gies0r
13

Pole nbytes podaje rozmiar w bajtach wszystkich elementów tablicy w a numpy.array:

size_in_bytes = my_numpy_array.nbytes

Zauważ, że to nie mierzy "atrybutów nieelementowych obiektu tablicy", więc rzeczywisty rozmiar w bajtach może być o kilka bajtów większy.

El Marce
źródło
Ta odpowiedź nadal tworzy tablicę, więc myślę, że masz na myśli „bez potrzeby konwertowania z listy na tablicę”. Chociaż prawdą jest, że odpowiedź GWW najpierw tworzy listę, a następnie konwertuje ją na tablicę, to nie ma znaczenia, ponieważ OP ma już tablicę ... Chodzi o to, jak uzyskać rozmiar tablicy numpy, więc tak nie jest najważniejsze jest to, jak otrzymałeś tablicę. Można podobnie skrytykować tę odpowiedź, mówiąc, że zmienia ona istniejącą tablicę.
Moot
Witaj @Moot, dzięki za komentarz. Pytanie dotyczy tego, jak uzyskać rozmiar w bajtach tablicy. Chociaż prawdą jest, że mój fragment kodu najpierw tworzy tablicę, to tylko w celu uzyskania pełnego przykładu, który można wykonać. Zmienię odpowiedź, aby to podkreślić.
El Marce
1

W notatnikach Pythona często chcę odfiltrować „wiszące” numpy.ndarray, w szczególności te, które są przechowywane w _1,_2 itp, które nigdy nie były naprawdę znaczy żyć.

Używam tego kodu, aby uzyskać listę wszystkich z nich i ich rozmiar.

Nie jestem pewien, locals()czy globals()tutaj jest lepiej.

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)))
Herberta
źródło