Comment écrire un tableau multidimensionnel dans un fichier texte?

116

Dans une autre question, d'autres utilisateurs ont offert de l'aide si je pouvais fournir le tableau avec lequel j'avais des problèmes. Cependant, j'échoue même à une tâche d'E / S de base, telle que l'écriture d'un tableau dans un fichier.

Quelqu'un peut-il expliquer le type de boucle dont j'aurais besoin pour écrire un tableau numpy 4x11x14 dans un fichier?

Ce tableau se compose de quatre tableaux 11 x 14, donc je devrais le formater avec une belle nouvelle ligne, pour rendre la lecture du fichier plus facile pour les autres.

Edit : J'ai donc essayé la fonction numpy.savetxt. Étrangement, cela donne l'erreur suivante:

TypeError: float argument required, not numpy.ndarray

Je suppose que c'est parce que la fonction ne fonctionne pas avec des tableaux multidimensionnels? Des solutions comme je les aimerais dans un seul fichier?

Ivo Flipse
la source

Réponses:

198

Si vous voulez l'écrire sur le disque afin qu'il soit facile à lire en tant que tableau numpy, regardez dans numpy.save. Le décapage fonctionnera bien aussi, mais il est moins efficace pour les grands tableaux (ce qui n'est pas le vôtre, donc c'est parfaitement bien).

Si vous voulez qu'il soit lisible par l'homme, examinez-le numpy.savetxt.

Edit: Donc, il semble que ce savetxtn'est pas une aussi bonne option pour les tableaux avec> 2 dimensions ... Mais juste pour tout tirer à sa conclusion complète:

Je viens de réaliser que numpy.savetxt les ndarrays s'étouffent avec plus de 2 dimensions ... C'est probablement par conception, car il n'y a pas de manière intrinsèquement définie d'indiquer des dimensions supplémentaires dans un fichier texte.

Par exemple, ceci (un tableau 2D) fonctionne très bien

import numpy as np
x = np.arange(20).reshape((4,5))
np.savetxt('test.txt', x)

Alors que la même chose échouerait (avec une erreur plutôt non informative :) TypeError: float argument required, not numpy.ndarraypour un tableau 3D:

import numpy as np
x = np.arange(200).reshape((4,5,10))
np.savetxt('test.txt', x)

Une solution de contournement consiste simplement à diviser le tableau 3D (ou supérieur) en tranches 2D. Par exemple

x = np.arange(200).reshape((4,5,10))
with file('test.txt', 'w') as outfile:
    for slice_2d in x:
        np.savetxt(outfile, slice_2d)

Cependant, notre objectif est d'être clairement lisible par l'homme, tout en étant facilement lisible avec numpy.loadtxt. Par conséquent, nous pouvons être un peu plus verbeux et différencier les tranches en utilisant des lignes commentées. Par défaut, numpy.loadtxtignorera toutes les lignes commençant par #(ou le caractère spécifié par le commentskwarg). (Cela semble plus verbeux qu'il ne l'est en réalité ...)

import numpy as np

# Generate some test data
data = np.arange(200).reshape((4,5,10))

# Write the array to disk
with open('test.txt', 'w') as outfile:
    # I'm writing a header here just for the sake of readability
    # Any line starting with "#" will be ignored by numpy.loadtxt
    outfile.write('# Array shape: {0}\n'.format(data.shape))

    # Iterating through a ndimensional array produces slices along
    # the last axis. This is equivalent to data[i,:,:] in this case
    for data_slice in data:

        # The formatting string indicates that I'm writing out
        # the values in left-justified columns 7 characters in width
        # with 2 decimal places.  
        np.savetxt(outfile, data_slice, fmt='%-7.2f')

        # Writing out a break to indicate different slices...
        outfile.write('# New slice\n')

Cela donne:

