Как сохранить словари и массивы в одном архиве (с numpy.savez)

первый вопрос здесь. Я постараюсь быть кратким.

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

Я также создаю ярлыки для работы с функциями. Эти метки хранятся в массивах. Кроме того, существуют строки, содержащие точные параметры, используемые для запуска script и временной метки.

В целом это выглядит так:

import numpy as np    

feature1 = {}
feature2 = {}
label1 = np.array([])
label2 = np.array([])
docString = 'Commands passed to the script were...'

# features look like this:
feature1 = {'case 1': np.array([1, 2, 3, ...]),
            'case 2': np.array([2, 1, 3, ...]),
            'case 3': np.array([2, 3, 1, ...]),
            and so on... }

Теперь моя цель будет заключаться в следующем:

np.savez(outputFile, 
         saveFeature1 = feature1, 
         saveFeature2 = feature2, 
         saveLabel1 = label1, 
         saveLabel2 = label2,
         saveString = docString)

Это, по-видимому, работает (т.е. такой файл сохраняется без ошибки и может быть загружен снова). Однако, когда я снова пытаюсь загрузить, например, функцию из файла:

loadedArchive = np.load(outFile)
loadedFeature1 = loadedArchive['saveFeature1']
loadedString = loadedArchive['saveString']

Затем вместо того, чтобы возвращать словарь, я получаю numpy массив формы (0), где я не знаю, как получить доступ к содержимому:

In []: loadedFeature1
Out[]: 
       array({'case 1': array([1, 2, 3, ...]), 
              'case 2': array([2, 3, 1, ...]), 
              ..., }, dtype=object)

Также строки становятся массивами и получают странный тип данных:

In []: loadedString.dtype
Out[]: dtype('|S20')

Короче говоря, я предполагаю, что это не так, как это делается правильно. Однако я бы предпочел не помещать все переменные в один большой словарь, потому что я буду извлекать их в другом процессе и хотел бы просто перебрать словарь .keys(), не беспокоясь о сравнении строк.

Любые идеи приветствуются. Благодаря

Ответ 1

Как уже указывал @fraxel, использование pickle в этом случае намного лучше. Просто сохраните dict с вашими элементами в нем.

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

saved_data = dict(outputFile, 
                  saveFeature1 = feature1, 
                  saveFeature2 = feature2, 
                  saveLabel1 = label1, 
                  saveLabel2 = label2,
                  saveString = docString)

with open('test.dat', 'wb') as outfile:
    pickle.dump(saved_data, outfile, protocol=pickle.HIGHEST_PROTOCOL)

Чтобы было сказано, посмотрим, что происходит более подробно для иллюстративных целей.

numpy.savez ожидает, что каждый элемент будет массивом. Фактически, он вызывает np.asarray во всем, что вы проходите.

Если вы превратите dict в массив, вы получите массив объектов. Например.

import numpy as np

test = {'a':np.arange(10), 'b':np.arange(20)}
testarr = np.asarray(test)

Аналогично, если вы создаете массив из строки, вы получите массив строк:

In [1]: np.asarray('abc')
Out[1]: 
array('abc', 
      dtype='|S3')

Однако из-за причуды в том, как обрабатываются массивы объектов, если вы передаете один объект (в вашем случае ваш dict), который не является кортежем, списком или массивом, вы получите 0-мерный массив объектов.

Это означает, что вы не можете индексировать его напрямую. Фактически, при выполнении testarr[0] будет повышаться IndexError. Данные все еще существуют, но сначала вам нужно добавить измерение, поэтому вам нужно сделать yourdictionary = testarr.reshape(-1)[0].

Если все это кажется неуклюжим, это потому, что оно есть. Объектные массивы по существу всегда являются неправильным ответом. (Хотя asarray должен, вероятно, проходить в ndmin=1 до array, что решило бы эту конкретную проблему, но потенциально нарушит другие вещи.)

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

Если вы действительно захотите его использовать, скорее всего, это будет быстро:

np.savez(outputFile, 
         saveFeature1 = [feature1], 
         saveFeature2 = [feature2], 
         saveLabel1 = [label1], 
         saveLabel2 = [label2],
         saveString = docString)

И вы будете получать доступ к вещам с помощью

loadedArchive = np.load(outFile)
loadedFeature1 = loadedArchive['saveFeature1'][0]
loadedString = str(loadedArchive['saveString'])

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

Ответ 2

Если вам нужно сохранить свои данные структурированным способом, вам следует рассмотреть возможность использования формата файла HDF5 (http://www.hdfgroup.org/HDF5/). Он очень гибкий, простой в использовании, эффективный, и другое программное обеспечение уже может его поддерживать (HDFView, Mathematica, Matlab, Origin..). Существует простая привязка к python, называемая h5py.

Вы можете хранить наборы данных в файловой системе, такой как структура, и определять атрибуты для каждого набора данных, например, словарь. Например:

import numpy as np
import h5py

# some data
table1 = np.array([(1,1), (2,2), (3,3)], dtype=[('x', float), ('y', float)])
table2 = np.ones(shape=(3,3))

# save to data to file
h5file = h5py.File("test.h5", "w")
h5file.create_dataset("Table1", data=table1)
h5file.create_dataset("Table2", data=table2, compression=True)
# add attributes
h5file["Table2"].attrs["attribute1"] = "some info"
h5file["Table2"].attrs["attribute2"] = 42
h5file.close()

Чтение данных также прост, вы можете даже загрузить только несколько элементов из большого файла, если хотите:

h5file = h5py.File("test.h5", "r")
# read from file (numpy-like behavior)
print h5file["Table1"]["x"][:2]
# read everything into memory (real numpy array)
print np.array(h5file["Table2"])
# read attributes
print h5file["Table2"].attrs["attribute1"]

Дополнительные возможности и возможности можно найти в документации и на веб-сайтах (

Ответ 3

Поместите все свои переменные в объект, а затем используйте Pickle. Это лучший способ сохранить информацию о состоянии.