【问题标题】:Resizing and storing dataset in .h5 format using h5py in python在 python 中使用 h5py 以 .h5 格式调整和存储数据集
【发布时间】:2019-05-19 04:09:33
【问题描述】:

我正在尝试使用 python 中的h5py 包调整数据集的大小并存储新值。我的数据集大小在每次实例中都在不断增加,我想使用resize 函数附加.h5 文件。但是,我使用我的方法遇到了错误。变量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")

【问题讨论】:

  • 主要问题是dset显示为[<Closed HDF5 dataset>, <Closed HDF5 dataset>]

标签: python arrays numpy h5py


【解决方案1】:

@tel 为这个问题提供了一个优雅的解决方案。我在他的回答下方的 cmets 中概述了一种更简单的方法。初学者编码(和理解)更简单。基本上,它对@Maxtron 的原始代码进行了一些小改动。修改如下:

  • with h5py.File(path, "a") as hf: 移动到__main__ 例程
  • create_h5py(hf) 中传递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))

【讨论】:

    【解决方案2】:

    问题

    不确定您的其余代码,但您不能在返回数据集的函数中使用上下文管理器模式(即with h5py.File(foo) as bar:)。正如您在问题下的评论中指出的那样,这意味着当您尝试访问数据集时,实际的 HDF5 文件将已经关闭。 h5py 中的数据集对象就像文件的实时视图,因此它们需要文件保持打开才能使用它们。因此,您会遇到错误。

    解决方案

    最好始终在托管上下文中与文件交互(即在with 子句中)。如果您的代码抛出错误,上下文管理器将(几乎总是)确保文件已关闭。这有助于避免因崩溃而导致的任何潜在数据丢失。

    在您的情况下,您可以通过编写自己的上下文管理器来管理文件,从而获得蛋糕(将数据集创建例程封装在单独的函数中)并吃掉它(在托管上下文中与 HDF5 文件交互)你。

    编码实际上非常简单。任何实现 __enter____exit__ 方法的 Python 对象都是有效的上下文管理器。这是一个完整的工作版本:

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

    【讨论】:

    • 我的问题是this 的扩展。在这里,作者使用with h5py.Fileopen 的文件。但是,它没有在函数中使用。
    • 非常感谢您提供宝贵的反馈。我认为你使用classdset 对象交互的方法是一个非常干净和健壮的实现。
    • 你也可以将with h5py.File(path, "a") as hf:移动到__main__,然后在create_h5py(hf)中传递hf。您将获得上下文管理器和更简单的def。编写自定义上下文管理器有什么好处?我错过了什么吗?
    • 你的建议对于初学者来说是一个比我上面介绍的更简单的模式(我想展示上下文管理器内部发生的事情,但我可能有点忘乎所以) .你应该根据这个想法在这个帖子中添加一个答案。
    猜你喜欢
    • 2023-01-10
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    • 2020-07-25
    • 2021-09-24
    • 2019-01-06
    • 2019-01-14
    • 2021-01-02
    相关资源
    最近更新 更多