结合hdf5文件

时间:2013-08-28 15:33:00

标签: python hdf5 h5py

我有许多hdf5文件,每个文件都有一个数据集。数据集太大而无法容纳在RAM中。我想将这些文件组合成一个单独包含所有数据集的文件(即,以将数据集连接成一个数据集)。

执行此操作的一种方法是创建hdf5文件,然后逐个复制数据集。这将是缓慢而复杂的,因为它需要缓冲副本。

有更简单的方法吗?似乎应该有,因为它实际上只是创建一个容器文件。

我正在使用python / h5py。

6 个答案:

答案 0 :(得分:30)

这实际上是HDF5的使用案例之一。 如果您只想从单个文件访问所有数据集,而不关心它们实际存储在磁盘上的方式,则可以使用external links。来自HDF5 website

  

外部链接允许组在另一个HDF5文件中包含对象,并使库能够访问这些对象,就像它们在当前文件中一样。通过这种方式,组可能看起来直接包含数据集,命名数据类型,甚至包含实际位于不同文件中的组。此功能是通过一组函数实现的,这些函数可以创建和管理链接,定义和检索外部对象的路径,以及解释链接名称:

Here's how to do it in h5py

myfile = h5py.File('foo.hdf5','a')
myfile['ext link'] = h5py.ExternalLink("otherfile.hdf5", "/path/to/resource")

小心点:打开myfile时,如果是现有文件,则应使用'a'打开它。如果您使用'w'打开它,它将删除其内容。

这比将所有数据集复制到新文件中要快得多。我不知道对otherfile.hdf5的访问速度有多快,但对所有数据集进行操作都是透明的 - 也就是说,h5py会将所有数据集视为驻留在foo.hdf5

答案 1 :(得分:13)

一种解决方案是将B界面用于HDF5 API的低级h5py function,尤其是H5Ocopy function:< / p>

h5py.h5o.copy

上面是使用In [1]: import h5py as h5 In [2]: hf1 = h5.File("f1.h5") In [3]: hf2 = h5.File("f2.h5") In [4]: hf1.create_dataset("val", data=35) Out[4]: <HDF5 dataset "val": shape (), type "<i8"> In [5]: hf1.create_group("g1") Out[5]: <HDF5 group "/g1" (0 members)> In [6]: hf1.get("g1").create_dataset("val2", data="Thing") Out[6]: <HDF5 dataset "val2": shape (), type "|O8"> In [7]: hf1.flush() In [8]: h5.h5o.copy(hf1.id, "g1", hf2.id, "newg1") In [9]: h5.h5o.copy(hf1.id, "val", hf2.id, "newval") In [10]: hf2.values() Out[10]: [<HDF5 group "/newg1" (1 members)>, <HDF5 dataset "newval": shape (), type "<i8">] In [11]: hf2.get("newval").value Out[11]: 35 In [12]: hf2.get("newg1").values() Out[12]: [<HDF5 dataset "val2": shape (), type "|O8">] In [13]: hf2.get("newg1").get("val2").value Out[13]: 'Thing' 版本h5py和iPython版本2.0.1-2+b1在Python版本0.13.1-2+deb7u1上创建的,来自或多或少的Debian Wheezy安装。在执行上述操作之前,文件2.7.3-4+deb7u1f1.h5不存在。 请注意,对于每个salotz,对于Python 3,数据集/组名称需要 f2.h5 (例如 bytes ),而不是 b"val"

命令str中的hf1.flush()是至关重要的,因为低级接口显然总是从存储在磁盘上的[7]文件的版本中提取,而不是缓存在内存中。可以通过使用例如.h5提供该组的ID来实现向不在File根目录的组复制数据集。

请注意,如果指定名称的对象已存在于目标位置,hf1.get("g1").id将失败,并显示异常(无clobber)。

答案 2 :(得分:11)

我使用官方hdf5工具中的h5copy找到了非python解决方案。 h5copy可以将hdf5文件中的各个指定数据集复制到另一个现有的hdf5文件中。

如果有人发现基于python / h5py的解决方案,我很高兴听到它。

答案 3 :(得分:2)

我通常使用ipythonh5copy工具来处理,与纯Python解决方案相比,这要快得多。一旦安装了h5copy。

控制台解决方案M.W.E。

#PLESE NOTE THIS IS IPYTHON CONSOLE CODE NOT PURE PYTHON

import h5py
#for every dataset Dn.h5 you want to merge to Output.h5 
f = h5py.File('D1.h5','r+') #file to be merged 
h5_keys = f.keys() #get the keys (You can remove the keys you don't use)
f.close() #close the file
for i in h5_keys:
        !h5copy -i 'D1.h5' -o 'Output.h5' -s {i} -d {i}

自动化控制台解决方案

要完全自动化该过程,假设您在该文件夹中工作,则存储要合并的文件:

import os 
d_names = os.listdir(os.getcwd())
d_struct = {} #Here we will store the database structure
for i in d_names:
   f = h5py.File(i,'r+')
   d_struct[i] = f.keys()
   f.close()

# A) empty all the groups in the new .h5 file 
for i in d_names:
    for j  in d_struct[i]:
        !h5copy -i '{i}' -o 'output.h5' -s {j} -d {j}

为添加的每个.h5文件创建一个新组

如果要将以前的数据集与output.h5分开,则必须先使用标记-p创建组:

 # B) Create a new group in the output.h5 file for every input.h5 file
 for i in d_names:
        dataset = d_struct[i][0]
        newgroup = '%s/%s' %(i[:-3],dataset)
        !h5copy -i '{i}' -o 'output.h5' -s {dataset} -d {newgroup} -p
        for j  in d_struct[i][1:]:
            newgroup = '%s/%s' %(i[:-3],j) 
            !h5copy -i '{i}' -o 'output.h5' -s {j} -d {newgroup}

答案 4 :(得分:1)

要对此进行更新,使用HDF5版本1.10会出现一个新功能,在此上下文中可能很有用,称为&#34;虚拟数据集&#34;。
在这里您可以找到简要的教程和一些解释: Virtual Datasets
这里有更完整详尽的解释和文档说明:
Virtual Datasets extra doc
在这里,h5py中的合并拉取请求将虚拟数据集API包含在h5py中:
h5py Virtual Datasets PR但我不知道它是否已经在当前的h5py版本中提供,或者将来会更晚。

答案 5 :(得分:0)

要使用Python(而非IPython)和h5copy合并HDF5文件,我们可以在GM's answer上构建:

import h5py
import os

d_names = os.listdir(os.getcwd())
d_struct = {} #Here we will store the database structure
for i in d_names:
   f = h5py.File(i,'r+')
   d_struct[i] = f.keys()
   f.close()

for i in d_names:
   for j  in d_struct[i]:
      os.system('h5copy -i %s -o output.h5 -s %s -d %s' % (i, j, j))