pandas 取 groupby 後每個分組的前 N 行

原始數據如下:

(圖是從 excel 截的,最左1行不是數據,是 excel 自帶的行號,為了方便說明截進來的)

除去首行是標題外,有效數據為 28行 x 4列

目前的需求是根據 partition 分組,然後取每組的前 2 行,如果不考慮排序,程式碼如下:
(把head()裡面的數字改成 n 就可以取 n 行)

import pandas as pd

esp_df = pd.read_excel('excel文件路徑', sheet_name='Sheet名')
esp_df.groupby(['partition', 'create_time', 'last_modified_time']).mean().reset_index(drop=False).groupby('partition').head(2)

結果如下:

分別說明如下:

  • groupby:分組,這裡是根據數據中的 3 列來一起分組,因為我們並不需要做聚合運算,所以這麼取可以保留原始數據不變。原始數據只有 4 列,這裡 groupby 了 3 列,只剩下 size(其實把 size 放進去一起 groupby 也沒問題)
  • mean:求平均值,但是在這裡沒用,因為上一步的 groupby 取了前面的 3 列,在本例中,前 3 列並在一起就能得到一個唯一的一行,所以這裡其實也只是每一行數據自己求平均數,結果等於它本身。同理,這裡替代成求和函數 sum() 也是一樣的。但是不能省略,因為**省略後它就是一個 DataFrameGroupBy 類型的變數,不是 DataFrame,而 DataFrameGroupBy 是沒有後面的 reset_index 方法的
  • reset_index:重置索引,groupby 之後,結果集的索引就變成了 groupby 裡面的 key,這個 reset_index 把這個索引重新退回為數據。
    舉例說明,在應用 reset_index 之前,即使用 mean() 之後的數據是這樣的:

可以看到左邊的 3 列,也就是 groupby key 的 partition、create_time、last_modified_time 是加粗了的,說明此時這 3 列都是索引;而且 partition 因為有相同的行,還被合併了。顯然這不是我們想要的。reset_index 把它們重新放回到數據列里

參數中的 drop 作用是是否保留(重置前)的索引
數據就又回來了,索引變成了原來默認的(0123…)

  • groupby:再次根據 partition 分組
  • head: 取每個分組的前 n 行

如果要排序

本例中,如果要先根據 partition 分組,然後再根據 size 倒序(從大到小)再取前 2 行,則程式碼如下:

esp_df.groupby(['partition']).apply(lambda x: x.sort_values(["size"], ascending = False)).reset_index(drop=True).groupby('partition').head(2)

結果如下: