使用h5py对hdf5进行增量写入

36 投票
2 回答
35129 浏览
提问于 2025-04-19 17:21

我有个问题,想知道用Python和h5py写hdf5文件的最佳方法。

我有一些数据,像这样:

-----------------------------------------
| timepoint | voltage1 | voltage2 | ...
-----------------------------------------
| 178       | 10       | 12       | ...
-----------------------------------------
| 179       | 12       | 11       | ...
-----------------------------------------
| 185       | 9        | 12       | ...
-----------------------------------------
| 187       | 15       | 12       | ...
                    ...

大约有10^4列,和大约10^7行。(这大约是10^11(1000亿)个元素,或者说大约100GB,假设每个元素占用1个字节)。

对于这些数据,通常的使用方式是写一次,读很多次。典型的读取方式是抓取第一列和另一列(比如第254列),把这两列加载到内存中,然后进行一些复杂的统计分析。

我觉得一个好的hdf5结构应该是把上面表格中的每一列都作为一个hdf5组,这样就会有10^4个组。这样我们就不需要把所有数据都读入内存,对吧?不过hdf5的结构还没有确定,所以可以随意设计。

现在问题来了:我每次接收的数据大约是10^4行(而且每次接收的行数不完全相同),需要逐步写入到hdf5文件中。我该怎么写这个文件呢?

我在考虑使用Python和h5py,但如果有其他推荐的工具也可以。是不是应该用分块的方式,比如说:

dset = f.create_dataset("voltage284", (100000,), maxshape=(None,), dtype='i8', chunks=(10000,))

然后当另一块10^4行的数据到达时,替换掉数据集?

还是说把每块10^4行的数据存储为一个单独的数据集更好?或者我真的需要知道最终的行数吗?(这可能有点难,但也许可以做到)。

如果hdf5不是合适的工具,我也可以放弃它,不过我觉得一旦解决了写入的问题,它会非常好用。

2 个回答

7

正如@unutbu提到的,dset.resize是一个很不错的选择。你可以看看pandas以及它对HDF5的支持,这可能对你的工作流程有帮助。听起来HDF5是个合适的选择,但有可能你的问题用一个额外的层来表达会更好。

一个需要考虑的重要点是数据的方向。如果你主要关注的是读取数据,并且主要是按列来获取数据,那么你可能需要把数据转置一下,这样读取时就可以按行进行,因为HDF5是按行优先的方式存储数据的。

37

根据常见问题解答,你可以使用 dset.resize 来扩展数据集。比如说,

import os
import h5py
import numpy as np
path = '/tmp/out.h5'
os.remove(path)
with h5py.File(path, "a") as f:
    dset = f.create_dataset('voltage284', (10**5,), maxshape=(None,),
                            dtype='i8', chunks=(10**4,))
    dset[:] = np.random.random(dset.shape)        
    print(dset.shape)
    # (100000,)

    for i in range(3):
        dset.resize(dset.shape[0]+10**4, axis=0)   
        dset[-10**4:] = np.random.random(10**4)
        print(dset.shape)
        # (110000,)
        # (120000,)
        # (130000,)

撰写回答