Изменение размера и сохранение набора данных в формате .h5 с использованием h5py в python - PullRequest
0 голосов
/ 18 декабря 2018

Я пытаюсь изменить размер набора данных и сохранить новые значения, используя пакет h5py в python.Размер моего набора данных увеличивается с каждым разом, и я хотел бы добавить файл .h5, используя функцию resize.Тем не менее, я сталкиваюсь с ошибками, используя мой подход.Переменная dset представляет собой массив наборов данных.

import os
import h5py
import numpy as np

path = './out.h5'
os.remove(path)

def create_h5py(path):
    with h5py.File(path, "a") as hf:
        grp = hf.create_group('left')
        dset = []
        dset.append(grp.create_dataset('voltage', (10**4,3), maxshape=(None,3), dtype='f', chunks=(10**4,3)))
        dset.append(grp.create_dataset('current', (10**4,3), maxshape=(None,3), dtype='f', chunks=(10**4,3)))
        return dset

if __name__ == '__main__':
    dset = create_h5py(path)
    for i in range(3):

        if i == 0:
            dset[0][:] = np.random.random(dset[0].shape) 
            dset[1][:] = np.random.random(dset[1].shape)
        else:
            dset[0].resize(dset[0].shape[0]+10**4, axis=0)
            dset[0][-10**4:] = np.random.random((10**4,3))
            dset[1].resize(dset[1].shape[0]+10**4, axis=0)
            dset[1][-10**4:] = np.random.random((10**4,3))

РЕДАКТИРОВАТЬ

Благодаря tel я смог решить эту проблему.Заменить with h5py.File(path, "a") as hf: на hf = h5py.File(path, "a").

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

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

  • перемещение with h5py.File(path, "a") as hf: в __main__ рутина
  • проход hf в create_h5py(hf)
  • Я также добавил тест до os.remove()чтобы избежать ошибок, если файл h5 не существует

Мои предлагаемые изменения приведены ниже:

import h5py, os
import numpy as np

path = './out.h5'
# test existence of H5 file before deleting
if  os.path.isfile(path):
    os.remove(path)

def create_h5py(hf):
    grp = hf.create_group('left')
    dset = []
    dset.append(grp.create_dataset('voltage', (10**4,3), maxshape=(None,3), dtype='f', chunks=(10**4,3)))
    dset.append(grp.create_dataset('current', (10**4,3), maxshape=(None,3), dtype='f', chunks=(10**4,3)))
    return dset

if __name__ == '__main__':

    with h5py.File(path, "a") as hf:
        dset = create_h5py(hf)
        for i in range(3):

            if i == 0:
                dset[0][:] = np.random.random(dset[0].shape) 
                dset[1][:] = np.random.random(dset[1].shape)
            else:
                dset[0].resize(dset[0].shape[0]+10**4, axis=0)
                dset[0][-10**4:] = np.random.random((10**4,3))
                dset[1].resize(dset[1].shape[0]+10**4, axis=0)
                dset[1][-10**4:] = np.random.random((10**4,3))
0 голосов
/ 18 декабря 2018

Проблема

Не уверен насчет остальной части вашего кода, но вы не можете использовать шаблон диспетчера контекста (например, with h5py.File(foo) as bar:) в функции, которая возвращает набор данных.Как вы указали в комментарии под своим вопросом, это означает, что к тому времени, когда вы попытаетесь получить доступ к набору данных, фактический файл HDF5 уже будет закрыт.Объекты набора данных в h5py подобны интерактивным представлениям в файле, поэтому для их использования требуется, чтобы файл оставался открытым.Таким образом, вы получаете ошибки.

Решение

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

В вашем случае вы можете иметь свой торт (инкапсулировать подпрограммы создания набора данных в отдельной функции) и съесть его тоже (взаимодействовать с файлом HDF5 внутриуправляемый контекст), написав свой собственный менеджер контекста, который позаботится о вас.

На самом деле это довольно просто кодировать.Любой объект Python, который реализует методы __enter__ и __exit__, является допустимым диспетчером контекста.Вот полная рабочая версия:

import os
import h5py
import numpy as np

path = './out.h5'
try:
    os.remove(path)
except OSError: 
    pass

class H5PYManager:
    def __init__(self, path, method='a'):
        self.hf = h5py.File(path, method)

    def __enter__(self):
        # when you call `with H5PYManager(foo) as bar`, the return of this method will be assigned to `bar`
        return self.create_datasets()

    def __exit__(self, type, value, traceback):
        # this method gets called when you exit the `with` clause, including when an error is raised
        self.hf.close()    

    def create_datasets(self):
        grp = self.hf.create_group('left')
        return [grp.create_dataset('voltage', (10**4,3), maxshape=(None,3), dtype='f', chunks=(10**4,3)),
                grp.create_dataset('current', (10**4,3), maxshape=(None,3), dtype='f', chunks=(10**4,3))]

if __name__ == '__main__':
    with H5PYManager(path) as dset:
        for i in range(3):
            if i == 0:
                dset[0][:] = np.random.random(dset[0].shape) 
                dset[1][:] = np.random.random(dset[1].shape)
            else:
                dset[0].resize(dset[0].shape[0]+10**4, axis=0)
                dset[0][-10**4:] = np.random.random((10**4,3))
                dset[1].resize(dset[1].shape[0]+10**4, axis=0)
                dset[1][-10**4:] = np.random.random((10**4,3))
...