¿Cómo escribir una matriz multidimensional en un archivo de texto?

115

En otra pregunta, otros usuarios ofrecieron algo de ayuda si podía suministrar la matriz con la que estaba teniendo problemas. Sin embargo, incluso fallo en una tarea básica de E / S, como escribir una matriz en un archivo.

¿Alguien puede explicar qué tipo de bucle necesitaría para escribir una matriz numpy de 4x11x14 en el archivo?

Esta matriz consta de cuatro matrices de 11 x 14, por lo que debería formatearla con una bonita nueva línea, para facilitar la lectura del archivo a otros.

Editar : Así que probé la función numpy.savetxt. Curiosamente, da el siguiente error:

TypeError: float argument required, not numpy.ndarray

Supongo que esto se debe a que la función no funciona con matrices multidimensionales. ¿Alguna solución como me gustaría dentro de un archivo?

Ivo Flipse
fuente

Respuestas:

197

Si desea escribirlo en el disco para que sea fácil volver a leerlo como una matriz numerosa, consulte numpy.save. El decapado también funcionará bien, pero es menos eficiente para arreglos grandes (que el suyo no lo es, por lo que cualquiera de los dos está perfectamente bien).

Si desea que sea legible por humanos, consulte numpy.savetxt.

Editar: Entonces, parece que savetxtno es una opción tan buena para matrices con> 2 dimensiones ... Pero solo para sacar todo a su conclusión completa:

Me acabo de dar cuenta de que se numpy.savetxtahoga en los rayos ndar con más de 2 dimensiones ... Esto probablemente sea por diseño, ya que no hay una forma inherentemente definida de indicar dimensiones adicionales en un archivo de texto.

Por ejemplo, esto (una matriz 2D) funciona bien

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

Si bien lo mismo fallaría (con un error bastante poco informativo :) TypeError: float argument required, not numpy.ndarraypara una matriz 3D:

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

Una solución es simplemente dividir la matriz 3D (o mayor) en cortes 2D. P.ej

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)

Sin embargo, nuestro objetivo es ser claramente legible por humanos, sin dejar de ser fácil de leer numpy.loadtxt. Por lo tanto, podemos ser un poco más detallados y diferenciar los cortes utilizando líneas comentadas. De forma predeterminada, numpy.loadtxtignorará cualquier línea que comience con #(o cualquier carácter que especifique el commentskwarg). (Esto parece más detallado de lo que realmente es ...)

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

Esto produce:

# 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

Leerlo de nuevo es muy fácil, siempre que sepamos la forma de la matriz original. Podemos simplemente hacer numpy.loadtxt('test.txt').reshape((4,5,10)). Como ejemplo (puede hacer esto en una línea, solo estoy siendo detallado para aclarar las cosas):

# 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
fuente
2
+1 de mí, ver también numpy.loadtxt( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )
Dominic Rodger
2
Ahora hay una solución mucho más fácil para este problema: yourStrArray = np.array ([str (val) for val in yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Greg Kramida
@GregKramida y ¿cómo recuperas la matriz?
astrojuanlu
@ Juanlu001: Sé que numpy.loadtxt (...) también acepta un argumento dtype, que se puede establecer en np.string_. Le daría una oportunidad, en primer lugar. También hay un numpy.fromstring (...) para analizar matrices de cadenas.
Greg Kramida
Oye, ¿y si necesito almacenar una matriz de imágenes? ¿Cómo cambiaríamos el tamaño si el tamaño de la imagen es, digamos, 512 x 512?
Ambika Saxena
31

No estoy seguro de si esto cumple con sus requisitos, dado que creo que está interesado en hacer que las personas puedan leer el archivo, pero si eso no es una preocupación principal, simplemente pickleeso.

Para salvarlo:

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

Para volver a leerlo:

import pprint, pickle

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

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

pkl_file.close()
Dominic Rodger
fuente
Es posible que no lo necesite pprintpara imprimir el diccionario.
zyy
11

Si no necesita una salida legible por humanos, otra opción que podría probar es guardar la matriz como un .matarchivo MATLAB , que es una matriz estructurada. Detesto MATLAB, pero el hecho de que pueda leer y escribir.mat en muy pocas líneas es conveniente.

A diferencia de la respuesta de Joe Kington, el beneficio de esto es que no es necesario conocer la forma original de los datos en el .matarchivo, es decir, no es necesario cambiar la forma al leer. Y, a diferencia de usar pickle, un.mat MATLAB puede leer archivo, y probablemente también algunos otros programas / lenguajes.

Aquí hay un ejemplo:

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 olvida la clave con la que se nombra la matriz en el .matarchivo, siempre puede hacer:

print matdata.keys()

Y, por supuesto, puede almacenar muchas matrices utilizando muchas más claves.

Entonces, sí, no será legible con sus ojos, pero solo se necesitan 2 líneas para escribir y leer los datos, lo que creo que es una compensación justa.

Eche un vistazo a los documentos de scipy.io.savemat y scipy.io.loadmat y también a esta página del tutorial: scipy.io File IO Tutorial

aseagrama
fuente
9

ndarray.tofile() también debería funcionar

por ejemplo, si su matriz se llama a:

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

Sin embargo, no estoy seguro de cómo obtener el formato de nueva línea.

Editar ( crédito al comentario de Kevin J. Black aquí ):

Desde la versión 1.5.0, np.tofile()toma un parámetro opcional newline='\n'para permitir la salida multilínea. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

atomh33ls
fuente
Pero, ¿hay alguna manera de crear una matriz original a partir del archivo de texto?
Ahashan Alam Sojib
@AhashanAlamSojib ver stackoverflow.com/questions/3518778/…
atomh33ls
tofileno tiene newline='\n'.
Nico Schlömer
1

Simplemente puede atravesar la matriz en tres ciclos anidados y escribir sus valores en su archivo. Para leer, simplemente use la misma construcción de bucle exacta. Obtendrá los valores exactamente en el orden correcto para volver a llenar sus matrices correctamente.

jwueller
fuente
0

Tengo una manera de hacerlo usando una simple operación filename.write (). Funciona bien para mí, pero estoy tratando con matrices que tienen ~ 1500 elementos de datos.

Básicamente, solo tengo bucles for para iterar a través del archivo y escribirlo en el destino de salida línea por línea en una salida de estilo 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")

Las declaraciones if y elif se utilizan para agregar comas entre los elementos de datos. Por alguna razón, estos se eliminan al leer el archivo como una nd matriz. Mi objetivo era generar el archivo como un csv, por lo que este método ayuda a manejar eso.

¡Espero que esto ayude!

BennyD
fuente
0

El pepinillo es mejor para estos casos. Suponga que tiene un ndarray llamado x_train. Puede volcarlo en un archivo y revertirlo usando el siguiente comando:

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
fuente