将 HDF5 文件读入 numpy 数组

Posted

技术标签:

【中文标题】将 HDF5 文件读入 numpy 数组【英文标题】:Read HDF5 file into numpy array 【发布时间】:2018-03-25 18:36:13 【问题描述】:

我有以下代码将 hdf5 文件作为 numpy 数组读取:

hf = h5py.File('path/to/file', 'r')
n1 = hf.get('dataset_name')
n2 = np.array(n1)

当我打印 n2 时,我得到了这个:

Out[15]:
array([[<HDF5 object reference>, <HDF5 object reference>,
        <HDF5 object reference>, <HDF5 object reference>...

如何读取HDF5 object reference 以查看其中存储的数据?

【问题讨论】:

【参考方案1】:

最简单的方法是使用 HDF5 数据集的.value 属性。

>>> hf = h5py.File('/path/to/file', 'r')
>>> data = hf.get('dataset_name').value # `data` is now an ndarray.

您还可以对数据集进行切片,这会生成一个包含请求数据的实际 ndarray:

>>> hf['dataset_name'][:10] # produces ndarray as well

但请记住,h5py 数据集在许多方面的行为类似于ndarray。因此,您可以将数据集本身原封不动地传递给大多数(如果不是全部)NumPy 函数。因此,例如,这很好用:np.mean(hf.get('dataset_name'))

编辑:

我最初误解了这个问题。问题不在于加载数字数据,而是数据集实际上包含 HDF5 引用。这是一个奇怪的设置,在h5py 中阅读有点尴尬。您需要取消引用数据集中的每个引用。我将只为其中一个展示它。

首先,让我们创建一个文件和一个临时数据集:

>>> f = h5py.File('tmp.h5', 'w')
>>> ds = f.create_dataset('data', data=np.zeros(10,))

接下来,创建对它的引用并将其中一些存储在数据集中。

>>> ref_dtype = h5py.special_dtype(ref=h5py.Reference)
>>> ref_ds = f.create_dataset('data_refs', data=(ds.ref, ds.ref), dtype=ref_dtype)

然后,您可以通过获取其名称,然后从引用的实际数据集中读取其中一个,以一种迂回的方式读取。

>>> name = h5py.h5r.get_name(ref_ds[0], f.id) # 2nd argument is the file identifier
>>> print(name)
b'/data'
>>> out = f[name]
>>> print(out.shape)
(10,)

这是迂回的,但它似乎工作。 TL;DR 是:获取引用数据集的名称,并直接从中读取。

注意:

h5py.h5r.dereference 函数在这里似乎没什么用,尽管有这个名字。它返回被引用对象的 ID。这可以直接读取,但在这种情况下很容易导致崩溃(我在这个人为的例子中做了几次)。获取名称并从中读取要容易得多。

注2:

如release notes for h5py 2.1 中所述,不推荐使用Dataset.value 属性,应酌情使用mydataset[...]mydataset[()] 替换。

可追溯到 h5py 1.0 的属性 Dataset.value 已被弃用,并将在以后的版本中删除。此属性将整个数据集转储到 NumPy 数组中。使用.value 的代码应更新为使用NumPy 索引,并酌情使用mydataset[...]mydataset[()]

【讨论】:

我正在尝试,但当我打印 data 变量时,我仍然得到相同的 HDF5 object reference 啊,我想我知道发生了什么事。您尝试加载的数据集实际上由 HDF5 引用组成。这不是数字数据。您可以通过对文件执行h5lsh5dump 来验证这一点。在这种情况下,我不知道如何从h5py 中的引用数据集中读取。 看来您可以使用h5py.H5R 模块来取消引用数据集。你可以试试:h5py.h5r.dereference(hf['dataset_name']) 当我尝试这样做时,我收到此错误消息TypeError: dereference() takes exactly 2 positional arguments (1 given) 当我通过with h5py.File('path/to/file, 'r') as hdf: ls = list(hdf.keys()) print('List of datasets in this file: \n', ls) 列出密钥时,我得到List of datasets in this file: ['#refs#', 'data_set'] 不确定这是否有帮助【参考方案2】:

你好,这是我用来读取hdf5数据的方式,希望对你有用

with h5py.File('name-of-file.h5', 'r') as hf:
    data = hf['name-of-dataset'][:]

【讨论】:

【参考方案3】:

HDF5 有一个简单的对象模型,用于存储datasets(粗略地说,相当于“文件数组”)并将它们组织成组(想想目录)。除了这两种对象类型之外,还有更强大的功能需要多层次的理解。

手头是“Reference”。是HDF5存储模型中的内部地址。

h5py 将为您完成所有工作,而无需调用任何晦涩的例程,因为它尽可能地遵循类似 dict 的接口(但对于引用,使其透明有点复杂)。

在文档中查找的位置是Object and Region References。它指出要访问引用 ref 指向的对象,您可以这样做

 my_object = my_file[ref]

在您的问题中,有两个步骤: 1.获取参考 2. 获取数据集

# Open the file
hf = h5py.File('path/to/file', 'r')
# Obtain the dataset of references
n1 = hf['dataset_name']
# Obtain the dataset pointed to by the first reference
ds = hf[n1[0]]
# Obtain the data in ds
data = ds[:]

如果包含参考的数据集是二维的,例如,你必须使用

ds = hf[n1[0,0]]

如果数据集是标量,则必须使用

data = ds[()]

一次获取所有数据集:

all_data = [hf[ref] for ref in n1[:]]

假设 n1 的一维数据集。对于 2D,这个想法是成立的,但我没有看到写它的捷径。

为了全面了解如何使用引用来往返数据,我编写了简短的“写入程序”和一个简短的“读取程序”:

import numpy as np
import h5py

# Open file                                                                                    
myfile = h5py.File('myfile.hdf5', 'w')

# Create dataset                                                                               
ds_0 = myfile.create_dataset('dataset_0', data=np.arange(10))
ds_1 = myfile.create_dataset('dataset_1', data=9-np.arange(10))

# Create a data                                                                                
ref_dtype = h5py.special_dtype(ref=h5py.Reference)

ds_refs = myfile.create_dataset('ref_to_dataset', shape=(2,), dtype=ref_dtype)

ds_refs[0] = ds_0.ref
ds_refs[1] = ds_1.ref

myfile.close()

import numpy as np
import h5py

# Open file                                                                                    
myfile = h5py.File('myfile.hdf5', 'r')

# Read the references                                                                          
ref_to_ds_0 = myfile['ref_to_dataset'][0]
ref_to_ds_1 = myfile['ref_to_dataset'][1]

# Read the dataset                                                                             
ds_0 = myfile[ref_to_ds_0]
ds_1 = myfile[ref_to_ds_1]

# Read the value in the dataset                                                                
data_0 = ds_0[:]
data_1 = ds_1[:]

myfile.close()

print(data_0)
print(data_1)

您会注意到,对于参考数据集,您不能使用标准的方便易用的 NumPy 语法。这是因为 HDF5 引用不能用 NumPy 数据类型表示。它们必须一次读取和写入。

【讨论】:

【参考方案4】:

这是将 hdf5 文件读取为 numpy 数组的直接方法:

import numpy as np
import h5py

hf = h5py.File('path/to/file.h5', 'r')
n1 = np.array(hf["dataset_name"][:]) #dataset_name is same as hdf5 object name 

print(n1)

【讨论】:

【参考方案5】:

h5py 为此类任务提供了内在方法:read_direct()

hf = h5py.File('path/to/file', 'r')
n1 = np.zeros(shape, dtype=numpy_type)
hf['dataset_name'].read_direct(n1)
hf.close()

如果您使用%timeit,组合步骤仍然比n1 = np.array(hf['dataset_name']) 快。唯一的缺点是,需要事先知道数据集的形状,数据提供者可以将其分配为属性。

【讨论】:

【参考方案6】:

我尝试了之前建议的所有答案,但没有一个对我有用。 例如,read_direct() 方法给出错误“未为数据类型类定义操作”。 .value 方法也不起作用。经过一番挣扎后,我可以使用引用本身来获取 numpy 数组。

import numpy as np
import h5py
f = h5py.File('file.mat','r')
data2get = f.get('data2get')[:]

data = np.zeros([data2get.shape[1]])
for i in range(data2get.shape[1]):
    data[i]  = np.array(f[data2get[0][i]])[0][0]

【讨论】:

以上是关于将 HDF5 文件读入 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章

将 HDF5 文件中的大型数据集读入 x_train 并在 keras 模型中使用

大型 numpy (HDF5) 数组的统计信息

有没有办法让一个 numpy 样式的视图查看存储在 hdf5 文件中的数组切片?

将单色 png 读入 numpy 数组

无法将制表符分隔的文件读入 numpy 二维数组

如何在 NumPy 中将 HDF5 2D 数组转换为 1D?