Использование памяти Python массивов numpy

156

Я использую python для анализа некоторых больших файлов и сталкиваюсь с проблемами с памятью, поэтому я использовал sys.getsizeof (), чтобы попытаться отследить использование, но его поведение с массивными массивами странное. Вот пример с картой альбедо, которую я должен открыть:

>>> 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 байт. Я хотел бы надеяться, что мои проблемы с памятью закончились и просто конвертировать все в массивы, но я чувствую, что это поведение, если оно истинно, каким-то образом нарушит некоторый закон теории информации или термодинамики, или что-то еще, так что я склонен полагать, что getsizeof () не работает с массивами numpy. Любые идеи?

EddyTheB
источник
8
Из документации sys.getsizeof: «Возвращать размер объекта в байтах. Объект может быть объектом любого типа. Все встроенные объекты будут возвращать правильные результаты, но это не обязательно должно быть справедливо для сторонних расширений, как есть». зависит от реализации. Учитывается только потребление памяти, непосредственно приписываемое объекту, а не потребление памяти объектами, к которым он относится ».
Джоэл Корнетт
1
Это делает getsizeofненадежным индикатором потребления памяти, особенно для сторонних расширений.
Джоэл Корнетт
13
По сути, проблема здесь в том, что resizeвозвращается, а viewне новый массив. Вы получаете размер представления, а не фактические данные.
Мгилсон
С этой целью, sys.getsizeof(albedo.base)даст размер не вид.
Эрик

Ответы:

236

Вы можете использовать array.nbytesдля пустых массивов, например:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192
GWW
источник
Это 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 сначала создает список, а затем преобразует его в массив, это не относится к делу, поскольку у OP уже есть массив ... Дело в том, как получить размер массива с нулевыми значениями, поэтому критично, как вы получили массив в первую очередь. Можно так же критиковать этот ответ, сказав, что он изменяет существующий массив.
Спорный
Здравствуйте, @Moot, спасибо за комментарий. Вопрос в том, как получить размер в байтах массива. Хотя верно, что мой фрагмент сначала создает массив, это только для того, чтобы иметь полный пример, который может быть выполнен. Я отредактирую свой ответ, чтобы подчеркнуть это.
Эль Марс
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)))
Герберт
источник