Como salvar e carregar dados numpy.array () corretamente?

103

Eu me pergunto, como salvar e carregar numpy.arraydados corretamente. Atualmente estou usando o numpy.savetxt()método. Por exemplo, se eu obtiver uma matriz markers, que se parece com isto:

insira a descrição da imagem aqui

Tento salvá-lo usando:

numpy.savetxt('markers.txt', markers)

Em outro script, tento abrir o arquivo salvo anteriormente:

markers = np.fromfile("markers.txt")

E é isso que eu ganho ...

insira a descrição da imagem aqui

Os dados salvos têm a seguinte aparência:

0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00
0.000000000000000000e+00

Mas quando eu salvo apenas os dados carregados pelo uso do mesmo método, ou seja. numpy.savetxt()Se parece com isso:

1.398043286095131769e-76
1.398043286095288860e-76
1.396426376485745879e-76
1.398043286055061908e-76
1.398043286095288860e-76
1.182950697433698368e-76
1.398043275797188953e-76
1.398043286095288860e-76
1.210894289234927752e-99
1.398040649781712473e-76

O que estou fazendo de errado? PS, não há nenhuma outra operação "backstage" que eu execute. Basta salvar e carregar, e é isso que recebo. Agradeço antecipadamente.

bluevoxel
fonte
Qual é a saída do arquivo de texto? Por que não apenas gravar em um arquivo CSV?
4
Você precisa salvar e carregar como arquivos de texto legíveis por humanos? Será mais rápido (e os arquivos serão mais compactos) se você salvar / carregar arquivos binários usando np.save()e np.load().
ali_m
Obrigado pelo seu conselho. Ajudou. Porém, você pode explicar porque é o que é, e se existe alguma maneira de permitir salvar dados no formato * .txt e carregá-los sem dor de cabeça? Por exemplo, quando se deseja trabalhar com matlab, java ou outras ferramentas / linguagens.
bluevoxel de
3
Para passar arrays de / para o MATLAB, você pode usar scipy.io.savemate scipy.io.loadmat.
ali_m
2
O padrão para fromfileé ler os dados como binários. loadtxté o emparelhamento correto com savetxt. Veja a documentação da função.
hpaulj de

Respostas:

144

A maneira mais confiável que descobri de fazer isso é usar np.savetxtcom np.loadtxte não a np.fromfileque é mais adequada para arquivos binários gravados com tofile. Os métodos np.fromfilee np.tofileescrevem e leem arquivos binários enquanto np.savetxtgrava um arquivo de texto. Então, por exemplo:

In [1]: a = np.array([1, 2, 3, 4])
In [2]: np.savetxt('test1.txt', a, fmt='%d')
In [3]: b = np.loadtxt('test1.txt', dtype=int)
In [4]: a == b
Out[4]: array([ True,  True,  True,  True], dtype=bool)

Ou:

In [5]: a.tofile('test2.dat')
In [6]: c = np.fromfile('test2.dat', dtype=int)
In [7]: c == a
Out[7]: array([ True,  True,  True,  True], dtype=bool)

Eu uso o método anterior, mesmo que seja mais lento e crie arquivos maiores (às vezes): o formato binário pode ser dependente da plataforma (por exemplo, o formato do arquivo depende do endianness do seu sistema).

Existe um formato independente de plataforma para matrizes NumPy, que podem ser salvas e lidas com np.savee np.load:

In  [8]: np.save('test3.npy', a)    # .npy extension is added if not given
In  [9]: d = np.load('test3.npy')
In [10]: a == d
Out[10]: array([ True,  True,  True,  True], dtype=bool)
xnx
fonte
46
.npyarquivos (por exemplo, gerados por np.save()) são independentes da plataforma e serão mais compactos e rápidos de criar do que arquivos de texto.
ali_m
2
também np.savezse você quiser a saída compactada.
começou
3
@tegan np.savezsalva vários arrays descompactados - np.savez_compressedirá compactá-los - não há nenhum np.save_compressedainda. Consulte docs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
Brian Burns,
1
Obrigado xnx. Eu estava tendo o mesmo problema (com dtype float) usando np.savetxt com np.loadtxt resolvido
Yogesh
Eu tive problemas com dados salvando pickle maior que 2 GB. Graças a xnx o problema foi resolvido usando a.tofile e np.fromfile.
Azhar hussain
47
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load
Sherzod
fonte
há um problema com o uso pickle?
Charlie Parker
por exemplo, para que possamos carregar os dados com as x = db["x"]seguido por y = db["y"]?
Charlie Parker
3

np.fromfile()tem um sep=argumento de palavra - chave:

Separador entre itens se o arquivo for um arquivo de texto. Separador vazio (“”) significa que o arquivo deve ser tratado como binário. Os espaços (””) no separador correspondem a zero ou mais caracteres de espaço em branco. Um separador que consiste apenas em espaços deve corresponder a pelo menos um espaço em branco.

O valor padrão de sep=""significa que np.fromfile()tenta lê-lo como um arquivo binário em vez de um arquivo de texto separado por espaços, portanto, você obtém valores sem sentido de volta. Se utilizar np.fromfile('markers.txt', sep=" "), obterá o resultado que procura.

