149 votes

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 qui me pose problème. Cependant, j'échoue même à une tâche d'E/S de base, comme l'écriture d'un tableau dans un fichier.

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

Ce tableau est composé de quatre tableaux de 11 x 14, je devrais donc le formater avec une belle nouvelle ligne, afin de faciliter la lecture du fichier pour les autres.

Modifier : J'ai donc essayé la fonction numpy.savetxt. Bizarrement, elle donne l'erreur suivante :

TypeError: float argument required, not numpy.ndarray

Je suppose que c'est parce que la fonction ne fonctionne pas avec les tableaux multidimensionnels ? Y a-t-il une solution car j'aimerais les avoir dans un seul fichier ?

226voto

Joe Kington Points 68089

Si vous voulez l'écrire sur le disque de façon à ce qu'il soit facile de le relire sous forme de tableau numpy, jetez un œil à numpy.save . Le décapage fonctionne bien aussi, mais il est moins efficace pour les grands tableaux (ce qui n'est pas le cas du vôtre, donc l'un ou l'autre convient parfaitement).

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

Editar: Donc, il semble que savetxt n'est pas une aussi bonne option pour les tableaux à >2 dimensions... Mais juste pour aller jusqu'au bout de la démarche :

Je viens de réaliser que numpy.savetxt s'étrangle sur les tableaux de ndarrays avec plus de 2 dimensions... C'est probablement à dessein, car il n'y a pas de moyen intrinsèquement défini 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 peu informative : TypeError: float argument required, not numpy.ndarray ) pour un réseau 3D :

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

Une solution consiste à décomposer le tableau 3D (ou plus) en tranches 2D. Par exemple

x = np.arange(200).reshape((4,5,10))
with open('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 relisible avec les données de l'entreprise. 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.loadtxt ignorera toutes les lignes qui commencent par # (ou tout autre caractère spécifié par l'option comments kwarg). (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

La relecture est très facile, pour autant que l'on connaisse la forme du tableau d'origine. Nous pouvons simplement faire numpy.loadtxt('test.txt').reshape((4,5,10)) . A titre d'exemple (Vous pouvez faire cela 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)

4 votes

+1 de ma part, voir aussi numpy.loadtxt ( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )

2 votes

Il existe maintenant une solution beaucoup plus simple à ce problème : yourStrArray = np.array([str(val) for val in yourMulDArray],dtype='string') ; np.savetxt('YourTextFile.txt',yourStrArray,fmt='%s')

0 votes

@GregKramida et comment récupérez-vous la matrice ?

42voto

Dominic Rodger Points 44489

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 majeure, il suffit de pickle il.

Pour le sauver :

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

1 votes

Vous n'aurez peut-être pas besoin pprint afin d'imprimer le dictionnaire.

14voto

aseagram Points 123

Si vous n'avez pas besoin d'une sortie lisible par l'homme, une autre option consiste à enregistrer le tableau sous forme de fichier MATLAB .mat qui est un tableau structuré. Je méprise MATLAB, mais le fait que je puisse à la fois lire et écrire un fichier de type .mat en très peu de lignes est pratique.

Contrairement à la réponse de Joe Kington, l'avantage de cette solution est que vous pouvez n'ont pas besoin de connaître la forme originale des données dans le .mat c'est-à-dire qu'il n'est pas nécessaire de le remodeler à la lecture. Et, contrairement à l'utilisation de pickle , a .mat peut être lu par MATLAB, et probablement par d'autres programmes/langues également.

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é qui sert à nommer le tableau dans le fichier .mat vous pouvez toujours le 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 à l'œil nu, mais il ne faut que deux lignes pour écrire et lire les données, ce qui me semble être un compromis équitable.

Jetez un coup d'œil aux documents relatifs à scipy.io.savemat et scipy.io.loadmat et aussi cette page de tutoriel : Tutoriel d'E/S de fichiers scipy.io

9voto

atomh33ls Points 2461

ndarray.tofile() devrait également fonctionner

Par exemple, si votre tableau s'appelle a :

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

Je ne sais pas comment obtenir le formatage des nouvelles lignes.

Modifier (crédit : commentaire de Kevin J. Black aquí ):

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

0 votes

Mais existe-t-il un moyen de créer un tableau original à partir du fichier texte ?

0 votes

@AhashanAlamSojib voir stackoverflow.com/questions/3518778/

1 votes

tofile n'a pas newline='\n' .

4voto

Ronny Brendel Points 2588

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

J'espère que cela vous aidera

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X