Matrizes muito grandes usando Python e NumPy

86

NumPy é uma biblioteca extremamente útil e, ao usá-la, descobri que é capaz de lidar com matrizes muito grandes (10000 x 10000) facilmente, mas começa a lutar com qualquer coisa muito maior (tentando criar uma matriz de 50000 x 50000 falhar). Obviamente, isso se deve aos enormes requisitos de memória.

Existe uma maneira de criar matrizes enormes nativamente no NumPy (digamos 1 milhão por 1 milhão) de alguma forma (sem ter vários terrabytes de RAM)?

Peter
fonte

Respostas:

91

PyTables e NumPy são o caminho a percorrer.

PyTables armazenará os dados em disco no formato HDF, com compactação opcional. Meus conjuntos de dados costumam ter compactação 10x, o que é útil ao lidar com dezenas ou centenas de milhões de linhas. Também é muito rápido; meu laptop de 5 anos pode processar dados fazendo agregação GROUP BY semelhante a SQL a 1.000.000 linhas / segundo. Nada mal para uma solução baseada em Python!

Acessar os dados como um recarray NumPy novamente é tão simples como:

data = table[row_from:row_to]

A biblioteca HDF cuida da leitura dos blocos de dados relevantes e da conversão para NumPy.

Stephen Simmons
fonte
4
Então, você ainda precisa dividir os dados em partes para processamento? É apenas uma maneira de simplificar a conversão de e para os arquivos do disco?
endolith
Alguma chance de você expandir sua resposta com um pouco mais de clareza e alguns exemplos?
Adam B
56

numpy.arrays são feitos para viver na memória. Se você deseja trabalhar com matrizes maiores do que sua RAM, você deve contornar isso. Existem pelo menos duas abordagens que você pode seguir:

  1. Tente uma representação de matriz mais eficiente que explore qualquer estrutura especial que suas matrizes tenham. Por exemplo, como outros já apontaram, existem estruturas de dados eficientes para matrizes esparsas (matrizes com muitos zeros), como scipy.sparse.csc_matrix.
  2. Modifique seu algoritmo para trabalhar em submatrizes . Você pode ler do disco apenas os blocos da matriz que estão sendo usados ​​atualmente em cálculos. Algoritmos projetados para serem executados em clusters geralmente funcionam em blocos, uma vez que os dados são espalhados por diferentes computadores e são transmitidos apenas quando necessário. Por exemplo, o algoritmo Fox para multiplicação de matrizes (arquivo PDF) .
Roberto Bonvallet
fonte
4
3- Entre no paradigma do Big Data e estude soluções como MapReduce
Medeiros
Para o número 2, como você decide o tamanho de seus pedaços? Existe uma maneira de medir a quantidade de memória livre e dimensionar seus blocos com base nisso?
endolith
30

Você deve ser capaz de usar numpy.memmap para mapear a memória de um arquivo no disco. Com o python mais recente e a máquina de 64 bits, você deve ter o espaço de endereço necessário, sem carregar tudo na memória. O sistema operacional deve controlar apenas manter parte do arquivo na memória.

DopplerShift
fonte
19
Você pode dar um exemplo de como usá-lo para fazer algo que não cabe na memória?
endolith
24

Para lidar com matrizes esparsas, você precisa do scipypacote que fica no topo numpy- veja aqui para mais detalhes sobre as opções de matrizes esparsas que scipyoferece.

Alex Martelli
fonte
11

O post de Stefano Borini me fez ver o quão longe esse tipo de coisa já está.

É isso. Parece fazer basicamente o que você deseja. HDF5 permitirá que você armazene conjuntos de dados muito grandes e, em seguida, acesse e os use da mesma maneira que o NumPy.

SingleNegationElimination
fonte
9
Uma escolha melhor pode ser PyTables. É um nível mais alto do que a funcionalidade HDF5 principal (H5Py é pouco mais do que a API de baixo nível acessível a partir do Python). Além disso, o beta 2.2 da semana passada tem ferramentas para este problema: pytables.org/moin/ReleaseNotes/Release_2.2b1 Adicionado Expr, uma classe [que] pode avaliar expressões (como '3 * a + 4 * b') que operam em grande arbitrário arrays otimizando os recursos [...]. É semelhante ao pacote Numexpr, mas além dos objetos NumPy, também aceita matrizes homogêneas baseadas em disco, como os objetos Array, CArray, EArray e Column PyTables.
AFoglia
5

Certifique-se de usar um sistema operacional de 64 bits e uma versão de Python / NumPy de 64 bits. Observe que em arquiteturas de 32 bits, você pode endereçar normalmente 3 GB de memória (com cerca de 1 GB perdido para E / S mapeada de memória e outros).

Com arrays de 64 bits e coisas maiores do que a RAM disponível, você pode se safar com a memória virtual, embora as coisas fiquem mais lentas se você precisar trocar. Além disso, os mapas de memória (consulte numpy.memmap) são uma forma de trabalhar com arquivos enormes no disco sem carregá-los na memória, mas, novamente, você precisa ter um espaço de endereço de 64 bits para trabalhar para que seja útil. PyTables fará a maior parte disso para você também.

dwf
fonte
4

Às vezes, uma solução simples é usar um tipo personalizado para seus itens de matriz. Com base na gama de números que você precisa, você pode usar um manual dtypee especialmente menor para seus itens. Como o Numpy considera o maior tipo de objeto por padrão, isso pode ser uma ideia útil em muitos casos. Aqui está um exemplo:

In [70]: a = np.arange(5)

In [71]: a[0].dtype
Out[71]: dtype('int64')

In [72]: a.nbytes
Out[72]: 40

In [73]: a = np.arange(0, 2, 0.5)

In [74]: a[0].dtype
Out[74]: dtype('float64')

In [75]: a.nbytes
Out[75]: 32

E com tipo personalizado:

In [80]: a = np.arange(5, dtype=np.int8)

In [81]: a.nbytes
Out[81]: 5

In [76]: a = np.arange(0, 2, 0.5, dtype=np.float16)

In [78]: a.nbytes
Out[78]: 8
Kasravnd
fonte
3

Você está perguntando como lidar com uma matriz de elemento de 2.500.000.000 sem terabytes de RAM?

A maneira de lidar com 2 bilhões de itens sem 8 bilhões de bytes de RAM é não manter a matriz na memória.

Isso significa algoritmos muito mais sofisticados para buscá-lo em partes do sistema de arquivos.

S.Lott
fonte
7
Não é verdade. Se 99,99% (para um exemplo realista) dos elementos são zero, todos os dados da matriz podem ser mantidos na memória. Não há necessidade de usar até 4 bytes para cada zero, quando você pode simplesmente armazenar uma lista das (row, column, value)entradas existentes.
Eric Wilson
6
@EricWilson: Onde na pergunta isso sugeria que a matriz era esparsa? Eu perdi totalmente isso. Você pode fornecer a cotação?
S.Lott,
1

Normalmente, quando lidamos com matrizes grandes, as implementamos como matrizes esparsas .

Não sei se numpy suporta matrizes esparsas, mas descobri isso .

Nick Dandoulakis
fonte
1

Pelo que sei sobre entorpecimento, não, mas posso estar errado.

Posso propor a você esta solução alternativa: escrever a matriz no disco e acessá-la em blocos. Eu sugiro o formato de arquivo HDF5. Se precisar de forma transparente, você pode reimplementar a interface ndarray para paginar sua matriz armazenada em disco na memória. Tenha cuidado ao modificar os dados para sincronizá-los de volta no disco.

Stefano Borini
fonte
E se eu quiser acessar uma matriz completa de 57600 por 57600?
Gunjan naik