批量读取HDF5文件直接切片数据集无需转存的实现方法
多HDF5文件无落地合并切片实现方案
核心逻辑不需要生成持久化的合并文件,两种实现路径可按需选择,都能兼容原有切片、可视化代码逻辑。
方案1:内存直接拼接(推荐,数据量可放进内存时用)
逻辑最简单,和原有单文件读取的代码兼容性最高,全程只在内存中操作,不会生成任何中间文件:
- 用标准库
glob解析入参里的通配符,拿到所有匹配的HDF5文件路径 - 遍历所有文件,逐个读取
jets/truth_hadrons/hits三个数据集存入临时列表 - 用numpy沿第0维(样本维度)拼接所有数组,得到的合并对象和单文件读取得到的数组结构完全一致,原有切片逻辑不需要做任何修改
可直接复用的代码如下:
import glob import h5py import numpy as np # 解析通配符匹配所有目标文件 file_list = sorted(glob.glob(args.H5file)) if not file_list: raise RuntimeError(f"输入路径{args.H5file}未匹配到任何HDF5文件") jet_cache, had_cache, hit_cache = [], [], [] for file_path in file_list: with h5py.File(file_path, 'r') as df: print(f"读取文件:{file_path}\n文件包含键:{list(df.keys())}") # 和原有单文件读取逻辑完全一致 jet_cache.append(df['jets'][:]) had_cache.append(df['truth_hadrons'][:]) hit_cache.append(df['hits'][:]) # 拼接得到最终合并数据集 jetdset = np.concatenate(jet_cache, axis=0) haddset = np.concatenate(had_cache, axis=0) hitdset = np.concatenate(hit_cache, axis=0) # 后续直接复用原有切片、可视化代码即可
注意事项
- 所有匹配到的HDF5文件中,三个目标数据集除第一维(样本维)长度可不同外,其余维度尺寸、数据类型必须完全一致,否则拼接会报错,和提到的「所有文件数据格式一致」的前提匹配
- 脚本运行结束后内存中的数组会自动释放,不会残留任何持久化文件
方案2:虚拟数据集映射(大文件场景用)
如果总数据量太大无法全部加载进内存,可以用h5py原生的虚拟数据集功能,不需要把数据读入内存,也不需要生成合并文件,直接把多个文件的数据集映射为一个逻辑上的完整数据集,切片时才会按需读取对应位置的数据:
import glob import h5py import numpy as np file_list = sorted(glob.glob(args.H5file)) if not file_list: raise RuntimeError(f"输入路径{args.H5file}未匹配到任何HDF5文件") # 读取第一个文件获取数据集基础结构 with h5py.File(file_list[0], 'r') as f: jet_base_shape = f['jets'].shape[1:] had_base_shape = f['truth_hadrons'].shape[1:] hit_base_shape = f['hits'].shape[1:] jet_dtype = f['jets'].dtype had_dtype = f['truth_hadrons'].dtype hit_dtype = f['hits'].dtype # 遍历所有文件生成虚拟源 jet_sources, had_sources, hit_sources = [], [], [] total_jet_num = total_had_num = total_hit_num = 0 for fp in file_list: with h5py.File(fp, 'r') as f: jet_n = f['jets'].shape[0] had_n = f['truth_hadrons'].shape[0] hit_n = f['hits'].shape[0] jet_sources.append(h5py.VirtualSource(fp, 'jets', shape=(jet_n, *jet_base_shape), dtype=jet_dtype)) had_sources.append(h5py.VirtualSource(fp, 'truth_hadrons', shape=(had_n, *had_base_shape), dtype=had_dtype)) hit_sources.append(h5py.VirtualSource(fp, 'hits', shape=(hit_n, *hit_base_shape), dtype=hit_dtype)) total_jet_num += jet_n total_had_num += had_n total_hit_num += hit_n # 组装虚拟布局 jet_layout = h5py.VirtualLayout(shape=(total_jet_num, *jet_base_shape), dtype=jet_dtype) had_layout = h5py.VirtualLayout(shape=(total_had_num, *had_base_shape), dtype=had_dtype) hit_layout = h5py.VirtualLayout(shape=(total_hit_num, *hit_base_shape), dtype=hit_dtype) jet_offset = had_offset = hit_offset = 0 for src in jet_sources: n = src.shape[0] jet_layout[jet_offset:jet_offset+n] = src jet_offset += n for src in had_sources: n = src.shape[0] had_layout[had_offset:had_offset+n] = src had_offset += n for src in hit_sources: n = src.shape[0] hit_layout[hit_offset:hit_offset+n] = src hit_offset += n # 虚拟数据集支持和普通numpy数组几乎一致的切片语法,按需切片即可,不要直接用[:]拉取全量数据 # 示例:取前100个jet样本:jet_sample = jet_layout[:100]
内容的提问来源于stack exchange,提问作者physicscitizen
相关产品推荐
相关产品推荐

