web-dev-qa-db-fra.com

Comment écrire un tableau multidimensionnel dans un fichier texte?

Dans une autre question, d'autres utilisateurs ont proposé leur 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 quel type de boucle il me faudrait écrire un tableau 4x11x14 numpy dans un fichier?

Ce tableau se compose de quatre tableaux de 11 x 14, je dois donc le formater avec une nouvelle ligne de Nice pour faciliter la lecture du fichier à d’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 voudrais dans un seul fichier?

90
Ivo Flipse

Si vous voulez l'écrire sur le disque pour pouvoir le relire facilement sous forme de tableau numpy, cherchez dans numpy.save . Le décapage fonctionnera bien également, mais il est moins efficace pour les baies de grande taille (ce qui n’est pas le vôtre, donc cela va parfaitement).

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

Edit: Donc, il semblerait que savetxt ne soit pas une aussi bonne option pour les tableaux de plus de 2 dimensions ... Mais juste pour tirer tout le détail de sa conclusion:

Je viens de me rendre compte que numpy.savetxt étouffe les ndarrays ayant plus de 2 dimensions ... C'est probablement de par leur conception, car il n'y a pas de manière intrinsèque d'indiquer des dimensions supplémentaires dans un fichier texte.

Par exemple. Ceci (un tableau 2D) fonctionne 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.ndarray) pour 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 restant facilement lisible avec numpy.loadtxt. Par conséquent, nous pouvons être un peu plus verbeux et différencier les tranches à l'aide de lignes commentées. Par défaut, numpy.loadtxt ignore toutes les lignes commençant par # (ou le caractère spécifié par comments kwarg). (Cela a l'air plus verbeux qu'il ne l'est réellement ...)

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

La relire est très facile, tant que nous connaissons la forme du tableau d'origine. Nous pouvons simplement faire numpy.loadtxt('test.txt').reshape((4,5,10)). Par exemple (vous pouvez le faire en une seule ligne, je suis juste en train de parler 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)
170
Joe Kington

Je ne suis pas certain que cela réponde à vos exigences, étant donné que je pense que vous souhaitez rendre le fichier lisible par des tiers, mais si cela ne vous préoccupe pas vraiment, simplement pickle it.

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()
26
Dominic Rodger

Si vous n'avez pas besoin d'une sortie lisible par l'homme, vous pouvez également essayer d'enregistrer le tableau en tant que fichier MATLAB .mat, qui est un tableau structuré. Je méprise MATLAB, mais le fait de savoir lire et écrire un .mat en 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 fichier .mat, c’est-à-dire qu’il n’est pas nécessaire de modifier la forme après la lecture. pickle, un fichier .mat peut être lu par MATLAB, et probablement aussi par d’autres programmes/langues. 

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é du tableau nommée dans le fichier .mat, vous pouvez toujours faire:

print matdata.keys()

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

Donc, oui, il ne sera pas lisible de vos yeux, mais cela ne prend que deux lignes pour écrire et lire les données, ce qui, à mon avis, est un compromis équitable.

Jetez un coup d’œil aux docs pour scipy.io.savemat Et scipy.io.loadmat Ainsi que pour cette page de tutoriel: scipy.io Fichier IO Tutoriel

10
aseagram

ndarray.tofile() devrait également fonctionner

par exemple. si votre tableau s'appelle a:

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

Vous ne savez pas comment obtenir le formatage d'une nouvelle ligne.

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

Depuis la version 1.5.0, np.tofile() accepte 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

7
atomh33ls

Il existe des bibliothèques spéciales pour faire exactement cela. (Plus des wrappers pour python)

j'espère que cela t'aides

3
Ronny Brendel

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 dans le bon ordre pour remplir à nouveau correctement vos tableaux.

1
jwueller

Pickle est le meilleur pour ces cas. Supposons que vous avez un ndarray nommé x_train. Vous pouvez le sauvegarder 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)
0
Kenpachi Zaraki

J'ai un moyen de le faire en utilisant simplement l'opération filename.write (). Cela fonctionne bien pour moi, mais je traite avec des tableaux contenant ~ 1500 éléments de données. 

En gros, je n'ai que des boucles 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 dans un tableau nd. Mon but était de sortir le fichier en tant que csv, donc cette méthode aide à gérer ça.

J'espère que cela t'aides!

0
BennyD