1

我想知道将 TLorentzVector 信息从 .root 文件转换为 Pandas DataFrames 的推荐协议。到目前为止,我的策略是为我关心的每个粒子保存 pT、eta 和 phi 信息。然后我编写自己的函数(基于 TLorentzVector 定义)来计算我偶尔可能需要的任何其他量,例如 DeltaR、mT 等。

然后我想知道我是否可以只将 TLorentzVector 保存到我的 DataFrame 并使用 uproot 使用类似这样的东西即时获取 pT、eta、phi 等数量(当我在 DataFrame 上运行时有效我刚刚从 .root 文件转换):

for row in df.index:
    print(df.at[row,"leptons_p4_0"].pt)

不过,我很快意识到,仅 Pandas 并不了解 TLorentzVector 是什么,所以当我稍后使用pd.read_csv.

那么,我的问题是,其他人如何建议我将 TLorentzVector 信息保存在稍后将在 pandas 中打开的 DataFrame 中,而不是连根拔起?似乎我的选择是为每个粒子保存(pT,eta,phi)列,然后编写我自己的函数,或者保存 TLorentzVector 组件(E,px,py,pz)并用于uproot_methods将这些组件转换回每次我重新加载 DataFrame 时都会出现一个 TLorentzVector。或者,希望还有另一个我还没有遇到过的更简单的解决方案!

非常感谢您的任何建议。

4

1 回答 1

1

由于 Pandas 没有任何处理洛伦兹向量的工具,因此用它们的分量(pT、eta、phi、质量)来表达它们并编写自己的函数来转换它们是唯一的方法,特别是如果你想保存往返 CSV。

也就是说,可以创建在 Pandas 内部保留其“洛伦兹性”的洛伦兹矢量对象,但存在局限性。您可以将结构化数据创建为Awkward Arrays

>>> import awkward1 as ak
>>> import pandas as pd
>>> import numpy as np
>>> class Lorentz:
...     @property
...     def p(self):
...         return self.pt * np.cosh(self.eta)
... 
>>> class LorentzRecord(Lorentz, ak.Record): pass
... 
>>> class LorentzArray(Lorentz, ak.Array): pass
... 
>>> ak.behavior["lorentz"] = LorentzRecord
>>> ak.behavior["*", "lorentz"] = LorentzArray
>>> array = ak.Array([{"pt": 1.1, "eta": 2.2},
...                   {"pt": 3.3, "eta": 4.4},
...                   {"pt": 5.5, "eta": -2.2}],
...                  with_name="lorentz")
>>> array
<LorentzArray [{pt: 1.1, eta: 2.2}, ... eta: -2.2}] type='3 * lorentz["pt": floa...'>

上面定义了一个array带有字段pt和的记录,eta并给单记录和记录数组视图一个新的属性p,它派生自pteta

>>> # Each record has a pt, eta, and p.
>>> array[0].pt
1.1
>>> array[0].eta
2.2
>>> array[0].p
5.024699161788051
>>> # The whole array has a pt, eta, and p (columns).
>>> array.pt
<Array [1.1, 3.3, 5.5] type='3 * float64'>
>>> array.eta
<Array [2.2, 4.4, -2.2] type='3 * float64'>
>>> array.p
<Array [5.02, 134, 25.1] type='3 * float64'>

您可以将一组 Lorentz 记录放入 Pandas DataFrame 中:

>>> df = pd.DataFrame({"column": array})
>>> df
                 column
0   {pt: 1.1, eta: 2.2}
1   {pt: 3.3, eta: 4.4}
2  {pt: 5.5, eta: -2.2}

并用它做同样的事情:

>>> df.column.values.pt
<Array [1.1, 3.3, 5.5] type='3 * float64'>
>>> df.column.values.eta
<Array [2.2, 4.4, -2.2] type='3 * float64'>
>>> df.column.values.p
<Array [5.02, 134, 25.1] type='3 * float64'>

但那是因为我们将 Awkward Array 拉回以应用这些操作。

>>> df.column.values
<LorentzArray [{pt: 1.1, eta: 2.2}, ... eta: -2.2}] type='3 * lorentz["pt": floa...'>

应用于 DataFrame 的任何 NumPy 函数,例如否定(隐式调用np.negative),无需解包即可传递到 Awkward Array。

>>> -df
                  column
0  {pt: -1.1, eta: -2.2}
1  {pt: -3.3, eta: -4.4}
2   {pt: -5.5, eta: 2.2}

但目前,这是错误的操作:它不应该否定pt. 有可能进一步超载

>>> def negative_Lorentz(x):
...     return ak.zip({"pt": x.pt, "eta": -x.eta})
... 
>>> ak.behavior[np.negative, "lorentz"] = negative_Lorentz
>>> -df
                 column
0  {pt: 1.1, eta: -2.2}
1  {pt: 3.3, eta: -4.4}
2   {pt: 5.5, eta: 2.2}

我们仍在为 Lorentz 数组构建一套函数,但现在它们在 Pandas 运行的一次数组模式下工作。有一个名为vector的项目可以为 2D、3D 和Lorentz 向量,但它处于开发的早期阶段。

回到保存的问题——以上所有内容都对您没有帮助,因为 Pandas 通过打印这些数据来“保存”这些数据:

>>> df.to_csv("whatever.csv")

,column
0,"{pt: 1.1, eta: 2.2}"
1,"{pt: 3.3, eta: 4.4}"
2,"{pt: 5.5, eta: -2.2}"

这不是可以读回的东西。我们可以试试

>>> df2 = pd.read_csv("whatever.csv")
>>> df2
   Unnamed: 0                column
0           0   {pt: 1.1, eta: 2.2}
1           1   {pt: 3.3, eta: 4.4}
2           2  {pt: 5.5, eta: -2.2}
>>> df2.column.values
array(['{pt: 1.1, eta: 2.2}', '{pt: 3.3, eta: 4.4}',
       '{pt: 5.5, eta: -2.2}'], dtype=object)

到目前为止,它看起来不错,但并不好:

>>> df2.column.values
array(['{pt: 1.1, eta: 2.2}', '{pt: 3.3, eta: 4.4}',
       '{pt: 5.5, eta: -2.2}'], dtype=object)

它们是字符串。它们不再是可计算的。因此,如果要保存到文件,请将其分解为组件。

也许所有这些都可以整合到一个可用的系统中,但是有些方面,比如保存这些阵列的“洛伦兹性”完好无损,还没有准备好。

于 2020-05-20T01:07:46.417 回答