Python | ファイル・OS 操作:pandas.groupby

Python Python
スポンサーリンク
  1. 概要(groupbyは「カテゴリごとにまとめて計算」するための核機能)
  2. 基本の流れ(ここが重要)
    1. 1列でグループ化して単純集計
    2. 複数列でのグループ化と複数列の集計
    3. 結果を“ふつうの表”に戻す(as_index と reset_index)
  3. 集約・変換・適用(agg・transform・applyの使い分け)
    1. agg(集約)で「列ごとに異なる関数」を一度に
    2. transform(元の行数を保った“グループ単位の値”)
    3. apply(柔軟だが重い。最終手段として)
  4. 実務でよく使う集計と設計の勘所(数・ユニーク・並び・欠損)
    1. count と size の違い(欠損をどう数えるか)
    2. 並びを安定化(sort とソートキー)
    3. 欠損・カテゴリの扱い(dropna・observed)
  5. groupby とピボットの対比(いつどちらを使うか)
    1. groupbyのまま集計(縦軸=カテゴリ、横軸=指標)
    2. 横に広げたいなら pivot_table(クロス集計)
  6. パフォーマンスと安全運用(型・列選択・段階化)
    1. 事前に型を決めておく(int/float/category)
    2. 必要な列だけでグループ化(余計な負荷を避ける)
    3. 段階化して“作らず流す”(可読性も上がる)
  7. 例題で身につける(定番から一歩先まで)
    1. 例題1:都市別の件数・合計・平均を一括で
    2. 例題2:都市×商品で合計、結果を表に戻す
    3. 例題3:グループ平均を各行へ付与(transform)
    4. 例題4:グループごとの上位1件を抽出(apply)
  8. まとめ

概要(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)
Python

as_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)
Python

aggは「どの列にどの関数」を明示できて読みやすい。named aggregationは列名も一度に整えられます。

transform(元の行数を保った“グループ単位の値”)

# 各行に“その都市の平均売上”を付ける(行数は変わらない)
df["city_avg"] = df.groupby("city")["amount"].transform("mean")
print(df)
Python

transformは「グループの特徴量を各行へ戻す」用途に最適。後続のスコアリングや標準化に向いています。

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)
Python

applyは「グループに任意の処理」を書ける反面、遅くなりがち。まずは 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。これらを型にすれば、初心者でも短く、正確で、実務品質の集計が書けます。

タイトルとURLをコピーしました