使用uproot.daskframes从许多ROOT文件创建daskframe时,如何避免出现“打开文件过多”错误

时间:2020-02-12 13:26:12

标签: physics dask uproot awkward-array

我想尝试使用uproot将带有平面ROOT NTupels的许多根文件读取到桌面框架中。 214个文件,每个500kb,大约8000行,每个16列/变量。它们很容易放入内存中的pandas数据帧中,但是由于我希望将来会有更大的数据集,所以我尝试学习dask(并且是root,以前仅与root_pandas一起使用)。

因此,我认为uproot.daskframes(list_of_paths, flatten=True)是将文件读取到桌面框架的工具。很好地创建框架,但是在以下Too many open files错误中进行计算:https://pastebin.com/mfHgB16Q。 当我将文件限制为例如100个时,它可以进行计算,但是速度很慢(30秒),对几个文件来说,这没问题。当我使用100个文件并增加篮子容量(例如100Mb)来提高速度时,我得到了RecursionErrorhttps://pastebin.com/xTHa1Wav

我自己的解决方案是只创建连根拔起的普通熊猫数据帧,延迟创建并使用dask来创建它们的连接,这对我来说效果很好,并且比uproot.daskframes的计算速度更快。文件。

import uproot
from dask import delayed
import dask.dataframe as dd

def daskframe_from_rootfiles(path_list, treepath, branches=None):
    @delayed
    def get_df(file, treepath=None, branches=None):
        tree = uproot.open(file)[treepath]
        return tree.pandas.df(branches=branches)

    dfs = [get_df(path, treepath, branches=branches) for path in path_list]
    daskframe = dd.from_delayed(dfs)
    return daskframe

延迟数据帧创建的优点是我可以使用dask对其进行并行化。

但是我觉得应该有一些规范的方法,可能是我所缺少的东西,也许我应该为daskframes函数使用其他选项,或者也许我应该完全使用其他函数来做到这一点。您能为我提供任何想法或最佳做法吗?

2 个答案:

答案 0 :(得分:1)

吉姆·皮瓦尔斯基(Jim Pivarski)的comment证实我的方法是可以的,这并不是我做的完全错误的事情。由于他是开发人员,所以我不希望得到更复杂的答案,因此我将其标记为“无效”。

编辑:直到两天后我才能将自己的答案标记为解决方案,因此我将等到那时或其他人发布答案。

答案 1 :(得分:1)

    @delayed
    def get_df(file, treepath=None, branches=None):
        tree = uproot.open(file)[treepath]
        return tree.pandas.df(branches=branches)

我的猜测是此函数将留下一个打开的文件句柄。也许打开后有某种关闭文件的方法?

    @delayed
    def get_df(filename, treepath=None, branches=None):
        file = uproot.open(filename)
        tree = file[treepath]
        df = tree.pandas.df(branches=branches)
        file.close()  # does something like this exist?
        return df