【Pandas】groupbyでデータをグループ化・集計する

Pandas

こんにちは、かつコーチです。
「商品カテゴリごとの売上合計を出したい」「店舗ごとの平均客単価を知りたい」といった集計作業で必ず使うのがgroupbyです。
Excelでいうピボットテーブルに近い機能で、覚えると分析の幅がぐっと広がります。

groupbyとは?

groupbyの定義:グループ化して集計する仕組み

groupbyとは、指定した列の値でデータをグループ分けし、グループごとに合計・平均などの集計を行うためのメソッドです。

import pandas as pd

df = pd.DataFrame({
    "店舗": ["東京", "東京", "大阪", "大阪", "福岡"],
    "売上": [1000, 1500, 800, 1200, 600]
})

result = df.groupby("店舗")["売上"].sum()
print(result)
店舗
東京    2500
大阪    2000
福岡     600
Name: 売上, dtype: int64

「店舗」ごとにグループ分けし、それぞれの「売上」を合計しています。

なぜgroupbyが重要なのか

実務のデータ分析では、「全体の合計」よりも「カテゴリ別・期間別の内訳」を知りたい場面が圧倒的に多いです。
groupbyを使いこなせるようになると、「Aという条件で絞り込んで合計」「Bという条件で絞り込んで合計」といった作業を繰り返す必要がなくなり、1行で全グループの集計結果をまとめて得られます。

基本の書き方:groupbyの使い方

手順1:単一列でグループ化して集計する

import pandas as pd

df = pd.DataFrame({
    "店舗": ["東京", "東京", "大阪", "大阪", "福岡"],
    "商品": ["A", "B", "A", "B", "A"],
    "売上": [1000, 1500, 800, 1200, 600]
})

# 店舗ごとの合計
print(df.groupby("店舗")["売上"].sum())

# 店舗ごとの平均
print(df.groupby("店舗")["売上"].mean())

# 店舗ごとの件数
print(df.groupby("店舗")["売上"].count())

手順2:複数列でグループ化する

「店舗」と「商品」の組み合わせごとに集計したい場合は、列名をリストで渡します。

result = df.groupby(["店舗", "商品"])["売上"].sum()
print(result)
店舗  商品
大阪  A       800
    B      1200
東京  A      1000
    B      1500
福岡  A       600
Name: 売上, dtype: int64

手順3:複数の集計を同時に行う(agg)

合計と平均を同時に見たい場合は、aggメソッドを使います。

result = df.groupby("店舗")["売上"].agg(["sum", "mean", "count"])
print(result)
     sum         mean  count
店舗
大阪  2000  1000.000000      2
東京  2500  1250.000000      2
福岡   600   600.000000      1

手順4:グループ化した結果をDataFrameのまま扱う

reset_index()をつけると、集計結果を通常の列を持つDataFrameとして扱えるようになります。

result = df.groupby("店舗")["売上"].sum().reset_index()
print(result)
   店舗    売上
0  大阪  2000
1  東京  2500
2  福岡   600

その後グラフ作成や別データとの結合を行う場合は、このreset_index()をつけておくと扱いやすくなります。

つまずきやすい設定・注意点

  • groupbyだけを実行した戻り値はDataFrameGroupByという特殊なオブジェクトで、そのままprintしても中身は表示されません。集計メソッド(summeanなど)を続けて呼び出す必要があります
  • グループ化する列に欠損値(NaN)がある行は、デフォルトでは集計対象から除外されます

よくあるつまずきポイント・エラー対処

集計結果に文字列列が混ざってエラーになる

❌Before:数値以外の列を含んだままsum()を呼び出してしまう

df = pd.DataFrame({
    "店舗": ["東京", "東京", "大阪"],
    "担当者": ["田中", "佐藤", "鈴木"],
    "売上": [1000, 1500, 800]
})

result = df.groupby("店舗").sum()

pandas 2.x系では、文字列列(担当者)が混ざっていると以下のようなエラーになることがあります。

TypeError: agg function failed [how->sum,dtype->object]

私が実際にこのエラーに遭遇したときは、「なぜ数値列だけの集計でエラーになるのか」が最初は理解できませんでした。
原因は、DataFrame全体にsum()をかけたことで、文字列列である「担当者」まで一緒に集計しようとしていたためです。
pandas 1.x系では文字列列を自動的に無視してくれる挙動でしたが、2.x系では明示的に対象列を絞らないとエラーになるように変わっています。

✅After:集計したい列を先に絞り込んでからgroupbyする

result = df.groupby("店舗")["売上"].sum()

「groupbyの後にどの列を集計するか」を明示するくせをつけておくと、このエラーを避けられます。

応用・一歩先の使い方

列ごとに異なる集計方法を指定する

aggに辞書を渡すと、列ごとに異なる集計方法を指定できます。

result = df.groupby("店舗").agg({
    "売上": "sum",
    "担当者": "count"
})
print(result)

「売上は合計、担当者は人数(件数)」のように、列ごとに意味の異なる集計を同時に行いたい場合に便利です。

グループごとに独自の関数を適用する

標準の集計方法(sum、meanなど)では対応できない処理は、applyと組み合わせることもできます。
ただしapplyは処理が重くなりやすいため、まずは標準の集計方法で対応できないかを検討するのがおすすめです。
applyの詳しい使い方は「applyとlambdaで列・行に対する処理をまとめる」で解説します。

まとめ

この記事のポイント

  • groupbyは指定列でグループ化し、グループごとに集計するための機能
  • 複数列でのグループ化、複数集計の同時実行(agg)にも対応している
  • pandas 2.x系では文字列列を含んだままsum()するとエラーになりやすいので、対象列を明示する
  • reset_index()をつけると、集計結果を通常のDataFrameとして扱いやすくなる

次に読むべき記事

グループ集計ができるようになったら、次は複数のデータを1つにまとめる「merge・concatで複数のデータを結合する」に進みましょう。
複数の店舗データやマスタデータを結合してから集計する、という流れは実務で非常によく登場します。

タグ: Pandas, 中級者向け, データ加工

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