【问题标题】:Read HDF5 file into numpy array将 HDF5 文件读入 numpy 数组
【发布时间】:2018-03-25 18:36:13
【问题描述】:

我有以下代码将 hdf5 文件作为 numpy 数组读取:

hf = h5py.File('path/to/file', 'r')
n1 = hf.get('dataset_name')
n2 = np.array(n1)

当我打印 n2 时,我得到了这个:

Out[15]:
array([[<HDF5 object reference>, <HDF5 object reference>,
        <HDF5 object reference>, <HDF5 object reference>...

如何读取HDF5 object reference 以查看其中存储的数据?

【问题讨论】:

    标签: python numpy hdf5 h5py


    【解决方案1】:

    最简单的方法是使用 HDF5 数据集的.value 属性。

    >>> hf = h5py.File('/path/to/file', 'r')
    >>> data = hf.get('dataset_name').value # `data` is now an ndarray.
    

    您还可以对数据集进行切片,这会生成一个包含请求数据的实际 ndarray:

    >>> hf['dataset_name'][:10] # produces ndarray as well
    

    但请记住,h5py 数据集在许多方面的行为类似于ndarray。因此,您可以将数据集本身原封不动地传递给大多数(如果不是全部)NumPy 函数。因此,例如,这很好用:np.mean(hf.get('dataset_name'))

    编辑:

    我最初误解了这个问题。问题不在于加载数字数据,而是数据集实际上包含 HDF5 引用。这是一个奇怪的设置,在h5py 中阅读有点尴尬。您需要取消引用数据集中的每个引用。我将只为其中一个展示它。

    首先,让我们创建一个文件和一个临时数据集:

    >>> f = h5py.File('tmp.h5', 'w')
    >>> ds = f.create_dataset('data', data=np.zeros(10,))
    

    接下来,创建对它的引用并将其中一些存储在数据集中。

    >>> ref_dtype = h5py.special_dtype(ref=h5py.Reference)
    >>> ref_ds = f.create_dataset('data_refs', data=(ds.ref, ds.ref), dtype=ref_dtype)
    

    然后,您可以通过获取其名称,然后从引用的实际数据集中读取其中一个,以一种迂回的方式读取。

    >>> name = h5py.h5r.get_name(ref_ds[0], f.id) # 2nd argument is the file identifier
    >>> print(name)
    b'/data'
    >>> out = f[name]
    >>> print(out.shape)
    (10,)
    

    这是迂回的,但它似乎工作。 TL;DR 是:获取引用数据集的名称,并直接从中读取。

    注意:

    h5py.h5r.dereference 函数在这里似乎没什么用,尽管有这个名字。它返回被引用对象的 ID。这可以直接读取,但在这种情况下很容易导致崩溃(我在这个人为的例子中做了几次)。获取名称并从中读取要容易得多。

    注2:

    release notes for h5py 2.1 中所述,不推荐使用Dataset.value 属性,应酌情使用mydataset[...]mydataset[()] 替换。

    可追溯到 h5py 1.0 的属性 Dataset.value 已被弃用,并将在以后的版本中删除。此属性将整个数据集转储到 NumPy 数组中。使用.value 的代码应更新为使用NumPy 索引,并酌情使用mydataset[...]mydataset[()]

    【讨论】:

    • 我正在尝试,但当我打印 data 变量时,我仍然得到相同的 HDF5 object reference
    • 啊,我想我知道发生了什么事。您尝试加载的数据集实际上由 HDF5 引用组成。这不是数字数据。您可以通过对文件执行h5lsh5dump 来验证这一点。在这种情况下,我不知道如何从h5py 中的引用数据集中读取。
    • 看来您可以使用h5py.H5R 模块来取消引用数据集。你可以试试:h5py.h5r.dereference(hf['dataset_name'])
    • 当我尝试这样做时,我收到此错误消息TypeError: dereference() takes exactly 2 positional arguments (1 given)
    • 当我通过with h5py.File('path/to/file, 'r') as hdf: ls = list(hdf.keys()) print('List of datasets in this file: \n', ls) 列出密钥时,我得到List of datasets in this file: ['#refs#', 'data_set'] 不确定这是否有帮助
    【解决方案2】:

    你好,这是我用来读取hdf5数据的方式,希望对你有用

    with h5py.File('name-of-file.h5', 'r') as hf:
        data = hf['name-of-dataset'][:]
    

    【讨论】:

      【解决方案3】:

      HDF5 有一个简单的对象模型,用于存储datasets(粗略地说,相当于“文件数组”)并将它们组织成组(想想目录)。除了这两种对象类型之外,还有更强大的功能需要多层次的理解。

      手头是“Reference”。是HDF5存储模型中的内部地址。

      h5py 将为您完成所有工作,而无需调用任何晦涩的例程,因为它尽可能地遵循类似 dict 的接口(但对于引用,使其透明有点复杂)。

      在文档中查找的位置是Object and Region References。它指出要访问引用 ref 指向的对象,您可以这样做

       my_object = my_file[ref]
      

      在您的问题中,有两个步骤: 1.获取参考 2. 获取数据集

      # Open the file
      hf = h5py.File('path/to/file', 'r')
      # Obtain the dataset of references
      n1 = hf['dataset_name']
      # Obtain the dataset pointed to by the first reference
      ds = hf[n1[0]]
      # Obtain the data in ds
      data = ds[:]
      

      如果包含参考的数据集是二维的,例如,你必须使用

      ds = hf[n1[0,0]]
      

      如果数据集是标量,则必须使用

      data = ds[()]
      

      一次获取所有数据集:

      all_data = [hf[ref] for ref in n1[:]]
      

      假设 n1 的一维数据集。对于 2D,这个想法是成立的,但我没有看到写它的捷径。

      为了全面了解如何使用引用来往返数据,我编写了简短的“写入程序”和一个简短的“读取程序”:

      import numpy as np
      import h5py
      
      # Open file                                                                                    
      myfile = h5py.File('myfile.hdf5', 'w')
      
      # Create dataset                                                                               
      ds_0 = myfile.create_dataset('dataset_0', data=np.arange(10))
      ds_1 = myfile.create_dataset('dataset_1', data=9-np.arange(10))
      
      # Create a data                                                                                
      ref_dtype = h5py.special_dtype(ref=h5py.Reference)
      
      ds_refs = myfile.create_dataset('ref_to_dataset', shape=(2,), dtype=ref_dtype)
      
      ds_refs[0] = ds_0.ref
      ds_refs[1] = ds_1.ref
      
      myfile.close()
      

      import numpy as np
      import h5py
      
      # Open file                                                                                    
      myfile = h5py.File('myfile.hdf5', 'r')
      
      # Read the references                                                                          
      ref_to_ds_0 = myfile['ref_to_dataset'][0]
      ref_to_ds_1 = myfile['ref_to_dataset'][1]
      
      # Read the dataset                                                                             
      ds_0 = myfile[ref_to_ds_0]
      ds_1 = myfile[ref_to_ds_1]
      
      # Read the value in the dataset                                                                
      data_0 = ds_0[:]
      data_1 = ds_1[:]
      
      myfile.close()
      
      print(data_0)
      print(data_1)
      

      您会注意到,对于参考数据集,您不能使用标准的方便易用的 NumPy 语法。这是因为 HDF5 引用不能用 NumPy 数据类型表示。它们必须一次读取和写入。

      【讨论】:

        【解决方案4】:

        这是将 hdf5 文件读取为 numpy 数组的直接方法:

        import numpy as np
        import h5py
        
        hf = h5py.File('path/to/file.h5', 'r')
        n1 = np.array(hf["dataset_name"][:]) #dataset_name is same as hdf5 object name 
        
        print(n1)
        

        【讨论】:

          【解决方案5】:

          h5py 为此类任务提供了内在方法:read_direct()

          hf = h5py.File('path/to/file', 'r')
          n1 = np.zeros(shape, dtype=numpy_type)
          hf['dataset_name'].read_direct(n1)
          hf.close()
          

          如果您使用%timeit,组合步骤仍然比n1 = np.array(hf['dataset_name']) 快。唯一的缺点是,需要事先知道数据集的形状,数据提供者可以将其分配为属性。

          【讨论】:

            【解决方案6】:

            我尝试了之前建议的所有答案,但没有一个对我有用。 例如,read_direct() 方法给出错误“未为数据类型类定义操作”。 .value 方法也不起作用。经过一番挣扎后,我可以使用引用本身来获取 numpy 数组。

            import numpy as np
            import h5py
            f = h5py.File('file.mat','r')
            data2get = f.get('data2get')[:]
            
            data = np.zeros([data2get.shape[1]])
            for i in range(data2get.shape[1]):
                data[i]  = np.array(f[data2get[0][i]])[0][0]
            

            【讨论】:

              猜你喜欢
              • 2017-09-23
              • 2018-01-02
              • 2018-09-29
              • 2019-08-24
              • 2017-12-23
              • 2015-05-01
              • 2016-02-10
              • 2018-06-26
              • 2013-12-10
              相关资源
              最近更新 更多