在使用输出.root文件的Geant4进行模拟时,我很高兴地发现了uproot包。
我相信数据帧是完成特定分析任务的最佳选择,所以我使用uproot.pandas.df()将TTree中的内容读取到这样的数据帧中。
不幸的是,这最终成为了一个瓶颈。虽然代码可以很好地处理所有数字输入,但处理字符串似乎是一个严重的问题。该文件非常大,生成的帧有2406703行。
而这段代码(Egamma和z_eu都是数字):
df = uproot.open('rootFile.root')['seco_tuple;1].pandas.df( ['Egamma','z_eu'])平均需要430ms,包括已经包含字符串的一列:
df = uproot.open('rootFile.root')['seco_tuple;1].pandas.df( ['Name','Egamma','z_eu'])将时间增加到几乎3.5秒。有第二列字符串会使时间加倍。我还尝试了读取字典中的数据,然后将其传递给数据帧。读取数据相当快,但将其传递到数据帧中,然后又相当慢。
由于字符串显然会导致代码占用更多的资源,我想知道字符串对于dataframes来说是不是一般的问题,或者这里的特定字符串类型是否会有所不同?
我希望在这里得到一些进一步的见解,并可以尝试提供.root文件以及MWE,如果需要的话。
提前感谢!
发布于 2019-11-20 00:01:19
部分问题是,用纯Python语言编写的uproot在性能上有很大的不同,NumPy可以非常快速地处理数值工作和任何涉及Python对象(如字符串)的工作。在某些情况下,例如this one,我们可以选择将字符串视为数字数组,这对性能有很大帮助。
另一部分是熊猫本身。因为NumPy只能处理直线型数组,所以NumPy的字符串效率很低,因为它们必须填充到一个共同的长度--数据集中最长字符串的长度。因此,Pandas选择了一种不同的低效方法:它通过一个dtype为object的NumPy数组将字符串作为Python对象(即指向Python对象的指针,而不是原始数字数据)。
>>> import pandas, numpy
>>> df = pandas.DataFrame({"column": ["one", "two", "three", "four", "five"]})
>>> df
column
0 one
1 two
2 three
3 four
4 five
>>> df.values
array([['one'],
['two'],
['three'],
['four'],
['five']], dtype=object)当字符串只是标签时,Pandas有一个“分类”dtype (不是NumPy的一部分!)它将每个不同的字符串替换为一个整数,因此它实际上是一个包含元数据的整数数组。
>>> df["column"].astype("category")
0 one
1 two
2 three
3 four
4 five
Name: column, dtype: category
Categories (5, object): [five, four, one, three, two]如果与字符串总数(不是上面的情况)相比,您的不同字符串数量较少,则速度更快,使用的内存也更少。如果每个字符串都是唯一的,这只会使数据膨胀。
也许uproot的DataFrame转换应该将一些字符串值分支读取到一个“分类”dtype中。这将需要用户显式地请求作为参数,因为它并不总是有帮助的。这样的东西会放在uproot._connect._pandas.futures2df函数中--如果有人愿意贡献一个PR的话,我会接受它的。
https://stackoverflow.com/questions/58937233
复制相似问题