Wie schreibe ich ein mehrdimensionales Array in eine Textdatei?

115

In einer anderen Frage boten andere Benutzer Hilfe an, wenn ich das Array bereitstellen konnte, mit dem ich Probleme hatte. Ich versage jedoch sogar bei einer grundlegenden E / A-Aufgabe, z. B. beim Schreiben eines Arrays in eine Datei.

Kann jemand erklären, welche Art von Schleife ich benötigen würde, um ein 4x11x14-Numpy-Array in eine Datei zu schreiben?

Dieses Array besteht aus vier 11 x 14 Arrays, daher sollte ich es mit einer schönen neuen Zeile formatieren, um anderen das Lesen der Datei zu erleichtern.

Bearbeiten : Also habe ich die Funktion numpy.savetxt ausprobiert. Seltsamerweise gibt es den folgenden Fehler:

TypeError: float argument required, not numpy.ndarray

Ich gehe davon aus, dass dies daran liegt, dass die Funktion nicht mit mehrdimensionalen Arrays funktioniert. Irgendwelche Lösungen, wie ich sie in einer Datei haben möchte?

Ivo Flipse
quelle

Antworten:

197

Wenn Sie es auf die Festplatte schreiben möchten, damit es leicht als numpy-Array wieder eingelesen werden kann, schauen Sie in numpy.save . Das Beizen funktioniert auch gut, ist aber für große Arrays weniger effizient (was bei Ihnen nicht der Fall ist, also ist beides vollkommen in Ordnung).

Wenn Sie möchten, dass es für Menschen lesbar ist, schauen Sie in numpy.savetxt.

Edit: Also, es scheint sosavetxt also keine so gute Option für Arrays mit> 2 Dimensionen zu sein ... Aber nur um alles zu seiner vollständigen Schlussfolgerung zu ziehen:

Das habe ich gerade gemerkt numpy.savetxt Drosseln auf ndarrays mit mehr als 2 Dimensionen vorhanden sind ... Dies ist wahrscheinlich beabsichtigt, da es keine inhärent definierte Möglichkeit gibt, zusätzliche Dimensionen in einer Textdatei anzugeben.

ZB Dies (ein 2D-Array) funktioniert gut

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

Während dasselbe TypeError: float argument required, not numpy.ndarrayfür ein 3D-Array fehlschlagen würde (mit einem eher uninformativen Fehler :):

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

Eine Problemumgehung besteht darin, das 3D-Array (oder ein größeres Array) in 2D-Slices zu unterteilen. Z.B

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)

Unser Ziel ist es jedoch, klar lesbar zu sein und dennoch leicht wieder einzulesen numpy.loadtxt. Daher können wir etwas ausführlicher sein und die Slices anhand auskommentierter Zeilen unterscheiden. Standardmäßig numpy.loadtxtwerden alle Zeilen ignoriert, die mit beginnen #(oder welches Zeichen auch immer vom commentskwarg angegeben wird ). (Das sieht ausführlicher aus als es tatsächlich ist ...)

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

Dies ergibt:

# 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

Das Zurücklesen ist sehr einfach, solange wir die Form des ursprünglichen Arrays kennen. Wir können es einfach tun numpy.loadtxt('test.txt').reshape((4,5,10)). Als Beispiel (Sie können dies in einer Zeile tun, ich bin nur ausführlich, um die Dinge zu klären):

