Comment enregistrer et charger correctement les données numpy.array ()?

104

Je me demande comment enregistrer et charger numpy.arraycorrectement les données. Actuellement, j'utilise la numpy.savetxt()méthode. Par exemple, si j'ai un tableau markers, qui ressemble à ceci:

entrez la description de l'image ici

J'essaye de le sauvegarder en utilisant:

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

Dans un autre script, j'essaye d'ouvrir le fichier précédemment enregistré:

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

Et c'est ce que je reçois ...

entrez la description de l'image ici

Les données enregistrées ressemblent d'abord à ceci:

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

Mais quand je sauvegarde juste les données chargées en utilisant la même méthode, ce est à dire. numpy.savetxt()ça ressemble à ceci:

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

Qu'est-ce que je fais mal? PS il n'y a pas d'autre opération "backstage" que j'effectue. Juste enregistrer et charger, et c'est ce que j'obtiens. Merci d'avance.

bluevoxel
la source
Quelle est la sortie du fichier texte? Pourquoi ne pas simplement écrire dans un fichier CSV?
4
Avez-vous besoin d'enregistrer et de charger en tant que fichiers texte lisibles par l'homme? Ce sera plus rapide (et les fichiers seront plus compacts) si vous enregistrez / chargez des fichiers binaires en utilisant np.save()et np.load().
ali_m
Merci pour votre conseil. Ça m'a aidé. Cependant, pouvez-vous expliquer pourquoi c'est ce que c'est, et s'il existe un moyen d'autoriser l'enregistrement des données au format * .txt et de les charger sans maux de tête? Par exemple, quand on veut travailler avec matlab, java ou d'autres outils / langages.
bluevoxel
3
Pour transmettre des tableaux vers / depuis MATLAB, vous pouvez utiliser scipy.io.savematet scipy.io.loadmat.
ali_m
2
La valeur par défaut pour fromfileest de lire les données sous forme binaire. loadtxtest le bon appariement avec savetxt. Regardez la documentation de la fonction.
hpaulj

Réponses:

146

Le moyen le plus fiable que j'ai trouvé pour le faire est d'utiliser np.savetxtavec np.loadtxtet non np.fromfilece qui convient le mieux aux fichiers binaires écrits avec tofile. Les méthodes np.fromfileand np.tofileécrivent et lisent des fichiers binaires tandis que rédigent np.savetxtun fichier texte. Ainsi, par exemple:

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)

