Uso de memória Python de matrizes numpy

156

Estou usando o python para analisar alguns arquivos grandes e estou com problemas de memória, por isso tenho usado o sys.getsizeof () para tentar acompanhar o uso, mas seu comportamento com matrizes numpy é bizarro. Aqui está um exemplo envolvendo um mapa de albedos que estou tendo que abrir:

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

Bem, os dados ainda estão lá, mas o tamanho do objeto, um mapa de 3600x7200 pixels, passou de ~ 200 Mb para 80 bytes. Gostaria de ter esperança de que meus problemas de memória tenham acabado e convertido tudo em matrizes numpy, mas acho que esse comportamento, se verdadeiro, de alguma forma violaria alguma lei da teoria da informação ou da termodinâmica, ou algo assim, então estou inclinado a acreditar que getsizeof () não funciona com matrizes numpy. Alguma ideia?

EddyTheB
fonte
8
Dos documentos em sys.getsizeof: "Retorne o tamanho de um objeto em bytes. O objeto pode ser qualquer tipo de objeto. Todos os objetos internos retornarão resultados corretos, mas isso não precisa ser verdadeiro para extensões de terceiros, pois é implementação específica. Somente o consumo de memória diretamente atribuído ao objeto é contabilizado, não o consumo de memória dos objetos a que ele se refere. "
Joel Cornett
1
Isso cria getsizeofum indicador não confiável de consumo de memória, especialmente para extensões de terceiros.
Joel Cornett
13
Basicamente, o problema aqui é o resizeretorno de uma viewmatriz, não de uma nova. Você está obtendo o tamanho da visualização, não os dados reais.
mgilson
Para esse fim, sys.getsizeof(albedo.base)fornecerá o tamanho da não visualização.
Eric

Respostas:

236

Você pode usar array.nbytespara matrizes numpy, por exemplo:

>>> import numpy as np
>>> from sys import getsizeof
>>> a = [0] * 1024
>>> b = np.array(a)
>>> getsizeof(a)
8264
>>> b.nbytes
8192
GWW
fonte
Seu sys.getsizeof (a), depois de fazer o sys de importação.
Eddys
2
b.__sizeof__()é equivalente asys.getsizeof(b)
palash
1
round(getsizeof(a) / 1024 / 1024,2)MB
gies0r
13

O campo nbytes fornecerá o tamanho em bytes de todos os elementos da matriz em um numpy.array:

size_in_bytes = my_numpy_array.nbytes

Observe que isso não mede "atributos que não são elementos do objeto de matriz", portanto o tamanho real em bytes pode ser alguns bytes maior que isso.

El Marce
fonte
Essa resposta ainda cria uma matriz, então acho que você quer dizer "sem a necessidade de converter de uma lista para uma matriz". Embora seja verdade que a resposta do GWW primeiro cria uma lista e depois a converte em uma matriz, isso não vem ao caso, já que o OP já possui uma matriz ... A questão é como obter o tamanho de uma matriz numpy, portanto não é crítico como você conseguiu a matriz em primeiro lugar. Poder-se-ia igualmente criticar essa resposta dizendo que ela reformula uma matriz existente.
187 Moot
Olá @Moot, obrigado pelo comentário. A questão é sobre como obter o tamanho em bytes de uma matriz. Embora seja verdade que meu snippet primeiro cria uma matriz, é apenas para ter um exemplo completo que pode ser executado. Vou editar minha resposta para enfatizar isso.
El Marce
1

Em cadernos python muitas vezes eu quiser filtrar 'pendurada' numpy.ndarray's, em particular os que estão armazenados em _1, _2, etc que nunca foram feitos para permanecer vivo.

Eu uso esse código para obter uma lista de todos eles e seu tamanho.

Não tenho certeza se locals()ou globals()é melhor aqui.

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
fonte