来自多个 HDF5 文件/数据集的链数据集

Posted

技术标签:

【中文标题】来自多个 HDF5 文件/数据集的链数据集【英文标题】:Chain datasets from multiple HDF5 files/datasets 【发布时间】:2016-06-02 17:41:47 【问题描述】:

h5py(通过 HDF5)为在磁盘上持久化数据集提供的好处和简单的映射非常出色。我对一组文件进行了一些分析,并将结果存储到一个数据集中,每个文件一个。在这一步结束时,我有一组包含二维数组的 h5py.Dataset 对象。数组的列数相同,但行数不同,即 (A,N)、(B,N)、(C,N) 等。

我现在想将这些多个 2D 数组作为单个数组 2D 数组进行访问。也就是说,我想将它们按需读取为形状数组(A+B+C,N)。

为此,h5py.Link 类没有帮助,因为它在 HDF5 节点级别上工作。

这是一些伪代码:

import numpy as np
import h5py
a = h5py.Dataset('a',data=np.random.random((100, 50)))
b = h5py.Dataset('b',data=np.random.random((300, 50)))
c = h5py.Dataset('c',data=np.random.random((253, 50)))

# I want to view these arrays as a single array
combined = magic_array_linker([a,b,c], axis=1)
assert combined.shape == (100+300+253, 50)

出于我的目的,将数组复制到新文件中的建议不起作用。我也愿意在 numpy 级别解决这个问题,但我找不到任何合适的选项 numpy.viewnumpy.concatenate 可以在不复制数据的情况下工作。

有没有人知道一种方法可以将多个数组视为一组堆叠的数组,而无需从h5py.Dataset 复制?

【问题讨论】:

解释更多你想用这些数据做什么('按需读取')以及为什么 numpy 连接(最明显的解决方案)是错误的。 是否有令人信服的理由不将所有数据存储在单个 2D Dataset 中,然后使用切片索引访问各个子数组? @ali_m,单个数据集分析是基于增量分析生成的,有时也会创建新数据集。如果我必须连接并存储所有数据集,那么每次创建或更改新数据集时我都必须这样做。而且他们一个人可能会经常更换。此外,通过从单独的文件中读取,可以轻松过滤或选择数据集。对于如何链接数据集的任何见解,我将不胜感激。 @hpaulj,如果我找不到方法,连接 numpy 数组肯定是我的后备解决方案。例如,如果我在 h5py 数据集上运行 np.concatenate([a, b, c]),这会将它们读入内存吗?如果是这样,那么此解决方案不适用于大量数据。 有人对此有什么建议吗? 【参考方案1】:

首先,我认为没有办法在不复制数据以返回单个数组的情况下执行此操作。据我所知,不可能将 numpy 视图连接到一个数组中 - 当然,除非您创建自己的包装器。

在这里,我使用Object/Region references 演示概念证明。基本前提是我们在文件中创建一个新数据集,它是对组成子数组的引用数组。通过像这样存储引用,子数组可以动态更改大小,并且索引包装器将始终索引正确的子数组。

由于这只是一个概念证明,我没有实现正确的切片,只是非常简单的索引。也没有尝试进行错误检查 - 这几乎肯定会在生产中中断。

class MagicArray(object):
    """Magically index an array of references
    """
    def __init__(self, file, references, axis=0):
        self.file = file
        self.references = references
        self.axis = axis

    def __getitem__(self, items):
        # We need to modify the indices, so make sure items is a list
        items = list(items)

        for item in items:
            if hasattr(item, 'start'):
                # items is a slice object
                raise ValueError('Slices not implemented')

        for ref in self.references:
            size = self.file[ref].shape[self.axis]

            # Check if the requested index is in this subarray
            # If not, subtract the subarray size and move on
            if items[self.axis] < size:
                item_ref = ref
                break
            else:
                items[self.axis] = items[self.axis] - size

        return self.file[item_ref][tuple(items)]

这是你如何使用它:

with h5py.File("/tmp/so_hdf5/test.h5", 'w') as f:
    a = f.create_dataset('a',data=np.random.random((100, 50)))
    b = f.create_dataset('b',data=np.random.random((300, 50)))
    c = f.create_dataset('c',data=np.random.random((253, 50)))

    ref_dtype = h5py.special_dtype(ref=h5py.Reference)
    ref_dataset = f.create_dataset("refs", (3,), dtype=ref_dtype)

    for i, key in enumerate([a, b, c]):
        ref_dataset[i] = key.ref

with h5py.File("/tmp/so_hdf5/test.h5", 'r') as f:
    foo = MagicArray(f, f['refs'], axis=0)
    print(foo[104, 4])
    print(f['b'][4,4])

这应该很容易扩展到更高级的索引(即能够处理切片),但如果不复制数据,我看不出如何做到这一点。

您也许可以从numpy.ndarray 继承并获得所有常用方法。

【讨论】:

以上是关于来自多个 HDF5 文件/数据集的链数据集的主要内容,如果未能解决你的问题,请参考以下文章

从时间戳图像对创建 HDF5 数据集的最佳方法是啥?

如何使用 C++ 库在 HDF5 中找出数据集的 PredType

HDF5 数据集数量限制

C++ HDF5 使用数据集的维度作为 const int

在 Fortran 中读取 HDF5 数据集的子集时出现问题

在 MATLAB 中读取 HDF5 数据集的一些特定元素