如何合并多个.h5文件?

时间:2019-10-01 14:28:42

标签: hdf5 h5py pytables hdf

在线提供的所有内容都太复杂了。对于部分导出的数据库,我的数据库很大。我现在有三个.h5文件,我想将它们合并为一个.h5文件,以进行进一步的工作。我该怎么办?

3 个答案:

答案 0 :(得分:1)

至少有3种方法可以将单个HDF5文件中的数据合并为一个文件:

  1. 使用外部链接创建一个指向其他文件中数据的新文件(需要pytables / tables模块)
  2. 使用HDF组实用程序h5copy.exe复制数据
  3. 使用Python复制数据(使用h5py或pytables)

此处提供了外部链接的示例:
https://stackoverflow.com/a/55399562/10462884
它显示了如何创建链接,然后如何取消对它们的引用。

h5copy的文档在这里:
https://support.hdfgroup.org/HDF5/doc/RM/Tools.html#Tools-Copy

使用h5py或pytables复制会更复杂。

答案 1 :(得分:1)

这些示例展示了如何使用 h5py 在2个HDF5文件之间复制数据集。有关 PyTables 示例,请参见我的其他答案。我创建了一些简单的HDF5文件来模拟CSV类型的数据(所有浮点数,但是如果您使用的是混合数据类型,则过程相同)。根据您的描述,每个文件只有一个数据集。当您有多个数据集时,可以在h5py中使用visititems()扩展此过程。

注意:创建示例中使用的HDF5文件的代码位于最后。

所有方法都使用glob()查找以下操作中使用的HDF5文件。

方法1:创建外部链接
这将在新的HDF5文件中产生3个组,每个组都有一个指向原始数据的外部链接。 这不会复制数据,而是通过1个文件中的链接提供对所有文件中数据的访问。

with h5py.File('table_links.h5',mode='w') as h5fw:
    link_cnt = 0 
    for h5name in glob.glob('file*.h5'):
        link_cnt += 1
        h5fw['link'+str(link_cnt)] = h5py.ExternalLink(h5name,'/')   

方法2:“按原样”复制数据
这将使用原始数据集名称将数据从原始文件中的每个数据集复制到新文件。 这要求每个文件中的数据集具有不同的名称。数据不会合并到一个数据集中。

with h5py.File('table_copy.h5',mode='w') as h5fw:
    for h5name in glob.glob('file*.h5'):
        h5fr = h5py.File(h5name,'r') 
        dset1 = list(h5fr.keys())[0]
        arr_data = h5fr[dset1][:]
        h5fw.create_dataset(dset1,data=arr_data)   

方法3a:将所有数据合并到1个固定大小的数据集中
这会将原始文件中每个数据集的数据复制并合并到新文件中的单个数据集中。 在此示例中,数据集名称没有限制。另外,我最初创建了一个大型数据集,并且不调整大小。假定有足够的行来保存所有合并的数据。在生产工作中应添加测试。

with h5py.File('table_merge.h5',mode='w') as h5fw:
    row1 = 0
    for h5name in glob.glob('file*.h5'):
        h5fr = h5py.File(h5name,'r') 
        dset1 = list(h5fr.keys())[0]
        arr_data = h5fr[dset1][:]
        h5fw.require_dataset('alldata', dtype="f",  shape=(50,5), maxshape=(100, 5) )
        h5fw['alldata'][row1:row1+arr_data.shape[0],:] = arr_data[:]
        row1 += arr_data.shape[0]

方法3b:将所有数据合并到1个可调整大小的数据集中
这类似于上面的方法。但是,我创建了一个可调整大小的数据集,并根据读取和添加的数据量进行了放大。

with h5py.File('table_merge.h5',mode='w') as h5fw:
    row1 = 0
    for h5name in glob.glob('file*.h5'):
        h5fr = h5py.File(h5name,'r') 
        dset1 = list(h5fr.keys())[0]
        arr_data = h5fr[dset1][:]
        dslen = arr_data.shape[0]
        cols = arr_data.shape[1]
        if row1 == 0: 
            h5fw.create_dataset('alldata', dtype="f",  shape=(dslen,cols), maxshape=(None, cols) )
        if row1+dslen <= len(h5fw['alldata']) :
            h5fw['alldata'][row1:row1+dslen,:] = arr_data[:]
        else :
            h5fw['alldata'].resize( (row1+dslen, cols) )
            h5fw['alldata'][row1:row1+dslen,:] = arr_data[:]
        row1 += dslen

要创建源文件,请阅读上文:

