如何优化groupby上的apply调用

时间:2018-01-16 02:31:52

标签: python python-3.x pandas apply

我有一个数据框,我想在逻辑下方应用,以获得对该组进行分析的第一行组。

def mark_wakeup_source(df):
    min_id = df['Astart'].idxmin()
    df.loc[min_id, ["Reason", "Count", "CSwitch", "Used"]] = [df.loc[min_id, "type"],
                                                             len(df.index),
                                                             len(df[df['type'] == "Process"]),
                                                             df["Aduration"].sum()]
    return df

以下是我调用apply函数并将其组合的方法。

df_t1 = df_t[df_t['type'] != 'Unknown'].copy()
df_t1['Reason'] = "None"
grouped = df_t1.groupby(["CPU", "index"])
df_t1 = grouped.apply(mark_wakeup_source)
df_t = df_t1.append(df_t[df_t['type'] == 'Unknown'])

我目前的数据中有29K +唯一组,处理时间约为140秒。我有比这个更大的数据,我需要优化它,并且没有线索如何去做。

我的数据在分组之前看起来像这样:

    CPU   State     Start      Stop pre_state next_state  index    Astart  \
0     4  Active  0.015417  0.056283        C1         C1      1  0.015429
1     4  Active  0.015417  0.056283        C1         C1      1  0.015437
18    5  Active  0.015492  0.015499        C1         C1      2  0.015495
14    4  Active  0.015417  0.056283        C1         C1      1  0.019524
20    1  Active  0.019921  0.020071        C3         C3      1  0.019938

   Astop          Name     type  Count  CSwitch  Used  Reason  Aduration
0   0.015437        System  Process      0        0     0     None   0.000008
1   0.032188       wpr.exe  Process      0        0     0     None   0.016751
18  0.015498        System  Process      0        0     0     None   0.000003
14  0.019727  ntoskrnl.exe      DPC      0        0     0     None   0.000203
20  0.020064        System  Process      0        0     0     None   0.000126

我尽可能减少了团体数量。 试过Numba,但这根本没有帮助。 基于我在代码下面尝试的许多其他答案,通过返回0而不是df,这需要〜180s:

def mark_wakeup_source(df, df_parent):
    df_len = len(df.index)
    min_id = df['Astart'].idxmin()
    df_parent.loc[min_id, ["Reason", "Count", "CSwitch", "Used"]] = 
                                                                 [df.loc[min_id, "type"],
                                                                 df_len,
                                                                 len(df[df['type'] == "Process"]),
                                                                 df["Aduration"].sum()]
    return 0

用尽线索,寻找一些建议以最佳方式完成。

2 个答案:

答案 0 :(得分:1)

从聚合函数字典开始。

f = {
       'Astart' : [('Reason', 'idxmin')], 
       'type' : [
                  ('Count', 'size'), 
                  ('CSwitch', lambda x: x.eq('Process').sum())
        ], 
       'Aduration' : [('Used', 'sum')]
}

接下来,query + groupby并将f传递给agg

v = df.query("type != 'Unknown'").groupby(['CPU', 'index']).agg(f)
v.columns = v.columns.droplevel(0)

v['Reason'] = df.loc[v['Reason'].values, 'type'].values

v

           Reason  Count  CSwitch      Used
CPU index                                  
1   1          20      1        1  0.000126
4   1           0      3        2  0.016962
5   2          18      1        1  0.000003

请注意,在此使用agg聚合数据的速度更快批次,因为它矢量化您的操作(这比类似循环的{{更快} { 1}}解决方案)。

答案 1 :(得分:1)

为了优化代码,我根据@ COLDSPEED的建议使用了:

df_min = grouped.agg({'Aduration': 'sum', 'type': 'count', 'Astart': 'min'}).reset_index()
df_min.rename(columns={'Aduration': "Used", 'type': 'Count', 'Astart': 'min'}, inplace=True)
df_with_proc = df_t1[df_t1['type'] == "Process"].groupby(["CPU", "index"]).agg({'type': 'count'}).reset_index()
df_with_proc.rename(columns={'type': 'CSwitch'}, inplace=True)
df_t1 = pd.merge(df_with_proc, df_t1, how="right", on=['CPU', 'index'])
df_t1 = pd.merge(df_min, df_t1, how="right", on=['CPU', 'index'])

这可以在同一数据帧上以0.2秒计算。