# Array shape: (4, 5, 10)
0.00    1.00    2.00    3.00    4.00    5.00    6.00    7.00    8.00    9.00   
10.00   11.00   12.00   13.00   14.00   15.00   16.00   17.00   18.00   19.00  
20.00   21.00   22.00   23.00   24.00   25.00   26.00   27.00   28.00   29.00  
30.00   31.00   32.00   33.00   34.00   35.00   36.00   37.00   38.00   39.00  
40.00   41.00   42.00   43.00   44.00   45.00   46.00   47.00   48.00   49.00  
# New slice
50.00   51.00   52.00   53.00   54.00   55.00   56.00   57.00   58.00   59.00  
60.00   61.00   62.00   63.00   64.00   65.00   66.00   67.00   68.00   69.00  
70.00   71.00   72.00   73.00   74.00   75.00   76.00   77.00   78.00   79.00  
80.00   81.00   82.00   83.00   84.00   85.00   86.00   87.00   88.00   89.00  
90.00   91.00   92.00   93.00   94.00   95.00   96.00   97.00   98.00   99.00  
# New slice
100.00  101.00  102.00  103.00  104.00  105.00  106.00  107.00  108.00  109.00 
110.00  111.00  112.00  113.00  114.00  115.00  116.00  117.00  118.00  119.00 
120.00  121.00  122.00  123.00  124.00  125.00  126.00  127.00  128.00  129.00 
130.00  131.00  132.00  133.00  134.00  135.00  136.00  137.00  138.00  139.00 
140.00  141.00  142.00  143.00  144.00  145.00  146.00  147.00  148.00  149.00 
# New slice
150.00  151.00  152.00  153.00  154.00  155.00  156.00  157.00  158.00  159.00 
160.00  161.00  162.00  163.00  164.00  165.00  166.00  167.00  168.00  169.00 
170.00  171.00  172.00  173.00  174.00  175.00  176.00  177.00  178.00  179.00 
180.00  181.00  182.00  183.00  184.00  185.00  186.00  187.00  188.00  189.00 
190.00  191.00  192.00  193.00  194.00  195.00  196.00  197.00  198.00  199.00 
# New slice

Le relire est très facile, tant que nous connaissons la forme du tableau d'origine. On peut juste faire numpy.loadtxt('test.txt').reshape((4,5,10)). À titre d'exemple (vous pouvez le faire en une seule ligne, je suis juste verbeux pour clarifier les choses):

# Read the array from disk
new_data = np.loadtxt('test.txt')

# Note that this returned a 2D array!
print new_data.shape

# However, going back to 3D is easy if we know the 
# original shape of the array
new_data = new_data.reshape((4,5,10))

