Как записать многомерный массив в текстовый файл?

116

В другом вопросе другие пользователи предложили некоторую помощь, если бы я мог предоставить массив, с которым у меня возникли проблемы. Однако я даже не справляюсь с базовой задачей ввода-вывода, такой как запись массива в файл.

Может ли кто-нибудь объяснить, какой цикл мне понадобится для записи массива numpy 4x11x14 в файл?

Этот массив состоит из четырех массивов 11 x 14, поэтому я должен отформатировать его с красивой новой строкой, чтобы облегчить чтение файла для других.

Изменить : Итак, я пробовал функцию numpy.savetxt. Как ни странно, выдает следующую ошибку:

TypeError: float argument required, not numpy.ndarray

Я предполагаю, что это потому, что функция не работает с многомерными массивами? Какие-нибудь решения, как я хотел бы, в одном файле?

Иво Флипс
источник

Ответы:

198

Если вы хотите записать его на диск, чтобы его можно было легко прочитать как массив numpy, посмотрите numpy.save. Травление тоже подойдет, но для больших массивов оно менее эффективно (а у вас это не так, так что и то, и другое подойдет).

Если вы хотите, чтобы он был удобочитаемым человеком, изучите numpy.savetxt.

Изменить: Итак, похоже, не так savetxtуж и хорош вариант для массивов с> 2 измерениями ... Но просто чтобы подвести все к полному выводу:

Я только что понял, что numpy.savetxtзадыхается от ndarrays с более чем двумя измерениями ... Вероятно, это сделано намеренно, так как нет встроенного способа указать дополнительные измерения в текстовом файле.

Например, это (2D-массив) отлично работает

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

Хотя то же самое не получится (с довольно неинформативной ошибкой :) TypeError: float argument required, not numpy.ndarrayдля 3D-массива:

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

Одно из решений - просто разбить трехмерный (или более крупный) массив на двухмерные срезы. Например

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)

Однако наша цель - сделать его понятным для человека и при этом легко прочитать его numpy.loadtxt. Поэтому мы можем быть более подробными и различать фрагменты, используя закомментированные строки. По умолчанию numpy.loadtxtигнорируются любые строки, начинающиеся с #(или любого символа, указанного в commentskwarg). (Это выглядит более подробным, чем есть на самом деле ...)

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

Это дает:

# 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

Считать его обратно очень просто, если мы знаем форму исходного массива. Мы можем просто делать numpy.loadtxt('test.txt').reshape((4,5,10)). В качестве примера (вы можете сделать это одной строкой, я просто подробно разъясняю ситуацию):

# 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
+1 от меня, см. Также numpy.loadtxt( docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html )
Доминик Роджер
2
Теперь есть гораздо более простое решение этой проблемы: yourStrArray = np.array ([str (val) for val в yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Грег Крамида,
@GregKramida, а как восстановить массив?
astrojuanlu
@ Juanlu001: Я знаю, что numpy.loadtxt (...) также принимает аргумент dtype, который может иметь значение np.string_. В первую очередь я хотел бы попробовать. Также существует numpy.fromstring (...) для разбора массивов из строк.
Грег Крамида
Эй, а что, если мне нужно сохранить массив изображений? Как бы мы изменили его размер, если размер изображения, скажем, 512 x 512?
Амбика Саксена
31

Я не уверен, соответствует ли это вашим требованиям, учитывая, что я думаю, что вы заинтересованы в том, чтобы сделать файл доступным для чтения людям, но если это не является основной проблемой, просто pickleтак.

Чтобы сохранить это:

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

Чтобы прочитать это обратно:

import pprint, pickle

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

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

pkl_file.close()
Доминик Роджер
источник
Возможно, вам не понадобится pprintпечатать словарь.
zyy
11

Если вам не нужен понятный для человека вывод, вы можете попробовать еще один вариант - сохранить массив как .matфайл MATLAB , который является структурированным массивом. Я презираю MATLAB, но тот факт, что я могу читать и писать .matв очень небольшом количестве строк, удобен.

В отличие от ответа Джо Кингтона, преимущество этого состоит в том, что вам не нужно знать исходную форму данных в .matфайле, т.е. нет необходимости изменять форму при чтении. И, в отличие от использования pickle, .matфайл может быть прочитан MATLAB, и, возможно, некоторые другие программы / языки.

Вот пример:

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

Если вы забыли ключ, которым массив назван в .matфайле, вы всегда можете сделать:

print matdata.keys()

И, конечно же, вы можете хранить множество массивов, используя гораздо больше ключей.

Так что да - это не будет читаться вашими глазами, но для записи и чтения данных требуется всего 2 строки, что, на мой взгляд, является справедливым компромиссом.

Взгляните на документы для scipy.io.savemat и scipy.io.loadmat, а также на эту страницу руководства: scipy.io File IO Tutorial

aseagram
источник
9

ndarray.tofile() также должен работать

например, если ваш массив называется a:

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

Не знаю, как получить форматирование новой строки.

Изменить (кредит комментарий Кевина Дж. Блэка здесь ):

Начиная с версии 1.5.0, np.tofile()принимает необязательный параметр, newline='\n'разрешающий многострочный вывод. https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

atomh33ls
источник
Но есть ли способ создать исходный массив из текс-файла?
Ахашан Алам Соджиб
@AhashanAlamSojib см stackoverflow.com/questions/3518778/...
atomh33ls
1
tofileне имеет newline='\n'.
Нико Шлёмер
1

Вы можете просто пройти по массиву в трех вложенных циклах и записать их значения в свой файл. Для чтения вы просто используете ту же самую точную конструкцию цикла. Вы получите значения в правильном порядке, чтобы снова правильно заполнить массивы.

jwueller
источник
0

У меня есть способ сделать это с помощью простой операции filename.write (). У меня он отлично работает, но я имею дело с массивами, имеющими ~ 1500 элементов данных.

У меня в основном просто циклы for для перебора файла и записи его в конечный пункт вывода построчно в выводе в стиле 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")

Операторы if и elif используются для добавления запятых между элементами данных. По какой-то причине они удаляются при чтении файла в виде массива nd. Моей целью было вывести файл в формате CSV, поэтому этот метод помогает справиться с этим.

Надеюсь это поможет!

BennyD
источник
0

В таких случаях лучше всего подойдет рассол. Предположим, у вас есть ndarray с именем x_train. Вы можете выгрузить его в файл и вернуть обратно, используя следующую команду:

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)
Кенпачи Зараки
источник