使用 Python 在 HDF5 文件中查找特定值的所有路径的最有效方法是什么?

What is the most efficient way to find all paths to particular values in HDF5 file with Python?

我正在具有以下体系结构的 .hdf5 文件中查找负值:

- Incidence_0
   - Wavelength_0
      - (Table of size m * n)
   - Wavelength_1
      - (Table of size m * n)
   ...
- Incidence_1
   ...
...

我的objective是找出每一个负值,并取回它在文件中的确切位置(即入射数,波长数,以及它在关联table).

很抱歉,我无法提供最小的可重现示例,因为我无法提供我正在使用的文件,但这是我的想法。

import h5py

file = h5py.File('testFile.hdf5', 'r')

result = []

for incidence in range(nbIncidence):
    for wavelength in range(nbWavelength):
        for theta in range(nbTheta):
            for phi in range(nbPhi):
                value = file['Incidence_' + str(incidence)]['Wavelength_' + str(wavelength)][theta, phi]

                if (value < 0):
                    result.append([value, incidence, wavelength, theta, phi])

这是完美的工作,但使用四个循环很耗时,尤其是如果我必须处理大文件,这可能会发生...我对 h5py 库了解不够,但我很确定它存在一种比那更快的方法。

首先,坏消息是:h5py 没有按照您描述的方式查询数据的功能。好消息:您可以通过将每个 Incident/Wavelength 数据集提取到一个 NumPy 数组,然后结合 2 个 NumPy 方法对提取的数组进行操作来完成您的任务。 [注意:这假设您有足够的内存来加载每个数据集。]

关于处理这些数据的一些观察(以帮助您效仿我的示例)。

  1. HDF5 文件架构是 self-describing。所以你不需要遍历整数计数器。相反,您可以使用 .keys() 方法获取组和数据集名称。 (或者,您可以使用 .items() 方法获得 (name, object) 个元组。)
  2. 我强烈建议您使用 Python 的文件上下文管理器,以确保您不会 退出时保持文件打开。
  3. 使用标准的 numpy 切片符号将数据集中的数据读入 numpy 数组。空元组检索所有数据。在您的架构中使用以下内容:arr = file['Incidence_#']['Wavelength_#'][()]
  4. 根据您指定的条件创建一个新的布尔数组。使用 arr < 0 将 return True 用于所有负值(和 False 用于其他值)。
  5. 使用 np.argwhere 查找数组元素索引 non-zero。在布尔数组上使用它(记住 True 是 non-zero,False 是零)。
  6. 从那里,您可以遍历索引以提取所需的数据。 :-)

我创建了一个模仿您的架构的简单示例来演示该过程。为了完整起见,该代码在最后。这是一个小文件,不会让您埋没在输出中。

下面的代码读取数据、查找负值并将数据添加到列表中。它有几个打印语句,因此您可以看到每个步骤是如何工作的。一旦您对程序有信心,就不需要它们了。

with h5py.File('testFile.hdf5', 'r') as h5fr:
    result = []
    
    for i_grp in h5fr.keys():
        for wave_ds in h5fr[i_grp].keys():
            wave_arr = h5fr[i_grp][wave_ds][()]
            neg_idx = np.argwhere(wave_arr < 0.0)
            wave_res = []
            for n in neg_idx:
                i, j = n[0], n[1]
                result.append([wave_arr[i,j], i_grp, wave_ds, i, j])
                wave_res.append([wave_arr[i,j], i_grp, wave_ds, i, j])
            print(f'\nResults for {i_grp}; {wave_ds}:')    
            print(wave_res)    

创建上面使用的示例文件的代码:

nbIncidence = 4
nbWavelength = 6
m, n = 10, 10 # m,n same as nbTheta, nbPhi??

with h5py.File('testFile.hdf5', 'w') as h5fw:
    for i_cnt in range(nbIncidence):
        grp = h5fw.create_group('Incidence_' + str(i_cnt))
        for w_cnt in range(nbWavelength):
            arr = np.random.uniform(low=-1.0, high=10.0, size=(m,n)) #.reshape(m,n)
            grp.create_dataset('Wavelength_' + str(w_cnt), data=arr)