# Just to check that they're the same...
assert np.all(new_data == data)
Joe Kington
la source
2
+1 de moi, voir aussi numpy.loadtxt( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )
Dominic Rodger
2
Il existe maintenant une solution beaucoup plus simple à ce problème ici: yourStrArray = np.array ([str (val) for val in yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Greg Kramida
@GregKramida et comment récupérer le tableau?
astrojuanlu
@ Juanlu001: Je sais que numpy.loadtxt (...) accepte également un argument dtype, qui peut être défini sur np.string_. Je donnerais une chance à cela, d'abord et avant tout. Il existe également un numpy.fromstring (...) pour analyser les tableaux à partir de chaînes.
Greg Kramida
Hé, que faire si j'ai besoin de stocker un tableau d'images? Comment redimensionnerions-nous cela si la taille de l'image est, disons, 512 x 512?
Ambika Saxena
31

Je ne suis pas certain que cela réponde à vos exigences, étant donné que je pense que vous êtes intéressé à rendre le fichier lisible par les gens, mais si ce n'est pas une préoccupation principale, juste picklecela.

Pour le sauvegarder:

import pickle

my_data = {'a': [1, 2.0, 3, 4+6j],
           'b': ('string', u'Unicode string'),
           'c': None}
output = open('data.pkl', 'wb')
pickle.dump(my_data, output)
output.close()

Pour le relire:

import pprint, pickle

pkl_file = open('data.pkl', 'rb')

data1 = pickle.load(pkl_file)
pprint.pprint(data1)

pkl_file.close()
Dominic Rodger
la source
Vous n'aurez peut-être pas besoin pprintd'imprimer le dictionnaire.
zyy
11

Si vous n'avez pas besoin d'une sortie lisible par l'homme, une autre option que vous pouvez essayer est d'enregistrer le tableau en tant que .matfichier MATLAB , qui est un tableau structuré. Je méprise MATLAB, mais le fait de pouvoir à la fois lire et écrire un .maten très peu de lignes est pratique.

Contrairement à la réponse de Joe Kington, l'avantage de ceci est que vous n'avez pas besoin de connaître la forme originale des données dans le .matfichier, c'est-à-dire pas besoin de remodeler lors de la lecture. Et, contrairement à l'utilisation pickle, un .matfichier peut être lu par MATLAB, et probablement aussi d'autres programmes / langages.

Voici un exemple:

import numpy as np
import scipy.io

# Some test data
x = np.arange(200).reshape((4,5,10))

# Specify the filename of the .mat file
matfile = 'test_mat.mat'

# Write the array to the mat file. For this to work, the array must be the value
# corresponding to a key name of your choice in a dictionary
scipy.io.savemat(matfile, mdict={'out': x}, oned_as='row')

# For the above line, I specified the kwarg oned_as since python (2.7 with 
# numpy 1.6.1) throws a FutureWarning.  Here, this isn't really necessary 
# since oned_as is a kwarg for dealing with 1-D arrays.

# Now load in the data from the .mat that was just saved
matdata = scipy.io.loadmat(matfile)

# And just to check if the data is the same:
assert np.all(x == matdata['out'])

Si vous oubliez la clé que le tableau est nommé dans le .matfichier, vous pouvez toujours faire:

print matdata.keys()

Et bien sûr, vous pouvez stocker de nombreux tableaux en utilisant beaucoup plus de clés.

Alors oui - ce ne sera pas lisible avec vos yeux, mais il suffit de 2 lignes pour écrire et lire les données, ce qui, je pense, est un compromis équitable.

Jetez un œil à la documentation pour scipy.io.savemat et scipy.io.loadmat ainsi qu'à cette page de tutoriel: scipy.io File IO Tutorial

aseagramme
la source
9

ndarray.tofile() devrait aussi fonctionner

par exemple si votre tableau est appelé a:

a.tofile('yourfile.txt',sep=" ",format="%s")

Je ne sais pas comment obtenir le formatage de nouvelle ligne.

Edit (crédit du commentaire de Kevin J. Black ici ):

Depuis la version 1.5.0, np.tofile()prend un paramètre facultatif newline='\n'pour autoriser la sortie multiligne. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

atomh33ls
la source
Mais y a-t-il un moyen de créer un tableau original à partir du fichier texte?
Ahashan Alam Sojib
@AhashanAlamSojib voir stackoverflow.com/questions/3518778/…
atomh33ls
1
tofilen'a pas newline='\n'.
Nico Schlömer
1

Vous pouvez simplement parcourir le tableau en trois boucles imbriquées et écrire leurs valeurs dans votre fichier. Pour la lecture, vous utilisez simplement la même construction de boucle exacte. Vous obtiendrez les valeurs exactement dans le bon ordre pour remplir à nouveau correctement vos tableaux.

jwueller
la source
0

J'ai un moyen de le faire en utilisant simplement une opération filename.write (). Cela fonctionne bien pour moi, mais j'ai affaire à des tableaux ayant ~ 1500 éléments de données.

En gros, j'ai juste des boucles for pour parcourir le fichier et l'écrire ligne par ligne dans la destination de sortie dans une sortie de style csv.

import numpy as np

trial = np.genfromtxt("/extension/file.txt", dtype = str, delimiter = ",")

with open("/extension/file.txt", "w") as f:
    for x in xrange(len(trial[:,1])):
        for y in range(num_of_columns):
            if y < num_of_columns-2:
                f.write(trial[x][y] + ",")
            elif y == num_of_columns-1:
                f.write(trial[x][y])
        f.write("\n")

Les instructions if et elif sont utilisées pour ajouter des virgules entre les éléments de données. Pour une raison quelconque, ceux-ci sont supprimés lors de la lecture du fichier en tant que tableau nd. Mon objectif était de sortir le fichier au format csv, donc cette méthode aide à gérer cela.

J'espère que cela t'aides!

BennyD
la source
0

Pickle est le meilleur pour ces cas. Supposons que vous ayez un ndarray nommé x_train. Vous pouvez le vider dans un fichier et le restaurer à l'aide de la commande suivante:

import pickle

###Load into file
with open("myfile.pkl","wb") as f:
    pickle.dump(x_train,f)

###Extract from file
with open("myfile.pkl","rb") as f:
    x_temp = pickle.load(f)
Kenpachi Zaraki
la source