Come salvare e caricare correttamente i dati numpy.array ()?


104

Mi chiedo come salvare e caricare i numpy.arraydati correttamente. Attualmente sto usando il numpy.savetxt()metodo. Ad esempio, se ho un array markers, che assomiglia a questo:

inserisci qui la descrizione dell'immagine

Provo a salvarlo utilizzando:

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

In un altro script provo ad aprire il file salvato in precedenza:

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

Ed è quello che ottengo ...

inserisci qui la descrizione dell'immagine

I dati salvati inizialmente hanno questo aspetto:

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

Ma quando salvo i dati appena caricati utilizzando lo stesso metodo, ad es. numpy.savetxt()assomiglia a questo:

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

Che cosa sto facendo di sbagliato? PS non ci sono altre operazioni di "backstage" che eseguo. Sto solo salvando e caricando, ed è quello che ottengo. Grazie in anticipo.


Qual è l'output del file di testo? Perché non scrivere semplicemente su un file CSV?

4
Hai bisogno di salvare e caricare come file di testo leggibili dall'uomo? Sarà più veloce (ei file saranno più compatti) se salvi / carichi file binari usando np.save()e np.load().
ali_m

Grazie per il vostro consiglio. Ha aiutato. Tuttavia, puoi spiegare perché è quello che è e se esiste un modo per consentire il salvataggio dei dati in formato * .txt e il caricamento senza problemi? Ad esempio, quando si desidera lavorare con matlab, java o altri strumenti / linguaggi.
bluevoxel

3
Per passare array a / da MATLAB puoi usare scipy.io.savemate scipy.io.loadmat.
ali_m

2
L'impostazione predefinita per fromfileè leggere i dati come binari. loadtxtè l'abbinamento corretto con savetxt. Guarda la documentazione della funzione.
hpaulj

Risposte:


146

Il modo più affidabile che ho trovato per farlo è usare np.savetxtcon np.loadtxte non np.fromfileche è più adatto ai file binari scritti con tofile. I metodi np.fromfilee np.tofilescrivono e leggono file binari mentre np.savetxtscrive un file di testo. Quindi, ad esempio:

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)

O:

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)

Uso il primo metodo anche se è più lento e crea file più grandi (a volte): il formato binario può dipendere dalla piattaforma (ad esempio, il formato del file dipende dall'endianità del tuo sistema).

Esiste un formato indipendente dalla piattaforma per gli array NumPy, che può essere salvato e letto con 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)

47
.npyi file (ad esempio generati da np.save()) sono indipendenti dalla piattaforma e saranno più compatti e più veloci da creare rispetto ai file di testo.
ali_m

2
anche np.savezse vuoi che l'output sia compresso.
tegan

3
@tegan np.savezsalva diversi array non compressi - np.savez_compressedli comprimerà - non c'è np.save_compressedancora. Vedi docs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
Brian Burns

1
Grazie xnx ho riscontrato lo stesso problema (con dtype float) utilizzando np.savetxt con np.loadtxt risolto
Yogesh

Ho avuto problemi con il salvataggio di pickle di dati superiori a 2 GB. Grazie a xnx il problema è stato risolto utilizzando a.tofile e np.fromfile.
Azr

47
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load

c'è un problema con l'utilizzo pickle?
Charlie Parker

ad esempio, in modo che possiamo caricare i dati con come x = db["x"]seguito da y = db["y"]?
Charlie Parker

3

np.fromfile()ha un sep=argomento parola chiave:

Separatore tra gli elementi se il file è un file di testo. Il separatore vuoto ("") indica che il file deve essere trattato come binario. Gli spazi ("") nel separatore corrispondono a zero o più caratteri di spaziatura. Un separatore composto solo da spazi deve corrispondere ad almeno uno spazio bianco.

Il valore predefinito di sep=""significa che np.fromfile()cerca di leggerlo come un file binario anziché come un file di testo separato da spazi, in modo da ottenere valori senza senso. Se lo usi np.fromfile('markers.txt', sep=" ")otterrai il risultato che stai cercando.

