Jak zapisać wielowymiarową tablicę do pliku tekstowego?

116

W innym pytaniu inni użytkownicy zaoferowali pomoc, jeśli mogę dostarczyć macierz, z którą miałem problem. Jednak nawet nie udaje mi się wykonać podstawowego zadania we / wy, takiego jak zapis tablicy do pliku.

Czy ktoś może wyjaśnić, jakiego rodzaju pętli potrzebowałbym, aby zapisać tablicę numpy 4x11x14 do pliku?

Ta tablica składa się z czterech tablic 11 x 14, więc powinienem sformatować ją ładnym znakiem nowej linii, aby ułatwić innym czytanie pliku.

Edycja : Więc wypróbowałem funkcję numpy.savetxt. O dziwo, daje następujący błąd:

TypeError: float argument required, not numpy.ndarray

Zakładam, że dzieje się tak, ponieważ funkcja nie działa z wielowymiarowymi tablicami? Jakieś rozwiązania, które bym chciał w jednym pliku?

Ivo Flipse
źródło

Odpowiedzi:

198

Jeśli chcesz zapisać go na dysku, aby można go było łatwo wczytać jako tablicę numpy, zajrzyj do numpy.save. Marynowanie również będzie działać dobrze, ale jest mniej wydajne w przypadku dużych tablic (które nie są twoje, więc oba są w porządku).

Jeśli chcesz, aby był czytelny dla człowieka, zajrzyj do numpy.savetxt.

Edycja: Wygląda na to, że savetxtnie jest tak dobra opcja dla tablic o wymiarach> 2 ... Ale żeby wyciągnąć wszystko do pełnego wniosku:

Właśnie zdałem sobie sprawę, że numpy.savetxtdławiki na ndarrayach z więcej niż 2 wymiarami ... Jest to prawdopodobnie zgodne z projektem, ponieważ nie ma z natury zdefiniowanego sposobu wskazania dodatkowych wymiarów w pliku tekstowym.

Np. To (tablica 2D) działa dobrze

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

Chociaż to samo zawiodłoby (z raczej nieinformacyjnym błędem :) TypeError: float argument required, not numpy.ndarraydla macierzy 3D:

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

Jednym z obejść jest po prostu rozbicie szyku 3D (lub wyższego) na plasterki 2D. Na przykład

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)

Jednak naszym celem jest zapewnienie czytelności dla człowieka, a jednocześnie łatwego wczytywania z powrotem numpy.loadtxt. Dlatego możemy być nieco bardziej gadatliwi i różnicować wycinki za pomocą zakomentowanych linii. Domyślnie numpy.loadtxtzignoruje wszystkie linie zaczynające się od #(lub jakikolwiek znak określony przez commentskwarg). (To wygląda na bardziej szczegółowe niż w rzeczywistości ...)

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

To daje:

# 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

Odczytanie go z powrotem jest bardzo łatwe, o ile znamy kształt oryginalnej tablicy. Po prostu możemy to zrobić numpy.loadtxt('test.txt').reshape((4,5,10)). Na przykład (możesz to zrobić w jednym wierszu, jestem tylko gadatliwy, aby wyjaśnić rzeczy):

