由于 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
,它派生自pt
和eta
。
>>> # 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)
它们是字符串。它们不再是可计算的。因此,如果要保存到文件,请将其分解为组件。
也许所有这些都可以整合到一个可用的系统中,但是有些方面,比如保存这些阵列的“洛伦兹性”完好无损,还没有准备好。