Tuttavia, come altri hanno sottolineato, np.loadtxt()è il modo preferito per convertire i file di testo in array numpy, ea meno che il file non debba essere leggibile dall'uomo, di solito è meglio usare invece formati binari (ad esempio np.load()/ np.save()).


c'è un problema con l'utilizzo pickle?
Charlie Parker

0

Per una risposta breve dovresti usare np.savee np.load. Il vantaggio di questi è che sono realizzati dagli sviluppatori della libreria numpy e funzionano già (inoltre sono probabilmente già ottimizzati bene) ad es.

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

Risposta estesa:

Alla fine dipende davvero dalle tue esigenze perché puoi anche salvarlo in formato leggibile dall'uomo (vedi questo Scaricare un array NumPy in un file csv ) o anche con altre librerie se i tuoi file sono estremamente grandi (vedi questo modo migliore per preservare gli array numpy su disco per una discussione estesa).

Tuttavia, (facendo un'espansione poiché usi la parola "correttamente" nella tua domanda) penso ancora che l'uso della funzione numpy fuori dagli schemi (e la maggior parte del codice!) Molto probabilmente soddisfi la maggior parte delle esigenze degli utenti. Il motivo più importante è che funziona già . Cercare di usare qualcos'altro per qualsiasi altro motivo potrebbe portarti in una tana di coniglio inaspettatamente LUNGA per capire perché non funziona e costringerlo a funzionare.

Prendiamo ad esempio il tentativo di salvarlo con pickle. L'ho provato solo per divertimento e mi ci sono voluti almeno 30 minuti per rendermi conto che pickle non avrebbe salvato le mie cose a meno che non avessi aperto e letto il file in modalità byte con wb. Mi ci è voluto del tempo per google, provare, capire il messaggio di errore ecc ... Piccolo dettaglio ma il fatto che già mi richiedesse di aprire un file ha complicato le cose in modi inaspettati. Per aggiungere che mi ha richiesto di rileggere questo (che btw è un po 'confuso) Differenza tra le modalità a, a +, w, w + e r + nella funzione di apertura incorporata? .

Quindi, se esiste un'interfaccia che soddisfa le tue esigenze, usala a meno che tu non abbia una ( molto ) buona ragione (es. Compatibilità con matlab o per qualche motivo vuoi davvero leggere il file e stampare in python non soddisfa le tue esigenze, il che potrebbe essere discutibile). Inoltre, molto probabilmente se hai bisogno di ottimizzarlo lo scoprirai in seguito (piuttosto che passare anni a eseguire il debug di cose inutili come l'apertura di un semplice file numpy).

Quindi usa l'interfaccia / numpy fornisce . Potrebbe non essere perfetto, molto probabilmente va bene, specialmente per una libreria che esiste da quando è numpy.

Ho già speso il salvataggio e il caricamento dei dati con numpy in un sacco di modi quindi divertiti con esso, spero che aiuti!

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

Alcuni commenti su ciò che ho imparato:

  • np.savecome previsto, questo già lo comprime bene (vedere https://stackoverflow.com/a/55750128/1601580 ), funziona immediatamente senza alcuna apertura di file. Pulito. Facile. Efficiente. Usalo.
  • np.savezusa un formato non compresso (vedi documenti ) Save several arrays into a single file in uncompressed .npz format.Se decidi di usarlo (sei stato avvertito di abbandonare la soluzione standard quindi aspettati bug!) potresti scoprire che devi usare nomi di argomenti per salvarlo, a meno che tu non lo voglia utilizzare i nomi predefiniti. Quindi non usarlo se il primo funziona già (o qualsiasi lavoro lo usa!)
  • Pickle consente anche l'esecuzione di codice arbitrario. Alcune persone potrebbero non volerlo utilizzare per motivi di sicurezza.
  • i file leggibili dall'uomo sono costosi da creare, ecc. Probabilmente non ne vale la pena.
  • c'è qualcosa chiamato hdf5per file di grandi dimensioni. Freddo! https://stackoverflow.com/a/9619713/1601580

Nota che questa non è una risposta esaustiva. Ma per altre risorse controlla questo:

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.