# 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
źródło
2
+1 ode mnie, zobacz także numpy.loadtxt( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )
Dominic Rodger
2
Jest teraz znacznie łatwiejsze rozwiązanie tego problemu: yourStrArray = np.array ([str (val) for val in yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Greg Kramida,
@GregKramida i jak odzyskać tablicę?
astrojuanlu
@ Juanlu001: Wiem, że numpy.loadtxt (...) akceptuje również argument dtype, który można ustawić na np.string_. Dałbym temu strzał, pierwszy i ostatni. Istnieje również numpy.fromstring (...) do analizowania tablic z łańcuchów.
Greg Kramida,
Hej, a co jeśli muszę przechowywać tablicę obrazów? Jak zmienilibyśmy to, jeśli rozmiar obrazu to powiedzmy 512 x 512?
Ambika Saxena,
31

Nie jestem pewien, czy spełnia to twoje wymagania, biorąc pod uwagę, że myślę, że jesteś zainteresowany, aby ludzie mogli odczytać plik, ale jeśli to nie jest głównym problemem, po prostu pickleto.

Aby to zapisać:

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

Aby to przeczytać:

import pprint, pickle

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

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

pkl_file.close()
Dominic Rodger
źródło
Możesz nie potrzebować pprintdo wydrukowania słownika.
zyy
11

Jeśli nie potrzebujesz danych w postaci czytelnej dla człowieka, inną opcją, którą możesz wypróbować, jest zapisanie tablicy jako .matpliku MATLAB , który jest tablicą strukturalną. Gardzę MATLABEM, ale fakt, że potrafię zarówno czytać, jak i pisać .matw kilku wierszach, jest wygodny.

W przeciwieństwie do odpowiedzi Joe Kingtona, zaletą tego jest to, że nie musisz znać oryginalnego kształtu danych w .matpliku, tj. Nie ma potrzeby zmiany kształtu po wczytaniu. I w przeciwieństwie do używania pickle, .matplik może być odczytany przez MATLAB, i prawdopodobnie również inne programy / języki.

Oto przykład:

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

Jeśli zapomnisz klucza, którego nazwa tablicy znajduje się w .matpliku, zawsze możesz to zrobić:

print matdata.keys()

Oczywiście możesz przechowywać wiele tablic przy użyciu znacznie większej liczby kluczy.

Więc tak - nie będzie czytelny dla twoich oczu, ale zapisanie i odczyt danych zajmuje tylko 2 linie, co moim zdaniem jest uczciwym kompromisem.

Zapoznaj się z dokumentacją dotyczącą scipy.io.savemat i scipy.io.loadmat, a także z tą stroną samouczka: scipy.io Samouczek we / wy pliku

aseagram
źródło
9

ndarray.tofile() powinien również działać

np. jeśli twoja tablica nazywa się a:

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

Nie wiem jednak, jak uzyskać formatowanie nowej linii.

Edit (komentarz kredytowej Kevin J. Blacka tutaj ):

Od wersji 1.5.0 np.tofile()przyjmuje opcjonalny parametr, newline='\n'aby umożliwić wyjście wieloliniowe. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

atomh33ls
źródło
Ale czy istnieje sposób na utworzenie oryginalnej tablicy z pliku texfile?
Ahashan Alam Sojib
@AhashanAlamSojib patrz stackoverflow.com/questions/3518778/…
atomh33ls
1
tofilenie ma newline='\n'.
Nico Schlömer
1

Możesz po prostu przejść przez tablicę w trzech zagnieżdżonych pętlach i zapisać ich wartości w swoim pliku. Do czytania po prostu używasz tej samej dokładnej konstrukcji pętli. Otrzymasz wartości w dokładnie takiej kolejności, aby ponownie poprawnie wypełnić tablice.

jwueller
źródło
0

Mam sposób, aby to zrobić za pomocą prostej operacji filename.write (). U mnie działa dobrze, ale mam do czynienia z tablicami zawierającymi ~ 1500 elementów danych.

Zasadniczo mam po prostu pętle for do iteracji w pliku i zapisania go do docelowego miejsca wyjściowego linia po linii w wyniku w stylu 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")

Instrukcje if i elif służą do dodawania przecinków między elementami danych. Z jakiegoś powodu są one usuwane podczas wczytywania pliku jako tablicy nd. Moim celem było wyprowadzenie pliku jako csv, więc ta metoda pomaga sobie z tym poradzić.

Mam nadzieję że to pomoże!

BennyD
źródło
0

W takich przypadkach najlepsza jest marynata. Załóżmy, że masz ndarray o nazwie x_train. Możesz zrzucić go do pliku i przywrócić go za pomocą następującego polecenia:

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
źródło