来自多个 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.view
或 numpy.concatenate
可以在不复制数据的情况下工作。
有没有人知道一种方法可以将多个数组视为一组堆叠的数组,而无需从h5py.Dataset
复制?
【问题讨论】:
解释更多你想用这些数据做什么('按需读取')以及为什么 numpy 连接(最明显的解决方案)是错误的。 是否有令人信服的理由不将所有数据存储在单个 2DDataset
中,然后使用切片索引访问各个子数组?
@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 文件/数据集的链数据集的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 C++ 库在 HDF5 中找出数据集的 PredType