我怎样才能提高这段代码的运行时间?

How could I improve the runtime of this code?

我想在两个数据帧之间共享一些信息。我的代码有效但需要很长时间。你知道我怎样才能改善我的 运行 时间吗?我正在尝试执行以下操作:

我有一个数据框 df1(它有 160 列,但这里只有显示的列很重要):

         a_idx  b_idx  c_idx  d_idx  e_idx  f_idx Evt_ID
    0    0      1      3      4      2      6     346642
    1    1      2      3      4      5      5     917426
    2    0      1      3      4      2      2     123543
                        ...
                        

还有一个数据框df2(ist有10列,但这里只有这些很重要):

    Name    Evt_ID
0   Jet1    346642
1   Jet2    346642
2   Jet3    346642
3   Jet4    346642
4   Jet5    346642
5   Jet6    346642
6   Jet7    346642
7   Lepton  346642
8   Jet1    917426
9   Jet2    917426
      ...

现在我想要在 df2 中创建一个名为“y”的新列,其中包含每行的类别。该类别可以在 df1 的帮助下找到,类别是: category_list = ["a", "b", "c", "d", "e", "f"]也可以是"unknown"。例如,df1 中的第一行具有值 category = [0,1,3,4,2,6],这意味着 df2 应如下所示:

(解释:第5数在category中是2 --> Jet(2+1) = Jet3 在 category_list 中有 第五个 类别:"e")

    Name    Evt_ID    y
0   Jet1    346642    a
1   Jet2    346642    b
2   Jet3    346642    e
3   Jet4    346642    c
4   Jet5    346642    d
5   Jet6    346642    unknown
6   Jet7    346642    f
7   Lepton  346642    unknown
     ...

我的实现方式如下:

df["y"] = "unknown"
category_list = ["a", "b", "c", "d", "e", "f"]

for event_id in tqdm(df1.Evt_ID):
    category = df1.loc[df1.Evt_ID == event_id, ["a_idx","b_idx",
                                               "c_idx", "d_idx", 
                                               "e_idx", "f_idx"]].values.squeeze()
    
    i = 0
    for jet_index in category:
        df2.loc[(dfo.Evt_ID == event_id) & (dfo.Name == "Jet".join(str(jet_index+1))), "y"] = category_list[i] 
        i += 1

这段代码 运行 需要 30 或 60 分钟,具体取决于它 运行 进入的 jupyter 笔记本。为什么笔记本本身会影响 运行 时间?但更重要的是:如何改善 运行时间?

由于其矢量化结构,以下代码段应该 运行 更快。

这里有两个技巧。第一个是使用 df.melt,它有效地将列 ab、...、e 转换为行。第二个是 join 使用 df2 生成的 DataFrame。这样,所有缺失值都变成 NaN 并且可以用 unknowndf.fillna.

替换
cols = ["a_idx", "b_idx", "c_idx", "d_idx", "e_idx", "f_idx"]
df = df1[cols + ["Evt_ID"]].rename(columns={c: c[0] for c in cols})

df = df.melt(id_vars="Evt_ID", var_name="y")
df["value"] = "Jet" + (df["value"] + 1).astype(str)

df = df2.join(df.set_index(["Evt_ID", "value"]), on=["Evt_ID", "Name"])
df = df.fillna("unknown")

最后,df 看起来像:

     Name  Evt_ID        y
0    Jet1  346642        a
1    Jet2  346642        b
2    Jet3  346642        e
3    Jet4  346642        c
4    Jet5  346642        d
5    Jet6  346642  unknown
6    Jet7  346642        f
7  Lepton  346642  unknown
8    Jet1  917426  unknown
9    Jet2  917426        a

此结果是使用以下示例数据获得的:

import pandas as pd


df1 = pd.DataFrame(
    [
        [0, 1, 3, 4, 2, 6, 346642],
        [1, 2, 3, 4, 5, 5, 917426],
        [0, 1, 3, 4, 2, 2, 123543],
    ],
    columns=["a_idx", "b_idx", "c_idx", "d_idx", "e_idx", "f_idx", "Evt_ID"],
)

df2 = pd.DataFrame(
    [
        ["Jet1", 346642],
        ["Jet2", 346642],
        ["Jet3", 346642],
        ["Jet4", 346642],
        ["Jet5", 346642],
        ["Jet6", 346642],
        ["Jet7", 346642],
        ["Lepton", 346642],
        ["Jet1", 917426],
        ["Jet2", 917426],
    ],
    columns=["Name", "Evt_ID"],
)