for fcnt in range(1,4,1):
    fname = 'file' + str(fcnt) + '.h5'
    arr = np.random.random(50).reshape(10,5)
    with h5py.File(fname,'w') as h5fw :
        h5fw.create_dataset('data_'+str(fcnt),data=arr)

答案 2 :(得分:1)

对于那些喜欢使用 PyTables 的用户,我重做了h5py示例,以显示在2个HDF5文件之间复制数据的不同方法。这些示例使用与以前相同的示例HDF5文件。每个文件只有一个数据集。当您有多个数据集时,可以在Pytables中使用walk_nodes()扩展此过程。

所有方法都使用glob()查找以下操作中使用的HDF5文件。

方法1:创建外部链接
与h5py相似,它在新的HDF5文件中创建3个组,每个组都有一个指向原始数据的外部链接。 数据未复制。

import tables as tb
with tb.File('table_links_2.h5',mode='w') as h5fw:
    link_cnt = 0 
    for h5name in glob.glob('file*.h5'):
        link_cnt += 1
        h5fw.create_external_link('/', 'link'+str(link_cnt), h5name+':/')

方法2:“按原样”复制数据
这将使用原始数据集名称将数据从原始文件中的每个数据集复制到新文件。数据集对象与源HDF5文件的类型相同。在这种情况下,它们是PyTable数组(因为所有列都是相同的类型)。 使用源HDF5中的名称复制数据集,因此每个数据集必须具有不同的名称。数据不会合并到单个数据集中。

with tb.File('table_copy_2.h5',mode='w') as h5fw:
    for h5name in glob.glob('file*.h5'):
        h5fr = tb.File(h5name,mode='r') 
        print (h5fr.root._v_children)
        h5fr.root._f_copy_children(h5fw.root)     

方法3a:将所有数据合并到1个数组中
这会将原始文件中每个数据集的数据复制并合并到新文件中的单个数据集中。同样,数据另存为PyTables数组。数据集名称没有限制。首先,我读取数据并追加到一个Numpy数组。处理完所有文件后,将Numpy数组复制到PyTables数组。此过程将Numpy数组保存在内存中,因此可能不适用于大型数据集。您可以通过使用Pytables EArray(可扩展数组)来避免此限制。请参阅方法3b。

with tb.File('table_merge_2a.h5',mode='w') as h5fw:
    row1 = 0
    for h5name in glob.glob('file*.h5'):
        h5fr = tb.File(h5name,mode='r') 
        dset1 = h5fr.root._f_list_nodes()[0]
        arr_data = dset1[:]
        if row1 == 0 :
           all_data = arr_data.copy()
           row1 += arr_data.shape[0]
        else :
           all_data = np.append(all_data,arr_data,axis=0)
           row1 += arr_data.shape[0]
    tb.Array(h5fw.root,'alldata', obj=all_data )

方法3b:将所有数据合并到1个可扩展EArray中
这类似于上面的方法,但是将数据增量保存在PyTables EArray中。 EArray.append()方法用于添加数据。此过程减少了方法3a中的内存问题。

with tb.File('table_merge_2b.h5',mode='w') as h5fw:
    row1 = 0
    for h5name in glob.glob('file*.h5'):
        h5fr = tb.File(h5name,mode='r') 
        dset1 = h5fr.root._f_list_nodes()[0]
        arr_data = dset1[:]
        if row1 == 0 :
           earr = h5fw.create_earray(h5fw.root,'alldata', 
                                     shape=(0,arr_data.shape[1]), obj=arr_data )
        else :
           earr.append(arr_data)
        row1 += arr_data.shape[0]   

方法4:将所有数据合并到1个表中
此示例突出显示了 h5py PyTables 之间的区别。在h5py中,数据集可以引用np.arraysnp.recarrays-h5py处理不同的dtype。在Pytables中,数组(以及CArray和EArray)引用nd.array数据,而Tables引用np.recarray数据。本示例说明如何将源文件中的nd.array数据转换为适用于Table对象的np.recarray数据。它还显示了如何使用与方法3b中的Table.append()类似的EArray.append()

with tb.File('table_append_2.h5',mode='w') as h5fw:
    row1 = 0
    for h5name in glob.glob('file*.h5'):
        h5fr = tb.File(h5name,mode='r') 
        dset1 = h5fr.root._f_list_nodes()[0]
        arr_data = dset1[:]
        ds_dt= ([ ('f1', float), ('f2', float), ('f3', float), ('f4', float), ('f5', float) ])
        recarr_data = np.rec.array(arr_data,dtype=ds_dt)
        if row1 == 0: 
            data_table = h5fw.create_table('/','alldata', obj=recarr_data)
        else :
            data_table.append(recarr_data)
        h5fw.flush()
        row1 += arr_data.shape[0]