Bagaimana cara menulis array multidimensi ke file teks?

116

Dalam pertanyaan lain, pengguna lain menawarkan bantuan jika saya dapat menyediakan larik yang bermasalah. Namun, saya bahkan gagal pada tugas I / O dasar, seperti menulis array ke file.

Adakah yang bisa menjelaskan jenis loop yang saya perlukan untuk menulis array numpy 4x11x14 ke file?

Array ini terdiri dari empat larik berukuran 11 x 14, jadi saya harus memformatnya dengan baris baru yang bagus, untuk mempermudah pembacaan berkas pada orang lain.

Edit : Jadi saya sudah mencoba fungsi numpy.savetxt. Anehnya, ini memberikan kesalahan berikut:

TypeError: float argument required, not numpy.ndarray

Saya berasumsi bahwa ini karena fungsinya tidak bekerja dengan array multidimensi? Ada solusi yang saya inginkan dalam satu file?

Ivo Flipse
sumber

Jawaban:

198

Jika Anda ingin menulisnya ke disk agar mudah dibaca kembali sebagai larik numpy, periksa numpy.save. Pengawetan itu akan bekerja dengan baik, juga, tapi kurang efisien untuk array besar (yang Anda tidak, jadi baik-baik saja).

Jika Anda ingin agar dapat dibaca manusia, lihat numpy.savetxt.

Sunting: Jadi, sepertinya savetxtbukan pilihan yang bagus untuk array dengan> 2 dimensi ... Tapi hanya untuk menarik semuanya ke kesimpulan lengkap itu:

Saya baru menyadari bahwa numpy.savetxttersedak ndarrays dengan lebih dari 2 dimensi ... Ini mungkin berdasarkan desain, karena tidak ada cara yang ditentukan secara inheren untuk menunjukkan dimensi tambahan dalam file teks.

Misalnya Ini (array 2D) berfungsi dengan baik

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

Sementara hal yang sama akan gagal (dengan kesalahan yang agak tidak informatif :) TypeError: float argument required, not numpy.ndarrayuntuk array 3D:

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

Salah satu solusinya adalah dengan memecah array 3D (atau lebih besar) menjadi potongan 2D. Misalnya

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)

Namun, tujuan kami adalah agar dapat dibaca dengan jelas oleh manusia, sambil tetap mudah dibaca kembali numpy.loadtxt. Oleh karena itu, kita bisa sedikit lebih bertele-tele, dan membedakan irisan menggunakan baris yang diberi komentar. Secara default, numpy.loadtxtakan mengabaikan baris yang dimulai dengan #(atau karakter mana pun yang ditentukan oleh commentskwarg). (Ini terlihat lebih bertele-tele daripada yang sebenarnya ...)

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

Ini menghasilkan:

# 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

Membacanya kembali sangat mudah, selama kita mengetahui bentuk dari array aslinya. Kami bisa melakukannya numpy.loadtxt('test.txt').reshape((4,5,10)). Sebagai contoh (Anda dapat melakukan ini dalam satu baris, saya hanya bertele-tele untuk mengklarifikasi banyak hal):

# 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
sumber
2
+1 dari saya, lihat juga numpy.loadtxt( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )
Dominic Rodger
2
Ada solusi yang lebih mudah sekarang untuk masalah ini di sini: yourStrArray = np.array ([str (val) for val in yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Greg Kramida
@GregKramida dan bagaimana Anda memulihkan array?
astrojuanlu
@ Juanlu001: Saya tahu bahwa numpy.loadtxt (...) juga menerima argumen dtype, yang dapat disetel ke np.string_. Saya akan mencobanya, pertama dan terakhir. Ada juga numpy.fromstring (...) untuk mem-parsing array dari string.
Greg Kramida
Hei bagaimana jika saya perlu menyimpan array gambar? Bagaimana kita mengubah ukurannya jika ukuran gambar katakanlah, 512 x 512?
Ambika Saxena
31

Saya tidak yakin apakah ini memenuhi persyaratan Anda, mengingat saya pikir Anda tertarik membuat file dapat dibaca oleh orang, tetapi jika itu bukan perhatian utama, cukup pickle.

Untuk menyimpannya:

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

Untuk membacanya kembali:

import pprint, pickle

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

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

pkl_file.close()
Dominic Rodger
sumber
Anda mungkin tidak perlu pprintmencetak kamus.
zyy
11

Jika Anda tidak memerlukan output yang dapat dibaca manusia, opsi lain yang dapat Anda coba adalah menyimpan array sebagai .matfile MATLAB , yang merupakan array terstruktur. Saya membenci MATLAB, tetapi fakta bahwa saya dapat membaca dan menulis .matdalam beberapa baris adalah nyaman.

Tidak seperti jawaban Joe Kington, keuntungannya adalah Anda tidak perlu mengetahui bentuk asli dari data dalam .matfile tersebut, yaitu tidak perlu membentuk ulang setelah membaca. Dan, tidak seperti menggunakan pickle, .matfile dapat dibaca oleh MATLAB, dan mungkin beberapa program / bahasa lain juga.

Berikut ini contohnya:

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

Jika Anda lupa kunci yang dinamai array di .mat file, Anda selalu dapat melakukan:

print matdata.keys()

Dan tentu saja Anda dapat menyimpan banyak array menggunakan lebih banyak kunci.

Jadi ya - ini tidak akan terbaca dengan mata Anda, tetapi hanya membutuhkan 2 baris untuk menulis dan membaca data, yang menurut saya merupakan pertukaran yang adil.

Lihatlah dokumen untuk scipy.io.savemat dan scipy.io.loadmat dan juga halaman tutorial ini: scipy.io File IO Tutorial

aseagram
sumber
9

ndarray.tofile() juga harus bekerja

misalnya jika array Anda dipanggil a:

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

Tidak yakin bagaimana mendapatkan format baris baru.

Sunting (kreditkan komentar Kevin J. Black di sini ):

Sejak versi 1.5.0, np.tofile()mengambil parameter opsional newline='\n'untuk memungkinkan keluaran multi-baris. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

atomh33ls
sumber
Tetapi apakah ada cara untuk membuat array asli dari texfile?
Ahashan Alam Sojib
@AhashanAlamSojib lihat stackoverflow.com/questions/3518778/…
atomh33ls
1
tofiletidak punya newline='\n'.
Nico Schlömer
1

Anda cukup melintasi array dalam tiga loop bersarang dan menulis nilainya ke file Anda. Untuk membaca, Anda cukup menggunakan konstruksi loop yang sama persis. Anda akan mendapatkan nilai dengan urutan yang benar untuk mengisi array Anda dengan benar lagi.

jwueller.dll
sumber
0

Saya memiliki cara untuk melakukannya dengan menggunakan operasi nama file.write () sederhana. Ini berfungsi dengan baik untuk saya, tetapi saya berurusan dengan array yang memiliki ~ 1500 elemen data.

Saya pada dasarnya hanya memiliki loop untuk mengulang melalui file dan menuliskannya ke tujuan keluaran baris demi baris dalam gaya keluaran 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")

Pernyataan if dan elif digunakan untuk menambahkan koma di antara elemen data. Untuk alasan apa pun, ini dilucuti saat membaca file sebagai array nd. Tujuan saya adalah mengeluarkan file sebagai csv, jadi metode ini membantu mengatasinya.

Semoga ini membantu!

BennyD
sumber
0

Acar paling baik untuk kasus ini. Misalkan Anda memiliki ndarray bernama x_train. Anda dapat membuangnya ke dalam file dan mengembalikannya menggunakan perintah berikut:

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
sumber