在 pandas 中每月获取前 N 个项目

Get Top N items per month in pandas

我有以下数据框(与我原来的数据框相比,这是一个相当精简的样本)。

       year  month        id     revenue
80496  2020      2          16   536000.00
84222  2020      1        2758   430344.66
84223  2020      1        2758   679945.17
84224  2020      1        2758   543982.82
84225  2020      3        2758   287728.00
84226  2020      3        2758   321874.00
84227  2020      3        2758   408128.00
84230  2020      3        2758   458304.00
84231  2020      3        2758   332528.00
85309  2020      2        1560   277233.84
85312  2020      2        1560   419910.83
85876  2020      3        2890   333281.00
90690  2020      1        1304   306297.32
90691  2020      1        1304   391399.67
90698  2020      1        1304   314511.00
90699  2020      2        1304   598394.98
90701  2020      2        1304   391659.34
90702  2020      2        1304   420196.17
90703  2020      2        1304   390432.01
90705  2020      2        1304   485868.16
90706  2020      2        1304   340244.66
91066  2020      2        3738   426222.33
92039  2020      2        1273   269514.00
92040  2020      2        1273   399330.00
92043  2020      3        1273   845502.01
92044  2020      3        1273   285688.00
92045  2020      2        1304   471677.67
92053  2020      2        1304   306994.32
92055  2020      2        1304   514140.01
92058  2020      2        1304   670594.83
92059  2020      2        1304   313311.17
92060  2020      2        1304   264825.32
92061  2020      2        1304   417365.50
92063  2020      3        2758   460628.00
92064  2020      3        2758   270060.00
92074  2020      2        4354   626157.00
92075  2020      2        4354  1225539.99
92078  2020      3        2911   381026.67
92079  2020      3        2911   325471.67
92080  2020      3        2911   383008.33
92081  2020      3        2911   267538.66
92082  2020      3        2911   383789.17
92083  2020      3        2911   352452.50
92084  2020      3        2911   279040.84
92085  2020      3        2911   367950.82
92087  2020      2         130   284714.26
92088  2020      2         130   600318.97
92089  2020      2         130   270437.93
92091  2020      2         130   272350.83
92092  2020      2         130   346533.36
92093  2020      2         130   294939.32
92100  2020      2         134   303719.16
92101  2020      3         134   367001.67
92112  2020      3        1561   276828.00
92113  2020      3        1561   279312.01
92114  2020      3        1625   294794.50
92119  2020      3        1625   592332.50
92126  2020      2        2890   620486.67
92128  2020      3        2890   680190.00
92130  2020      3        2890   418707.33
92131  2020      3        2890   328754.99
92132  2020      3        2890   339958.00
92137  2020      3        2890   554962.00
92138  2020      3        2890   365953.34
92139  2020      3        2890   486639.16
92140  2020      3        2890  1610025.83
92141  2020      3        2890   589236.49

我正在尝试获取每年和每月的前 2 个 ID。因此,例如,我们的想法是获得以下 df。我在这里的主要问题是获取前 n 个以及日期,因为 nlargest 方法适用于 pd.Series 或数据框(但在这种情况下,您不能为多个条件传递列表) .

      year  month    id     revenue
0     2020      3  2890  6626149.47
1     2020      3  2758  4428253.33
691   2020      2  1304  6997646.32
692   2020      2   130  2229204.96
1785  2020      1  2758  1749250.49
1786  2020      1  1304  1581520.32

到目前为止,我的代码是:

df.groupby(by=['year', 'month', 'id'])[['revenue']].agg({'revenue': 'sum'}).sort_values(by=['year', 'month', 'revenue'], ascending=False).reset_index()

您可以使用 GroupBy.apply 为每个组调用一个函数(每个组都是一个单独的数据帧)。

top_two_per_year_month = df.groupby(['year', 'month'], as_index=False).apply(lambda x: x.sort_values('revenue', ascending=False)[0:2]).droplevel(0)

输出:

>>> top_two_per_year_month
       year  month    id     revenue
84223  2020      1  2758   679945.17
84224  2020      1  2758   543982.82
92075  2020      2  4354  1225539.99
92058  2020      2  1304   670594.83
92140  2020      3  2890  1610025.83
92043  2020      3  1273   845502.01

或者,使用 nlargest,正如@LarryTheLlama 建议的那样:

top_two_per_year_month = df.groupby(['year', 'month']).apply(lambda x: x['revenue'].nlargest(2))

输出:

>>> top_two_per_year_month
year  month       
2020  1      84223     679945.17
             84224     543982.82
      2      92075    1225539.99
             92058     670594.83
      3      92140    1610025.83
             92043     845502.01
Name: revenue, dtype: float64

>>> top_two_per_year_month.reset_index().rename({'level_2': 'id'}, axis=1)
   year  month     id     revenue
0  2020      1  84223   679945.17
1  2020      1  84224   543982.82
2  2020      2  92075  1225539.99
3  2020      2  92058   670594.83
4  2020      3  92140  1610025.83
5  2020      3  92043   845502.01

一种选择是在分组前对列进行排序,并使用nth函数:

(df.sort_values(['year', 'month','revenue', 'id'], 
                ascending=[True, True, False, False])
   .groupby(['year', 'month'], 
            as_index = False, 
            sort = False)
   .nth([0,1])
)

       year  month    id     revenue
84223  2020      1  2758   679945.17
84224  2020      1  2758   543982.82
92075  2020      2  4354  1225539.99
92058  2020      2  1304   670594.83
92140  2020      3  2890  1610025.83
92043  2020      3  1273   845502.01

你不需要申请,排序数据帧,groupby 然后使用 head:

df.sort_values(['year', 'month', 'revenue'], ascending=[True, True, False])\
  .groupby(['year', 'month']).head(2`)

输出:

       year  month    id     revenue
84223  2020      1  2758   679945.17
84224  2020      1  2758   543982.82
92075  2020      2  4354  1225539.99
92058  2020      2  1304   670594.83
92140  2020      3  2890  1610025.83
92043  2020      3  1273   845502.01