Як записати багатовимірний масив у текстовий файл?


115

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

Хто-небудь може пояснити, який саме цикл мені потрібно написати, щоб нумерувати масив 4x11x14?

Цей масив складається з чотирьох масивів 11 x 14, тому я повинен відформатувати його з приємним новим рядком, щоб полегшити читання файлу для інших.

Редагувати : Отже, я спробував функцію numpy.savetxt. Як не дивно, вона дає таку помилку:

TypeError: float argument required, not numpy.ndarray

Я припускаю, що це тому, що функція не працює з багатовимірними масивами? Будь-які рішення, як я хотів би їх у одному файлі?

Відповіді:


197

Якщо ви хочете записати його на диск, щоб його було легко прочитати у вигляді нумерованого масиву, погляньте на це 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)

Одне вирішення полягає лише в тому, щоб розбити 3D (або більше) масив на 2D фрагменти. Напр

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) для val у yourMulDArray], dtype = 'string'); np.savetxt ('YourTextFile.txt', yourStrArray, fmt = '% s')
Грег Краміда

@GregKramida і як відновити масив?
astrojuanlu

@ Juanlu001: Я знаю, що numpy.loadtxt (...) також приймає аргумент dtype, який можна встановити на np.string_. Я б дав цей кадр, в першу чергу. Існує також numpy.fromstring (...) для розбору масивів з рядків.
Грег Краміда

Ей, що, якщо мені потрібно зберегти масив зображень? Як ми можемо змінити розмір, якщо розмір зображення дозволений, скажімо, 512 x 512?
Ambika Saxena

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 Підручник з файлу IO


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


Але чи є спосіб створити оригінальний масив з текстового файлу?
Ахашан Алам Соджиб


tofileне має newline='\n'.
Ніко


1

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


0

У мене є спосіб зробити це за допомогою операції просто filename.write (). Для мене це працює добре, але я маю справу з масивами, що мають ~ 1500 елементів даних.

Я в основному просто петлі перебирати файл і записувати його у вихідний пункт призначення по черзі у вихідному стилі 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 використовується для додавання коми між елементами даних. З будь-якої причини вони викреслюються під час читання файлу у вигляді другого масиву. Моєю метою було вивести файл у форматі csv, тому цей метод допомагає впоратися з цим.

Сподіваюся, це допомагає!


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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.