概要(pivotは「縦長データを横に広げて“見やすい表”に再配置する」)
pandasのpivotは、行ラベル・列ラベル・値列を指定して、縦に並んだレコードを「行×列」の表へ並べ替えるメソッドです。Excelのピボットテーブルに似ていますが、pivotは集計をしません。「同じ行×列の組み合わせが一意である」ことが前提です。重複があるなら、集計できるpivot_tableを使うのが安全です。
基本の使い方(index・columns・valuesの3点を押さえる)
もっとも基本的なピボット
import pandas as pd
df = pd.DataFrame({
"store": ["A", "A", "B", "B"],
"item": ["apple", "banana", "apple", "banana"],
"sales": [10, 12, 7, 9]
})
out = df.pivot(index="store", columns="item", values="sales")
print(out)
# item apple banana
# store
# A 10 12
# B 7 9
Pythonindex(行ラベル)、columns(列ラベル)、values(セルに置く値)を指定します。指定した行×列の組み合わせが重複していないときに使えます。
重複があるときはpivot_tableを使う
df_dup = pd.DataFrame({
"store": ["A", "A", "A"],
"item": ["apple", "apple", "banana"],
"sales": [10, 13, 12]
})
# 同じ (store="A", item="apple") が2件 → pivotはエラー
# df_dup.pivot(index="store", columns="item", values="sales")
out = pd.pivot_table(df_dup, index="store", columns="item", values="sales", aggfunc="sum")
print(out)
# item apple banana
# store
# A 23 12
Pythonpivotは重複でエラーになります。pivot_tableならaggfunc(sum, mean, countなど)で集計して安全に整形できます。
重要ポイントの深掘り(重複対策・欠損・複数値・MultiIndex)
重複対策(pivotでダメならpivot_table)
- 判断基準: indexとcolumnsで定義される組み合わせが一意でない場合はpivotが失敗する。
- 解決策: pivot_tableでaggfuncを指定して集計する(sum/mean/count/firstなど)。
pd.pivot_table(df, index="store", columns="item", values="sales", aggfunc="mean")
Python欠損値の扱い(fill_valueで穴埋め)
- 欠損が出る理由: 行×列の組み合わせが存在しないセルはNaNになる。
- 解決策: pivot_tableならfill_valueで穴埋めできる。
out = pd.pivot_table(df, index="store", columns="item", values="sales", aggfunc="sum", fill_value=0)
Python複数のvaluesを並べる(列が層構造になる)
df2 = pd.DataFrame({
"store": ["A", "A", "B", "B"],
"item": ["apple", "banana", "apple", "banana"],
"sales": [10, 12, 7, 9],
"cost": [6, 7, 5, 6]
})
out = df2.pivot(index="store", columns="item", values=["sales", "cost"])
print(out)
# valuesが複数だと列がMultiIndex(階層)になる
Pythonvaluesを複数渡すと、列が階層(MultiIndex)になります。後で列名をフラット化するなどの整形が有効です。
行・列を複数にする(MultiIndex)
df3 = pd.DataFrame({
"year": [2024, 2024, 2025, 2025],
"store": ["A", "B", "A", "B"],
"item": ["apple", "apple", "apple", "apple"],
"sales": [10, 7, 12, 8]
})
out = df3.pivot(index=["year", "store"], columns="item", values="sales")
print(out)
# 年×店を行の階層にできる
Pythonindexやcolumnsをリストで指定すると階層化できます。グループ集計や並べ替えの前準備として有用です。
実践例(売上整形・比率計算・集計付きピボット)
例1:縦長売上を「店×商品」へ整形
df = pd.DataFrame({
"store": ["A", "A", "B", "B"],
"item": ["apple", "banana", "apple", "banana"],
"sales": [10, 12, 7, 9]
})
wide = df.pivot(index="store", columns="item", values="sales")
wide = wide.reset_index() # 行インデックスを列へ戻す(保存や出力用に便利)
print(wide)
Pythonまずpivotで「見やすく」整形し、必要ならreset_indexでフラットな表に戻します。
例2:重複があるデータを合計で整える
df = pd.DataFrame({
"month": ["2025-01", "2025-01", "2025-02", "2025-02"],
"item": ["apple", "apple", "apple", "banana"],
"sales": [10, 5, 12, 7]
})
# 同じ (month, item) が重複 → 合計で整形
pt = pd.pivot_table(df, index="month", columns="item", values="sales", aggfunc="sum", fill_value=0)
print(pt)
Python現実のデータは重複しやすいので、pivot_tableのaggfuncとfill_valueが定番です。
例3:比率列を追加する(後処理のコツ)
pt = pd.pivot_table(df, index="month", columns="item", values="sales", aggfunc="sum", fill_value=0)
pt["total"] = pt.sum(axis=1)
pt["apple_ratio"] = (pt.get("apple", 0) / pt["total"]).round(3)
print(pt)
Pythonpivot後は「合計」「比率」を列演算で追加できます。getで列がない場合の安全な参照も覚えておくと便利です。
よくあるつまずきと回避(エラー・列名・整形の戻し方)
ValueError: Index contains duplicate entries
- 原因: pivotで行×列の組み合わせが重複している。
- 回避: pivot_table+aggfuncを使う。重複を事前に集計して一意にする。
列名が階層で扱いづらい
- 対策: 列名をフラット化する。
pt.columns = ["_".join(map(str, c)).strip() if isinstance(c, tuple) else c for c in pt.columns]
Python整形を元に戻したい(ワイド→ロング)
- 手段: stackやmeltを使う。
# ワイド→ロング(列を縦へ)
long = pt.reset_index().melt(id_vars="month", var_name="item", value_name="sales")
# または、階層列なら stack() → reset_index() → rename()
Pythonまとめ(pivotで“再配置”、重複はpivot_tableで“集計しながら再配置”)
pivotはindex・columns・valuesの3つを指定して、縦長データを「行×列」に再配置する道具です。重複があるならpivot_tableでaggfuncを使って集計し、fill_valueで欠損を埋める。valuesや行列に複数を指定すれば階層化も可能で、後処理ではreset_index・列演算・stack/meltで整形を仕上げる。最初に「重複の有無」を見極め、pivotとpivot_tableを使い分ければ、初心者でも迷わず美しいテーブルが作れます。