# 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
quelle
2
+1 von mir, siehe auch numpy.loadtxt( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )
Dominic Rodger
2
Es gibt jetzt eine viel einfachere Lösung für dieses Problem: yourStrArray = np.array ([str (val) für val in yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Greg Kramida
@ GregKramida und wie stellen Sie das Array wieder her?
Astrojuanlu
@ Juanlu001: Ich weiß, dass numpy.loadtxt (...) auch ein dtype-Argument akzeptiert, das auf np.string_ gesetzt werden kann. Ich würde es in erster Linie versuchen. Es gibt auch eine numpy.fromstring (...) zum Parsen von Arrays aus Strings.
Greg Kramida
Hey, was ist, wenn ich ein Bildarray speichern muss? Wie würden wir die Größe ändern, wenn die Bildgröße beispielsweise 512 x 512 beträgt?
Ambika Saxena
31

Ich bin mir nicht sicher, ob dies Ihren Anforderungen entspricht, da ich denke, dass Sie daran interessiert sind, die Datei für Menschen lesbar zu machen, aber wenn dies kein Hauptanliegen ist, ist es einfach pickleso.

So speichern Sie es:

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

Um es zurückzulesen:

import pprint, pickle

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

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

pkl_file.close()
Dominic Rodger
quelle
Möglicherweise benötigen Sie nicht pprint, um das Wörterbuch zu drucken.
Zyy
11

Wenn Sie keine für Menschen lesbare Ausgabe benötigen, können Sie das Array auch als MATLAB- .matDatei speichern, bei der es sich um ein strukturiertes Array handelt. Ich verachte MATLAB, aber die Tatsache, dass ich .matin sehr wenigen Zeilen sowohl lesen als auch schreiben kann , ist praktisch.

Im Gegensatz zu Joe Kingtons Antwort ist der Vorteil davon, dass Sie die ursprüngliche Form der Daten in der .matDatei nicht kennen müssen, dh beim Einlesen keine Umformung vornehmen müssen. Im Gegensatz zur Verwendung picklekann eine .matDatei von MATLAB gelesen werden. und wahrscheinlich auch einige andere Programme / Sprachen.

Hier ist ein Beispiel:

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

Wenn Sie den Schlüssel vergessen, den das Array in der .mat Datei benannt ist, können Sie immer Folgendes tun:

print matdata.keys()

Und natürlich können Sie viele Arrays mit viel mehr Schlüsseln speichern.

Also ja - es ist nicht mit Ihren Augen lesbar, sondern benötigt nur 2 Zeilen, um die Daten zu schreiben und zu lesen, was ich für einen fairen Kompromiss halte.

Schauen Sie sich die Dokumente für scipy.io.savemat und scipy.io.loadmat sowie diese Tutorial-Seite an: scipy.io File IO Tutorial

Aseagramm
quelle
9

ndarray.tofile() sollte auch funktionieren

zB wenn Ihr Array heißt a:

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

Ich bin mir jedoch nicht sicher, wie ich die Zeilenumbruchformatierung erhalten soll.

Bearbeiten (Kredit Kevin J. Blacks Kommentar hier ):

Seit Version 1.5.0 wird np.tofile()ein optionaler Parameter verwendet newline='\n', um eine mehrzeilige Ausgabe zu ermöglichen. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

atomh33ls
quelle
Aber gibt es eine Möglichkeit, ein Original-Array aus der Texdatei zu erstellen?
Ahashan Alam Sojib
@ AhashanAlamSojib siehe stackoverflow.com/questions/3518778/…
atomh33ls
tofilehat nicht newline='\n'.
Nico Schlömer
1

Sie können das Array einfach in drei verschachtelten Schleifen durchlaufen und deren Werte in Ihre Datei schreiben. Zum Lesen verwenden Sie einfach die gleiche exakte Schleifenkonstruktion. Sie erhalten die Werte in genau der richtigen Reihenfolge, um Ihre Arrays wieder korrekt zu füllen.

jwueller
quelle
0

Ich habe eine Möglichkeit, dies mit einer einfachen Operation filename.write () zu tun. Es funktioniert gut für mich, aber ich habe es mit Arrays mit ~ 1500 Datenelementen zu tun.

Ich habe im Grunde nur for-Schleifen, um die Datei zu durchlaufen und sie zeilenweise in einer Ausgabe im CSV-Stil in das Ausgabeziel zu schreiben.

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

Die if- und elif-Anweisung werden verwendet, um Kommas zwischen den Datenelementen hinzuzufügen. Aus irgendeinem Grund werden diese beim Einlesen der Datei als nd-Array entfernt. Mein Ziel war es, die Datei als CSV auszugeben, daher hilft diese Methode, dies zu handhaben.

Hoffe das hilft!

BennyD
quelle
0

Gurke ist am besten für diese Fälle. Angenommen, Sie haben einen ndarray namens x_train. Sie können es in eine Datei kopieren und mit dem folgenden Befehl zurücksetzen:

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
quelle