首页 > 解决方案 > h5py:如何组织 HDF5 文件以有效读取混合数据类型对象

问题描述

我目前正在使用 python3.x 并使用 h5py 库来写入/读取 HDF5 文件。

假设我有大量包含混合数据类型属性的元素。我想将它们存储在 HDF5 文件中,以便可以通过索引尽可能有效地读取单个元素。

例如,假设我有以下数据:

item_1 = {'string_name': 'Paul', 'float_height': 5.9, 'int_age':27, 'numpy_data': np.array([5.4, 6.7, 8.8])}
item_2 = {'string_name': 'John', 'float_height': 5.7, 'int_age':31, 'numpy_data': np.array([3.1, 58.4, 66.4])}
...
item_1000000 = {'string_name': 'Anna', 'float_height': 6.1, 'int_age':33, 'numpy_data': np.array([4.7, 5.1, 4.2])}

我发现的最简单的解决方案是将每个属性存储在一个单独的数组中,然后将每个数组分别存储在 HDF5 文件中。

string_names = ['Paul', 'John', ... , 'Anna']
float_heights = [5.9, 5.7, ... , 6.1]
int_ages = [27, 31, ... , 33]
numpy_data = big_numpy_array_of_shape_1000000_by_3

然后,作为示例,要检索第三个元素,我必须为四个数组中的每一个读取索引“2”处的元素。

这个解决方案工作得很好,但我的猜测是它是一个非常低效的解决方案,因为需要四个读取操作来检索每个元素。

有什么建议么?

标签: pythonnumpyhdf5h5py

解决方案


正如@hpaulj 指出的那样,关键是创建一个记录数组(和/或dtype)并在创建数据集时引用。有很多方法可以加载数据。我使用您的列表数据(如下)创建了一个示例,该示例显示了最简单的 2 个(恕我直言)。阅读所有方法的参考资料。我不确定您是否可以从字典中加载。我确信有足够的 Python 和 NumPy 魔法是可能的。

import h5py
import numpy as np

string_names = ['Paul', 'John', 'Anna']
float_heights = [5.9, 5.7,  6.1]
int_ages = [27, 31, 33]
numpy_data = [ np.array([5.4, 6.7, 8.8]), 
               np.array([3.1, 58.4, 66.4]),
               np.array([4.7, 5.1, 4.2])  ] 

# Create empty record array with 3 rows
ds_dtype = [('name','S50'), ('height',float), ('ages',int), ('numpy_data', float, (3,) ) ]
ds_arr = np.recarray((3,),dtype=ds_dtype)
# load list data to record array by field name
ds_arr['name'] = np.asarray(string_names)
ds_arr['height'] = np.asarray(float_heights)
ds_arr['ages'] = np.asarray(int_ages)
ds_arr['numpy_data'] = np.asarray(numpy_data)

with h5py.File('SO_59483094.h5', 'w') as h5f:
# load data to dataset my_ds1 using recarray
    dset = h5f.create_dataset('my_ds1', data=ds_arr, maxshape=(None) )
# load data to dataset my_ds2 by lists/field names
    dset = h5f.create_dataset('my_ds2', dtype=ds_dtype, shape=(100,), maxshape=(None) )
    dset['name',0:3] = np.asarray(string_names)
    dset['height',0:3] = np.asarray(float_heights)
    dset['ages',0:3] = np.asarray(int_ages)
    dset['numpy_data',0:3] = np.asarray(numpy_data)

推荐阅读