J'utilise l'ancienne méthode même si elle est plus lente et crée des fichiers plus volumineux (parfois): le format binaire peut dépendre de la plate-forme (par exemple, le format de fichier dépend de l'endianness de votre système).

Il existe un format indépendant de la plate- forme pour les tableaux NumPy, qui peut être enregistré et lu avec np.saveet 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
la source
47
.npyles fichiers (générés par exemple par np.save()) sont indépendants de la plate-forme et seront plus compacts et plus rapides à créer que les fichiers texte.
ali_m
2
également np.savezsi vous voulez que la sortie soit compressée.
tegan
3
@tegan np.savezenregistre plusieurs tableaux non compressés - np.savez_compressedles compressera - il n'y en a pas np.save_compressedencore. Voir docs.scipy.org/doc/numpy-1.15.1/reference/routines.io.html
Brian Burns
1
Merci xnx J'avais le même problème (avec dtype float) en utilisant np.savetxt avec np.loadtxt résolu
Yogesh
J'ai eu un problème avec les données de sauvegarde de cornichons supérieures à 2 Go. Grâce à xnx, le problème a été résolu en utilisant a.tofile et np.fromfile.
Azr
47
np.save('data.npy', num_arr) # save
new_num_arr = np.load('data.npy') # load
Sherzod
la source
y a-t-il un problème avec l'utilisation pickle?
Charlie Parker le
par exemple, afin que nous puissions charger les données avec comme x = db["x"]suivi de y = db["y"]?
Charlie Parker le
3

np.fromfile()a un sep=argument de mot - clé:

Séparateur entre les éléments si le fichier est un fichier texte. Un séparateur vide («») signifie que le fichier doit être traité comme binaire. Les espaces (””) dans le séparateur correspondent à zéro ou plusieurs espaces blancs. Un séparateur composé uniquement d'espaces doit correspondre à au moins un espace blanc.

La valeur par défaut de sep=""signifie que np.fromfile()tente de le lire comme un fichier binaire plutôt que comme un fichier texte séparé par des espaces, de sorte que vous récupérez des valeurs absurdes. Si tu utilisesnp.fromfile('markers.txt', sep=" ") vous obtiendrez le résultat que vous recherchez.

Cependant, comme d'autres l'ont souligné, np.loadtxt()c'est le moyen préféré de convertir des fichiers texte en tableaux numpy, et à moins que le fichier ne doive être lisible par l'homme, il est généralement préférable d'utiliser des formats binaires à la place (par exemple np.load()/ np.save()).

ali_m
la source
y a-t-il un problème avec l'utilisation pickle?
Charlie Parker le
0

Pour une réponse courte, vous devez utiliser np.saveet np.load. Les avantages de ceux-ci sont qu'ils sont fabriqués par les développeurs de la bibliothèque numpy et qu'ils fonctionnent déjà (et sont probablement déjà bien optimisés), par exemple

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

Réponse étendue:

En fin de compte, cela dépend vraiment de vos besoins car vous pouvez également l'enregistrer au format lisible par l'homme (voir ce vidage d'un tableau NumPy dans un fichier csv ) ou même avec d'autres bibliothèques si vos fichiers sont extrêmement volumineux (voir cette meilleure façon de préserver les tableaux numpy sur disque pour une discussion approfondie).

Cependant, (en faisant une extension puisque vous utilisez le mot «correctement» dans votre question) je pense toujours que l'utilisation de la fonction numpy prête à l'emploi (et la plupart du code!) Satisfera probablement la plupart des besoins des utilisateurs. La raison la plus importante est que cela fonctionne déjà . Essayer d'utiliser autre chose pour toute autre raison pourrait vous amener dans un terrier de lapin inattendu LONG pour comprendre pourquoi cela ne fonctionne pas et le forcer à fonctionner.

Prenons l'exemple d'essayer de l'enregistrer avec du cornichon. J'ai essayé cela juste pour le plaisir et il m'a fallu au moins 30 minutes pour réaliser que pickle ne sauverait pas mes affaires à moins que j'ouvre et lisais le fichier en mode octets avec wb. Il a fallu du temps pour google, essayer quelque chose, comprendre le message d'erreur etc ... Petit détail mais le fait que cela m'obligeait déjà à ouvrir un fichier compliquait les choses de manière inattendue. Pour ajouter qu'il m'a fallu relire ceci (quel btw est un peu déroutant) Différence entre les modes a, a +, w, w + et r + dans la fonction ouverte intégrée?.

Donc, s'il y a une interface qui répond à vos besoins, utilisez-la sauf si vous avez un ( très ) bonne raison (par exemple, compatibilité avec matlab ou pour une raison quelconque, vous voulez vraiment lire le fichier et l'impression en python ne répond vraiment pas à vos besoins, ce qui pourrait être discutable). De plus, si vous avez besoin de l'optimiser, vous le saurez probablement plus tard (plutôt que de passer des années à déboguer des choses inutiles comme ouvrir un simple fichier numpy).

Utilisez donc l'interface / numpy fournit . Ce n'est peut-être pas parfait, c'est très probablement bien, en particulier pour une bibliothèque qui existe depuis aussi longtemps que numpy.

J'ai déjà passé la sauvegarde et le chargement de données avec numpy de plusieurs façons, alors amusez-vous avec, j'espère que cela vous aidera!

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

Quelques commentaires sur ce que j'ai appris:

  • np.savecomme prévu, cela le compresse déjà bien (voir https://stackoverflow.com/a/55750128/1601580 ), fonctionne hors de la boîte sans aucune ouverture de fichier. Nettoyer. Facile. Efficace. Utilise le.
  • np.savezutilise un format non compressé (voir la documentation ) Save several arrays into a single file in uncompressed .npz format.Si vous décidez de l'utiliser (vous avez été averti de vous éloigner de la solution standard, attendez-vous à des bogues!), vous pourriez découvrir que vous devez utiliser des noms d'argument pour l'enregistrer, à moins que vous ne vouliez utilisez les noms par défaut. Donc, ne l'utilisez pas si le premier fonctionne déjà (ou si toute œuvre l'utilise!)
  • Pickle permet également l'exécution de code arbitraire. Certaines personnes peuvent ne pas vouloir l'utiliser pour des raisons de sécurité.
  • les fichiers lisibles par l'homme coûtent cher à créer, etc. Cela n'en vaut probablement pas la peine.
  • il y a quelque chose qui s'appelle hdf5pour les gros fichiers. Cool! https://stackoverflow.com/a/9619713/1601580

Notez que ce n'est pas une réponse exhaustive. Mais pour d'autres ressources, vérifiez ceci:

Charlie Parker
la source