No entanto, como outros apontaram, np.loadtxt()é a maneira preferida de converter arquivos de texto em matrizes numpy e, a menos que o arquivo precise ser legível por humanos, geralmente é melhor usar formatos binários (por exemplo, np.load()/ np.save()).

ali_m
fonte
há um problema com o uso pickle?
Charlie Parker
0

Para uma resposta curta, você deve usar np.savee np.load. As vantagens disso é que são feitos por desenvolvedores da biblioteca numpy e já funcionam (e provavelmente já estão bem otimizados).

import numpy as np
from pathlib import Path

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2

np.save(path/'x', x)
np.save(path/'y', y)

x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')

print(x is x_loaded) # False
print(x == x_loaded) # [[ True  True  True  True  True]]

Resposta expandida:

No final, isso realmente depende de suas necessidades porque você também pode salvá-lo em um formato legível por humanos (veja este Despejar um array NumPy em um arquivo csv ) ou até mesmo com outras bibliotecas se seus arquivos forem extremamente grandes (veja esta melhor maneira de preservar arrays numpy no disco para uma discussão expandida).

No entanto, (fazendo uma expansão, já que você usa a palavra "corretamente" em sua pergunta), ainda acho que usar a função numpy pronta para uso (e a maioria dos códigos!) Provavelmente satisfará a maioria das necessidades do usuário. O motivo mais importante é que já funciona . Tentar usar outra coisa por qualquer outro motivo pode levá-lo a uma inesperada LONGA toca do coelho para descobrir por que não funciona e forçar o funcionamento.

Tomemos, por exemplo, tentar salvá-lo com picles. Eu tentei isso apenas por diversão e levei pelo menos 30 minutos para perceber que pickle não salvaria minhas coisas a menos que eu abrisse e lesse o arquivo no modo bytes com wb. Demorei para pesquisar no Google, tentar algo, entender a mensagem de erro etc ... Pequenos detalhes, mas o fato de já ter exigido que eu abrisse um arquivo complicou as coisas de maneiras inesperadas. Para adicionar isso, foi necessário reler isso (o que, aliás, é meio confuso). Diferença entre os modos a, a +, w, w + e r + na função aberta embutida? .

Portanto, se houver uma interface que atenda às suas necessidades, use-a a menos que tenha um ( muito ) bom motivo (por exemplo, compatibilidade com matlab ou por algum motivo, você realmente deseja ler o arquivo e imprimir em python realmente não atende às suas necessidades, o que pode ser questionável). Além disso, provavelmente, se você precisar otimizá-lo, você descobrirá mais tarde (em vez de passar séculos depurando coisas inúteis, como abrir um arquivo simples).

Portanto, use a interface / numpy fornecer . Pode não ser perfeito, é provavelmente bom, especialmente para uma biblioteca que existe há tanto tempo quanto entorpecida.

Eu já gastei várias maneiras de salvar e carregar dados com o numpy, então divirta-se com isso, espero que ajude!

import numpy as np
import pickle
from pathlib import Path

path = Path('~/data/tmp/').expanduser()
path.mkdir(parents=True, exist_ok=True)

lb,ub = -1,1
num_samples = 5
x = np.random.uniform(low=lb,high=ub,size=(1,num_samples))
y = x**2 + x + 2

# using save (to npy), savez (to npz)
np.save(path/'x', x)
np.save(path/'y', y)
np.savez(path/'db', x=x, y=y)
with open(path/'db.pkl', 'wb') as db_file:
    pickle.dump(obj={'x':x, 'y':y}, file=db_file)

## using loading npy, npz files
x_loaded = np.load(path/'x.npy')
y_load = np.load(path/'y.npy')
db = np.load(path/'db.npz')
with open(path/'db.pkl', 'rb') as db_file:
    db_pkl = pickle.load(db_file)

print(x is x_loaded)
print(x == x_loaded)
print(x == db['x'])
print(x == db_pkl['x'])
print('done')

Alguns comentários sobre o que aprendi:

  • np.savecomo esperado, isso já o compacta bem (consulte https://stackoverflow.com/a/55750128/1601580 ), funciona imediatamente, sem qualquer abertura de arquivo. Limpar \ limpo. Fácil. Eficiente. Use-o.
  • np.savezusa um formato descompactado (veja os documentos ) Save several arrays into a single file in uncompressed .npz format.Se você decidir usar isso (você foi avisado para abandonar a solução padrão, então espere erros!), você pode descobrir que precisa usar nomes de argumento para salvá-lo, a menos que queira use os nomes padrão. Portanto, não use isso se o primeiro já funcionar (ou se alguma obra usar isso!)
  • O Pickle também permite a execução arbitrária de códigos. Algumas pessoas podem não querer usar isso por motivos de segurança.
  • arquivos legíveis por humanos são caros para fazer, etc. Provavelmente não vale a pena.
  • há algo chamado hdf5para arquivos grandes. Legal! https://stackoverflow.com/a/9619713/1601580

Observe que esta não é uma resposta exaustiva. Mas para outros recursos verifique isto:

Charlie Parker
fonte