概要(groupbyは「カテゴリごとにまとめて計算」するための核機能)
pandas.groupbyは、列(カテゴリ)でデータをグループ化して、合計・平均・件数などの集計を一気に行う仕組みです。SQLのGROUP BYや、Excelのピボットテーブルの「集計」部分に相当します。初心者がまず覚えるのは「グループ化する列」「集計対象の列」「使う集計関数(sum/mean/countなど)」の3つ。さらに as_index、agg、transform、apply を押さえると、ほとんどの現場の集計が書けます。
基本の流れ(ここが重要)
1列でグループ化して単純集計
import pandas as pd
df = pd.DataFrame({
"city": ["Tokyo", "Osaka", "Tokyo", "Nagoya"],
"amount": [120, 150, 180, 90]
})
# 都市ごとの売上合計
g = df.groupby("city")["amount"].sum()
print(g)
Python「df.groupby(グループ化列)[集計列].集計関数()」が最短形。sum/mean/max/min/count/nunique などがよく使われます。
複数列でのグループ化と複数列の集計
df = pd.DataFrame({
"city": ["Tokyo","Tokyo","Osaka","Osaka","Nagoya"],
"item": ["A","B","A","B","A"],
"amount": [120, 180, 150, 200, 90],
"qty": [1, 2, 1, 3, 1]
})
# 都市×商品で、売上合計と数量平均
out = df.groupby(["city","item"]).agg({"amount": "sum", "qty": "mean"})
print(out)
Python複数列でグループ化すると「階層型インデックス」になります。後で扱いやすくするために reset_index を使うのが定石です。
結果を“ふつうの表”に戻す(as_index と reset_index)
# グループ化後も列として残す(インデックス化しない)
out = df.groupby("city", as_index=False)["amount"].sum()
print(out)
# すでにインデックスになっているなら戻す
g = df.groupby("city")["amount"].sum().reset_index()
print(g)
Pythonas_index=False か reset_index() を使うと、可視化や書き出しがスムーズになります。
集約・変換・適用(agg・transform・applyの使い分け)
agg(集約)で「列ごとに異なる関数」を一度に
# 名前付き集約(“named aggregation”)
out = df.groupby("city").agg(
total_amount=("amount", "sum"),
avg_amount=("amount", "mean"),
items=("item", "nunique")
)
print(out)
Pythonaggは「どの列にどの関数」を明示できて読みやすい。named aggregationは列名も一度に整えられます。
transform(元の行数を保った“グループ単位の値”)
# 各行に“その都市の平均売上”を付ける(行数は変わらない)
df["city_avg"] = df.groupby("city")["amount"].transform("mean")
print(df)
Pythontransformは「グループの特徴量を各行へ戻す」用途に最適。後続のスコアリングや標準化に向いています。
apply(柔軟だが重い。最終手段として)
def top_n(group, n=1):
return group.nlargest(n, "amount")
# 都市ごとに売上上位1件を抽出(戻りは部分DataFrame)
res = df.groupby("city").apply(top_n, n=1).reset_index(drop=True)
print(res)
Pythonapplyは「グループに任意の処理」を書ける反面、遅くなりがち。まずは agg/transform で書けないか検討するのが基本。
実務でよく使う集計と設計の勘所(数・ユニーク・並び・欠損)
count と size の違い(欠損をどう数えるか)
df = pd.DataFrame({"city": ["Tokyo","Tokyo","Osaka"], "amount": [120, None, 150]})
c1 = df.groupby("city")["amount"].count() # NaNを除いた件数
c2 = df.groupby("city").size() # 行の総件数(NaN含む)
print(c1, c2)
Python「列の欠損を除いて数えたい」なら count、「単純な行数」なら size。
並びを安定化(sort とソートキー)
# グループキーでソートしたい(デフォルトは並ぶ)
out = df.groupby("city", sort=True)["amount"].sum()
# 指標で並べ替えたいなら後段で sort_values
out = out.sort_values(ascending=False)
Python表示順を固定すると、レポートが安定します。
欠損・カテゴリの扱い(dropna・observed)
# グループキーにNaNがある行を除外(デフォルトTrue)
out = df.groupby("city", dropna=True)["amount"].sum()
# カテゴリ型の列で“実際に存在するカテゴリのみ”を出す
df["city"] = df["city"].astype("category")
out = df.groupby("city", observed=True)["amount"].sum()
Pythonカテゴリ型は observed=True を使うと「空のカテゴリ」を省けます。
groupby とピボットの対比(いつどちらを使うか)
groupbyのまま集計(縦軸=カテゴリ、横軸=指標)
out = df.groupby("city")["amount"].sum()
Pythonシンプルな「カテゴリ別指標」を出すなら groupby。
横に広げたいなら pivot_table(クロス集計)
pivot = df.pivot_table(index="city", columns="item", values="amount", aggfunc="sum", fill_value=0)
print(pivot)
Python「都市×商品」のような2軸に展開した表が欲しいなら pivot_table。fill_value で欠損を埋めると見やすい。
パフォーマンスと安全運用(型・列選択・段階化)
事前に型を決めておく(int/float/category)
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df["item"] = df["item"].astype("category")
Python数値は to_numeric、カテゴリは category へ固定。推定コストを減らし、メモリも節約できます。
必要な列だけでグループ化(余計な負荷を避ける)
# 集計対象の列だけ選んでから groupby
out = df[["city","amount"]].groupby("city")["amount"].sum()
Python列が多いと不要なメモリを消費します。「使う列だけ」を習慣化しましょう。
段階化して“作らず流す”(可読性も上がる)
g = df.groupby(["city","item"])["amount"]
out = g.sum().reset_index()
Python対象→集計→整形の順で、読みやすく安全に書けます。
例題で身につける(定番から一歩先まで)
例題1:都市別の件数・合計・平均を一括で
import pandas as pd
df = pd.DataFrame({
"city": ["Tokyo","Tokyo","Osaka","Nagoya","Tokyo"],
"amount": [100, 200, 150, 90, 180]
})
out = df.groupby("city").agg(
count=("amount", "count"),
total=("amount", "sum"),
avg=("amount", "mean"),
)
print(out)
Python例題2:都市×商品で合計、結果を表に戻す
df = pd.DataFrame({
"city": ["Tokyo","Tokyo","Osaka","Osaka","Nagoya"],
"item": ["A","B","A","B","A"],
"amount": [120, 180, 150, 200, 90],
})
out = df.groupby(["city","item"], as_index=False)["amount"].sum()
print(out) # city, item, amount のふつうの表
Python例題3:グループ平均を各行へ付与(transform)
df = pd.DataFrame({
"city": ["Tokyo","Tokyo","Osaka","Nagoya"],
"amount": [120, 180, 150, 90]
})
df["city_avg"] = df.groupby("city")["amount"].transform("mean")
df["deviation"] = df["amount"] - df["city_avg"]
print(df)
Python例題4:グループごとの上位1件を抽出(apply)
df = pd.DataFrame({
"city": ["Tokyo","Tokyo","Osaka","Osaka","Nagoya"],
"item": ["A","B","A","B","A"],
"amount": [120, 180, 150, 200, 90],
})
top1 = df.groupby("city").apply(lambda g: g.nlargest(1, "amount")).reset_index(drop=True)
print(top1)
Pythonまとめ
groupbyは「カテゴリでまとめて、指標を計算する」ための必須機能です。基本は「groupby→集計関数」で、結果を使いやすくするには as_index=False か reset_index。複数列・複数関数は agg(named aggregationが読みやすい)、各行へグループ特徴量を付けるなら transform、柔軟処理は apply(重いので最後の手段)。count と size の違い、sort・dropna・observedで見た目を整え、型を事前に固定して性能と安定性を確保。横展開が必要なら pivot_table。これらを型にすれば、初心者でも短く、正確で、実務品質の集計が書けます。
