Come scrivere un array multidimensionale in un file di testo?


116

In un'altra domanda, altri utenti hanno offerto un aiuto se potevo fornire l'array con cui avevo problemi. Tuttavia, non riesco nemmeno a svolgere un'attività di I / O di base, come scrivere un array in un file.

Qualcuno può spiegare che tipo di loop avrei bisogno per scrivere un array numpy 4x11x14 su file?

Questo array è composto da quattro array 11 x 14, quindi dovrei formattarlo con un bel ritorno a capo, per facilitare la lettura del file agli altri.

Modifica : quindi ho provato la funzione numpy.savetxt. Stranamente, dà il seguente errore:

TypeError: float argument required, not numpy.ndarray

Presumo che questo sia perché la funzione non funziona con gli array multidimensionali? Eventuali soluzioni come le vorrei all'interno di un file?

Risposte:


198

Se vuoi scriverlo su disco in modo che sia facile da leggere di nuovo come un array numpy, guarda in numpy.save. Anche il decapaggio funzionerà bene, ma è meno efficiente per array di grandi dimensioni (cosa che il tuo non è, quindi va perfettamente bene).

Se vuoi che sia leggibile dall'uomo, controlla numpy.savetxt.

Modifica: Quindi, sembra che savetxtnon sia un'opzione così eccezionale per gli array con> 2 dimensioni ... Ma solo per portare tutto alla sua conclusione completa:

Mi sono appena reso conto che si numpy.savetxtstrozza su ndarrays con più di 2 dimensioni ... Questo è probabilmente dovuto alla progettazione, poiché non esiste un modo intrinsecamente definito per indicare dimensioni aggiuntive in un file di testo.

Ad esempio, questo (un array 2D) funziona bene

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

Mentre la stessa cosa fallirebbe (con un errore piuttosto poco informativo :) TypeError: float argument required, not numpy.ndarrayper un array 3D:

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

Una soluzione alternativa è semplicemente suddividere l'array 3D (o superiore) in sezioni 2D. Per esempio

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)

Tuttavia, il nostro obiettivo è essere chiaramente leggibili dall'uomo, pur essendo facilmente leggibili con numpy.loadtxt. Pertanto, possiamo essere un po 'più prolissi e differenziare le sezioni usando le righe commentate. Per impostazione predefinita, numpy.loadtxtignorerà tutte le righe che iniziano con #(o il carattere specificato da commentskwarg). (Sembra più prolisso di quanto non sia in realtà ...)

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

Questo 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

Rileggerlo è molto semplice, purché conosciamo la forma dell'array originale. Possiamo solo fare numpy.loadtxt('test.txt').reshape((4,5,10)). Ad esempio (puoi farlo in una riga, sono solo prolisso per chiarire le cose):

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


2
C'è una soluzione molto più semplice ora a questo problema qui: yourStrArray = np.array ([str (val) for val in yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Greg Kramida

@GregKramida e come si ripristina l'array?
astrojuanlu

@ Juanlu001: So che numpy.loadtxt (...) accetta anche un argomento dtype, che può essere impostato su np.string_. Ci proverei, prima di tutto. C'è anche un numpy.fromstring (...) per analizzare gli array dalle stringhe.
Greg Kramida

Ehi, cosa succede se devo memorizzare un array di immagini? Come lo ridimensioneremmo se la dimensione dell'immagine fosse, diciamo, 512 x 512?
Ambika Saxena

31

Non sono sicuro che questo soddisfi le tue esigenze, dato che penso che tu sia interessato a rendere il file leggibile dalle persone, ma se questa non è una preoccupazione primaria, basta pickle.

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

Per rileggerlo:

import pprint, pickle

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

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

pkl_file.close()

Potrebbe non essere necessario pprintper stampare il dizionario.
zyy

11

Se non hai bisogno di un output leggibile dall'uomo, un'altra opzione che potresti provare è salvare l'array come .matfile MATLAB , che è un array strutturato. Disprezzo MATLAB, ma il fatto di poter sia leggere che scrivere .matin pochissime righe è conveniente.

A differenza della risposta di Joe Kington, il vantaggio di ciò è che non è necessario conoscere la forma originale dei dati nel .matfile, ovvero non è necessario rimodellare durante la lettura. E, a differenza dell'uso pickle, un .matfile può essere letto da MATLAB, e probabilmente anche altri programmi / linguaggi.

Ecco un esempio:

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

Se dimentichi la chiave con cui l'array è denominato nel .matfile, puoi sempre fare:

print matdata.keys()

E ovviamente puoi memorizzare molti array usando molte più chiavi.

Quindi sì, non sarà leggibile con i tuoi occhi, ma bastano solo 2 righe per scrivere e leggere i dati, il che penso sia un giusto compromesso.

Dai un'occhiata ai documenti per scipy.io.savemat e scipy.io.loadmat e anche a questa pagina tutorial: scipy.io File IO Tutorial


9

ndarray.tofile() dovrebbe funzionare anche

ad esempio, se il tuo array viene chiamato a:

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

Non sono sicuro di come ottenere la formattazione di nuova riga.

Modifica (credito al commento di Kevin J. Black qui ):

Dalla versione 1.5.0, np.tofile()accetta un parametro opzionale newline='\n'per consentire l'output su più righe. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html


Ma c'è un modo per creare un array originale dal texfile?
Ahashan Alam Sojib


1
tofilenon ha newline='\n'.
Nico Schlömer


1

Puoi semplicemente attraversare l'array in tre cicli annidati e scrivere i loro valori nel tuo file. Per la lettura, usi semplicemente la stessa identica struttura ad anello. Otterrai i valori esattamente nell'ordine giusto per riempire di nuovo correttamente i tuoi array.


0

Ho un modo per farlo usando semplicemente un'operazione filename.write (). Funziona bene per me, ma ho a che fare con array con ~ 1500 elementi di dati.

Fondamentalmente ho solo cicli for per iterare attraverso il file e scriverlo riga per riga nella destinazione di output in un output in stile 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")

Le istruzioni if ​​ed elif vengono utilizzate per aggiungere virgole tra gli elementi di dati. Per qualsiasi motivo, questi vengono rimossi durante la lettura del file come un nd array. Il mio obiettivo era generare il file come CSV, quindi questo metodo aiuta a gestirlo.

Spero che questo ti aiuti!


0

Pickle è il migliore per questi casi. Supponi di avere un ndarray denominato x_train. Puoi scaricarlo in un file e ripristinarlo utilizzando il seguente 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.