HOWTO · Pandas
計數 Pandas 中每組的唯一值
通過使用 Pandas 庫中的 df.groupby().nunique(),df.groupby().agg()和 df.groupby().unique()方法對 DataFrame 中的列進行分組來對值進行計數
本頁內容
分析 DataFrame 時,你經常需要知道每個分組內有多少個唯一值,而不是整個欄位中的唯一值總數。例如,資料集可能記錄 Countries 中各個國家使用的 code 值,而你想取得每個國家一筆計數。pandas 的 groupby() 操作為這項任務提供三種實用工具:
df.groupby().nunique()回傳每個分組中唯一值的數量。df.groupby().agg()透過通用彙總介面套用相同的計數。df.groupby().unique()列出每個分組的唯一值本身。
以下所有範例都使用同一個 DataFrame,由九列國家與代碼配對組成。
執行這個範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import pandas as pd
data = [
[999, "Switzerland"],
[113, "Switzerland"],
[112, "Japan"],
[112, "Switzerland"],
[113, "Canada"],
[114, "Japan"],
[100, "Germany"],
[114, "Japan"],
[115, "Germany"],
]
df = pd.DataFrame(data, columns=["code", "Countries"])
print(df)
code Countries
0 999 Switzerland
1 113 Switzerland
2 112 Japan
3 112 Switzerland
4 113 Canada
5 114 Japan
6 100 Germany
7 114 Japan
8 115 Germany
使用 GroupBy.nunique() 計算唯一值數量
計算每個分組中唯一值數量最直接的方法是 nunique()。在 groupby() 之後選取 code 欄位,會將已分組物件轉換為已分組的 Series,因此 nunique() 會計算每個國家各列中的不同代碼數量。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import pandas as pd
data = [
[999, "Switzerland"],
[113, "Switzerland"],
[112, "Japan"],
[112, "Switzerland"],
[113, "Canada"],
[114, "Japan"],
[100, "Germany"],
[114, "Japan"],
[115, "Germany"],
]
df = pd.DataFrame(data, columns=["code", "Countries"])
result = df.groupby("Countries")["code"].nunique()
print(result)
Countries
Canada 1
Germany 2
Japan 2
Switzerland 3
Name: code, dtype: int64
結果是一個 Series,其索引保存分組名稱,其值保存計數:瑞士使用三個不同的代碼,德國和日本各使用兩個,加拿大使用一個。由於分組鍵已成為索引,如果想取得不含分組索引的兩欄 DataFrame,請呼叫 reset_index(),或使用下一節的 agg() 形式。預設情況下,nunique() 不會計算遺漏(NaN)項目;如果遺漏值應計為一個不同的值,請傳入 dropna=False。
使用 GroupBy.agg() 計算唯一值數量
agg() 是分組物件的通用彙總方法。將 nunique() 作為彙總函式傳入,可透過 DataFrame.aggregate() 介面產生相同的計數,並能更精細地控制結果的形狀。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import pandas as pd
data = [
[999, "Switzerland"],
[113, "Switzerland"],
[112, "Japan"],
[112, "Switzerland"],
[113, "Canada"],
[114, "Japan"],
[100, "Germany"],
[114, "Japan"],
[115, "Germany"],
]
df = pd.DataFrame(data, columns=["code", "Countries"])
result = df.groupby(by="Countries", as_index=False).agg({"code": pd.Series.nunique})
print(result)
Countries code
0 Canada 1
1 Germany 2
2 Japan 2
3 Switzerland 3
字典 {"code": pd.Series.nunique} 告訴 agg() 要彙總哪個欄位以及套用哪個函式;pd.Series.nunique 與上一節直接呼叫的操作相同,而以字串傳入其名稱——agg({"code": "nunique"})——效果也完全相同。as_index=False 引數會將國家名稱保留為一般欄位,而不是移入索引,這就是 result 成為不含分組索引的 DataFrame,而不是以分組為索引的 Series 的原因。當你想要 DataFrame 結果,或唯一值計數只是單次操作中要計算的多個彙總之一時,請選用這種形式。
使用 GroupBy["code"].unique() 列出唯一值
計數回答的是「有多少」,但有時你需要知道每個國家使用的是哪些代碼。將 unique() 套用於分組後的 Series,會回傳唯一值本身。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
import pandas as pd
data = [
[999, "Switzerland"],
[113, "Switzerland"],
[112, "Japan"],
[112, "Switzerland"],
[113, "Canada"],
[114, "Japan"],
[100, "Germany"],
[114, "Japan"],
[115, "Germany"],
]
df = pd.DataFrame(data, columns=["code", "Countries"])
result = df.groupby("Countries")["code"].unique()
print(result)
Countries
Canada [113]
Germany [100, 115]
Japan [112, 114]
Switzerland [999, 113, 112]
Name: code, dtype: object
結果中的每一項都是一個陣列,包含該國家出現過的不同 code 值,並依出現順序排列——瑞士的陣列確認了先前計算的三個代碼:999、113 和 112。由於每個元素都是陣列而非單一數字,Series 的 dtype 為 object。值得注意的一個行為差異是:unique() 會在回傳的陣列中包含 NaN,而 nunique() 預設會略過遺漏值。
選擇計數或列出值
當問題著重於數量(例如「每個國家使用多少個唯一代碼?」)時,請選擇 nunique()。它會回傳數值計數,方便你排序、篩選或合併回原始資料列。若要將每列所屬分組的計數附加為新欄位,請使用 df.groupby("Countries")["code"].transform("nunique"),它會將各分組計數廣播到每一列。
當重要的是值本身——例如稽核哪些代碼在多個國家之間共用,或將值清單交給後續處理步驟——時,請選擇 unique()。如果你已經有 unique() 的結果並需要其長度,result.apply(len) 會重現 nunique() 原本會產生的相同計數。
最後,當唯一值計數只是更大範圍彙總的一部分時,請使用 agg(),例如 agg({"code": "nunique", "price": "sum"}) 會在單次操作中計算每個分組的多項統計量。簡言之:要計數就用 nunique(),要取得值就用 unique();需要 DataFrame 結果,或想把計數與其他彙總合併時,則使用 agg()。