请注意,每次对uproot.open(...)
和file [key]
的调用都使用纯Python(uproot最慢的部分)加载TFile和TTree元数据。如果多次调用此方法,请尝试保留TFile和/或TTree对象并重新使用它们。
另外,看来您的dropAndKeep
函数只是删除行(事件),但是如果我读错了并且它在做列(分支),则使用uproot的branches
参数数组读取功能仅发送所需的分支。由于ROOT文件中的数据是按列排列的,因此您无法避免读取不需要的事件-您必须在事实发生之后(在任何框架中)将其剪切掉。
接下来,请注意,对于简单的操作(如过滤事件),Pandas比NumPy慢得多。如果要加快速度,请使用TTree.arrays
而不是TTree.pandas.df
获取数组,构造一个NumPy布尔数组供您选择,然后将其应用于{{1} }返回。然后,您可以使用Pandas的DataFrame构造函数将它们全部放入DataFrame中(如果您真的需要Pandas的话)。
的确,您不需要通过HDF5,也不需要通过Pandas。您的机器学习框架(TensorFlow?Torch?)几乎可以肯定有一个接口,该接口可以接受零拷贝(或到GPU的一个拷贝)的NumPy数组。强调HDF5或Pandas的教程之所以这样做,是因为对于大多数用户(非HEP)来说,这些是最方便的界面。他们的数据可能已经在HDF5或Pandas中了;我们的数据可能在ROOT中。
如果您的机器学习将在GPU上进行,也许您也希望在GPU上进行事件选择。 CuPy是一个NumPy克隆,它完全在GPU上分配和运行,并且您的TensorFlow / Torch张量可能与CuPy数组具有零拷贝接口。原则上,如果将CuPy数组用作asarray interpretation的目标,则uproot应该能够直接从ROOT文件写入CuPy数组。不过,我还没有尝试过。
如果您可以控制要处理的ROOT文件,请尝试使它们的存储篮变大(增加刷新大小),并简化其数据结构(例如,纯数字或数字的数组/向量,再不深入)。也许最重要的是,使用像lz4这样的轻量级压缩,而不是使用重量级的Luke lzma。
Uproot可以并行读取篮子,但这仅在它需要执行许多非Python计算(例如对lzma进行解压缩)时才有用。
如果要一遍又一遍地读取这些数组,则可能要使用numpy.save写入中间文件,该文件实际上只是磁盘上的原始字节。这意味着回读时没有反序列化,这与解码ROOT或HDF5文件所需的工作相反。因为它是一种简单的格式,所以您甚至可以使用numpy.memmap来读回它,因为它会从磁盘延迟加载数据,从而偷看操作系统的页面缓存,甚至删除字节的显式副本。
并非所有这些技巧都将同样有用。我尝试将最重要的代码放在首位,但是在进行大型代码重写之前进行了实验,可能并没有太大的不同。有些技巧无法与其他技巧结合使用,例如CuPy和memmap(memmap总是延迟加载到主内存中,而不是GPU内存中)。但是某些组合可能会富有成果。
祝你好运!
,
我的另一个观点。我在连根拔起-> hdf5营地;这样,我可以做一次较慢的部分(将文件读入hdf5),并合并较小的文件并进行一些处理。我还保持压缩较低或关闭。这可能需要4到5分钟的连根读取许多文件,然后将其读取到
我要补充的一点是,如果您有“锯齿状”的数据(例如真相信息),则可以直接使用AwkwardArray(对hdf5具有本机支持)来很好地工作。我使用h5py处理HDF5文件。您可以在这里查看我的工作:https://gitlab.cern.ch/LHCb-Reco-Dev/pv-finder。
以前也以这种方式进行设计,因为我没有一个可以同时在其中使用ROOT和ML工具在任何地方运行的环境,但是现在我使用Conda使用了单个environment.yml文件-forge ROOT和ML工具(PyTorch等)。
,
每个人都忘记了明显的成分:RDataFrame.AsNumpy()
,例如https://root.cern.ch/doc/master/df026__AsNumpyArrays_8py.html
这样,就不需要临时文件,也不需要将所有内容加载到内存中。阅读以本机C ++速度进行。很高兴看到关于https://root-forum.cern.ch上效果更好的报告!
,
Jim似乎对选项提供了很好的概述,所以我将提供一种专门的策略:
由于您似乎正在执行“预选择”步骤,所以我认为您可以从以NumPy,HDF5或Parquet格式保存中间文件中受益。这样,您避免了每次在磁盘上处理数据时都重复选择计算(将这些格式加载到NumPy或pandas中与保存它们一样简单)。因此,我的建议是一次加载ROOT风格的数据(并且仅读取您感兴趣的分支),执行预选择步骤,并保存中间文件以备后用。我会举一个更具体的例子:
我的工作流程包括三个选择。我们可以将它们表示为pandas.DataFrame.eval / pandas.DataFrame.query字符串。 (如果可用,numexpr
会加速pandas.eval)。这些类似于TTree::Draw
选择。这是一个任意示例,其中我的树上有[electron_pt,regionA,regionB,regionC]
列。
selectA = "(electron_pt >= 25) & (regionA == True)"
selectB = "(electron_pt >= 30) & (regionB == True)"
selectC = "(electron_pt >= 35) & (regionC == True)"
我可以一次将数据加载到数据框中并应用选择:
keep_columns = [......] # some list of branches to keep,must contain selection branches
df = uproot.open("file.root").get("tree").pandas.df(branches=keep_columns)
selections = {
"A": selectA,"B": selectB,"C": selectC
}
现在我们可以遍历选择,查询数据框,并保存仅包含特定选择的中间格式。
for name,selection in selections.items():
df.query(selection).to_hdf("file_selection{}.h5".format(name),name)
# or save to parquet (if pyarrow is installed):
# df.query(selection).to_parquet("file_section{}.parquet".format(name))
然后使用pandas.read_hdf
或pandas.read_parquet
将文件读回到内存中。
过去,当我针对来自共同来源的数据训练ML分类器时,这种策略对我来说非常有效,但是需要将其分类为几个不同的选择。
本文链接:https://www.f2er.com/3117912.html