Використання пам’яті Python з numpy масивів


156

Я використовую python для аналізу деяких великих файлів, і я стикаюся з проблемами пам'яті, тому я використовую sys.getsizeof (), щоб спробувати відстежувати використання, але його поведінка з numpy масивами є химерним. Ось приклад із картою альбедосів, яку мені потрібно відкрити:

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

Ну, дані все ще є, але розмір об'єкта, карта пікселів 3600x7200, пішов від ~ 200 Мб до 80 байт. Хотілося б сподіватися, що проблеми з моєю пам’яттю закінчені і просто перетворять усе на нумерові масиви, але я вважаю, що така поведінка, якщо це правда, певним чином порушить якийсь закон теорії інформації чи термодинаміку, чи щось таке, тож я схильний вважати, що getizeof () не працює з numpy масивами. Будь-які ідеї?


8
З Документів на тему sys.getsizeof: "Повернути розмір об'єкта в байтах. Об'єктом може бути будь-який тип об'єкта. Усі вбудовані об'єкти повернуть правильні результати, але це не має бути правдою для сторонніх розширень, як це є конкретна реалізація. Обліковується лише споживання пам'яті, безпосередньо приписане об'єкту, а не споживання пам'яті об'єктів, на які він посилається. "
Джоел Корнетт

1
Це робить getsizeofнадійним показником споживання пам'яті, особливо для сторонніх розширень.
Джоел Корнетт

13
В основному, проблема полягає в тому, що resizeце повернення a view, а не новий масив. Ви отримуєте розмір перегляду, а не фактичні дані.
mgilson

З цією метою sys.getsizeof(albedo.base)надасть розмір неперегляду.
Ерік

Відповіді:


236

Ви можете використовувати array.nbytesдля nummy масивів, наприклад:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192

Його sys.getsizeof (a) після імпорту sys.
eddys

2
b.__sizeof__()еквівалентноsys.getsizeof(b)
палаш

1
round(getsizeof(a) / 1024 / 1024,2)щоб отримати MB
gies0r

13

Поле nbytes надасть вам розмір у байтах усіх елементів масиву в numpy.array:

size_in_bytes = my_numpy_array.nbytes

Зауважте, що це не вимірює "неелементні атрибути об'єкта масиву", тому фактичний розмір у байтах може бути на кілька байт більшим, ніж цей.


Ця відповідь все ще створює масив, тому я думаю, ви маєте на увазі "без необхідності перетворення зі списку в масив". Хоча це правда, що відповідь GWW спочатку створює список, а потім перетворює його в масив, це поруч із пунктом, оскільки в ОП вже є масив ... Справа в тому, як отримати розмір нумерованого масиву, так що це не критично, як ви отримали масив в першу чергу. Можна також аналогічно критикувати цю відповідь, сказавши, що вона переробляє існуючий масив.
Мут

Привіт @Moot, дякую за коментар. Питання полягає в тому, як отримати розмір у байтах масиву. Хоча це правда, що мій фрагмент спочатку створює масив, але тільки для того, щоб мати повний приклад, який можна виконати. Я відредагую свою відповідь, щоб наголосити на цьому.
El Marce

1

У Пітоні ноутбуках я часто хочу , щоб відфільтрувати «обірваним» numpy.ndarray«s, зокрема ті, які зберігаються в _1, _2і т.д. , які ніколи не були призначені , щоб залишитися в живих.

Я використовую цей код, щоб отримати список усіх їх розмірів.

Не знаєте, locals()чи globals()краще тут.

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)))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.