pandasのpivot()の使い方|縦長データを横長の表にする引数と重複エラーの直し方、Rのpivot_widerとの対応

pandasのpivot()は、縦に並んだデータ(ロング形式)を、行・列・値の3つを指定して横長の表(ワイド形式)に組み替えるメソッドです。書き方は df.pivot(index=”行にする列”, columns=”列にする列”, values=”値の列”) で、集計はしないので、行と列の組み合わせが重複しているとValueErrorになります。

この記事では、pivot()の引数、valuesを省略したときの多段の列、結果を普通の表に戻す方法、重複エラーの直し方、Rのpivot_wider()との対応までを実行例つきでまとめます。コードはpandas 3.0.6(Python 3.12.15)で実行しました(2026年10月15日確認)。集計もしたい場合は「pandasのpivot_tableの使い方」、stack・unstack・meltとの違いは「pandasのstack・unstack・pivotの違いと使い分け」で詳しく扱っています。

pivot()の書き方と3つの引数

公式リファレンスでのシグネチャは DataFrame.pivot(*, columns, index=<no_default>, values=<no_default>) です(pandas.DataFrame.pivot — pandas documentation、2026年10月15日確認)。先頭の * は、すべての引数をキーワードで渡す必要があるという意味です。

引数 役割 省略したとき
index 新しい表の行(見出し)にする列 今のインデックスをそのまま使う
columns 新しい表の列名にする列(必須) 省略できない
values セルに入れる値の列 残りの列すべてを使い、列が2段(MultiIndex)になる

どの引数にも列名のリストを渡せます。リストにすると、行や列の見出しが2段以上になります。

基本の使い方:日付×店舗の売上表を作る

1行に「日付・店舗・売上・客数」が1件ずつ並んだ表を、日付を行、店舗を列にした売上表へ組み替えます。

import pandas as pd

df = pd.DataFrame({
    "日付": ["10/1", "10/1", "10/1", "10/2", "10/2", "10/2"],
    "店舗": ["渋谷", "新宿", "池袋", "渋谷", "新宿", "池袋"],
    "売上": [120, 200, 90, 150, 180, 60],
    "客数": [12, 20, 9, 15, 18, 6],
})
print(df)

wide = df.pivot(index="日付", columns="店舗", values="売上")
print(wide)
print(wide.columns.name, wide.index.name)
     日付  店舗   売上  客数
0  10/1  渋谷  120  12
1  10/1  新宿  200  20
2  10/1  池袋   90   9
3  10/2  渋谷  150  15
4  10/2  新宿  180  18
5  10/2  池袋   60   6

店舗     新宿  池袋   渋谷
日付                
10/1  200  90  120
10/2  180  60  150

店舗 日付

見るポイントは3つです。

  • 「店舗」の値(渋谷・新宿・池袋)がそのまま列名になり、「日付」の値が行の見出しになります。
  • 列は並べ替えられます。日本語は文字コード順になるので、元データの順(渋谷・新宿・池袋)にはなりません。
  • 表の左上の「店舗」は列の名前(columns.name)、その下の「日付」は行の名前(index.name)です。データの列ではありません。

列の順番を決めたいときは、組み替えた後にリストで並べ直します。

w = wide[["渋谷", "新宿", "池袋"]]
print(w)
店舗     渋谷   新宿  池袋
日付                
10/1  120  200  90
10/2  150  180  60

valuesを省略すると列が2段になる

values を指定しないと、index・columns以外の列(ここでは売上と客数)がすべて値になり、列の見出しが「値の列名」と「店舗」の2段になります。

w = df.pivot(index="日付", columns="店舗")
print(w)
print(w["客数"])
       売上           客数       
店舗     新宿  池袋   渋谷  新宿 池袋  渋谷
日付                           
10/1  200  90  120  20  9  12
10/2  180  60  150  18  6  15

店舗    新宿  池袋  渋谷
日付              
10/1  20   9  12
10/2  18   6  15

上の段の名前で w["客数"] のように取り出せば、1段の表になります。values=["売上"] のようにリストで1列だけ渡した場合も、列は ("売上", "新宿") のような2段のままになる点に注意してください。

結果を普通の表(1段の列)に戻す

pivot()の結果は、行の見出しにindexが入った形です。CSVに書き出したり、別の表と結合したりするときは、reset_index() で「日付」を普通の列に戻し、列の名前を消しておくと扱いやすくなります。

w = df.pivot(index="日付", columns="店舗", values="売上")
flat = w.reset_index()
flat.columns.name = None
print(flat)

# 列が2段のときは「売上_新宿」のように1段へつなげる
w3 = df.pivot(index="日付", columns="店舗", values=["売上"])
w3.columns = [f"{a}_{b}" for a, b in w3.columns]
print(w3.reset_index())
     日付   新宿  池袋   渋谷
0  10/1  200  90  120
1  10/2  180  60  150

     日付  売上_新宿  売上_池袋  売上_渋谷
0  10/1    200     90    120
1  10/2    180     60    150

行や列を複数の列で組み立てる

indexやcolumnsに列名のリストを渡すと、見出しが2段になります。支店と月の組み合わせを行にして、商品を列に並べる例です。

df = pd.DataFrame({
    "支店": ["東京", "東京", "東京", "東京", "大阪", "大阪"],
    "月":   ["4月", "4月", "5月", "5月", "4月", "5月"],
    "商品": ["A", "B", "A", "B", "A", "A"],
    "売上": [100, 80, 120, 90, 70, 75],
})
print(df.pivot(index=["支店", "月"], columns="商品", values="売上"))
print(df.pivot(index="支店", columns=["月", "商品"], values="売上"))
商品         A     B
支店 月              
大阪 4月   70.0   NaN
   5月   75.0   NaN
東京 4月  100.0  80.0
   5月  120.0  90.0

月      4月           5月      
商品      A     B      A     B
支店                          
大阪   70.0   NaN   75.0   NaN
東京  100.0  80.0  120.0  90.0

大阪には商品Bのデータが無いので、そのセルは NaN になりました。2段の見出しの扱い方は「pandasのMultiIndexの使い方」で詳しく説明しています。

データが無いセルはNaNになり、整数が小数になる

元データに無い組み合わせは NaN で埋まります。NaNは小数(float)の値なので、整数だった列も 200.0 のような表示に変わります。pivot()には fill_value 引数が無いため、組み替えた後に fillna() で埋めます。

df = pd.DataFrame({
    "日付": ["10/1", "10/1", "10/2"],
    "店舗": ["渋谷", "新宿", "渋谷"],
    "売上": [120, 200, 150],
})
w = df.pivot(index="日付", columns="店舗", values="売上")
print(w)
print(w.dtypes.to_dict())
print(w.fillna(0).astype(int))
店舗       新宿     渋谷
日付                
10/1  200.0  120.0
10/2    NaN  150.0
{'新宿': dtype('float64'), '渋谷': dtype('float64')}

店舗     新宿   渋谷
日付            
10/1  200  120
10/2    0  150

「データが無い」と「売上が0」は意味が違います。0で埋めてよいかは、データの意味で判断してください。

エラー「Index contains duplicate entries, cannot reshape」の直し方

pivot()は集計をしないので、同じ行×列の組み合わせに値が2つ以上あると、どちらを入れるか決められずにValueErrorになります。公式リファレンスにも、組み合わせに複数の値があるとValueErrorになり、集計が必要ならpivot_tableを使うよう書かれています。

df = pd.DataFrame({
    "日付": ["10/1", "10/1", "10/2"],
    "店舗": ["渋谷", "渋谷", "渋谷"],
    "売上": [120, 30, 150],
})
try:
    df.pivot(index="日付", columns="店舗", values="売上")
except ValueError as e:
    print("ValueError:", e)

# 重複している行を確かめる
print(df[df.duplicated(["日付", "店舗"], keep=False)])
ValueError: Index contains duplicate entries, cannot reshape
     日付  店舗   売上
0  10/1  渋谷  120
1  10/1  渋谷   30

まず duplicated(..., keep=False) で重複している行を見て、原因を確かめます。同じデータの二重登録なら drop_duplicates() で消し、1日に複数回の売上が正しく記録されているなら、合計などで集計します。

print(df.pivot_table(index="日付", columns="店舗", values="売上", aggfunc="sum"))
print(df.groupby(["日付", "店舗"])["売上"].sum().unstack())
店舗     渋谷
日付       
10/1  150
10/2  150

店舗     渋谷
日付       
10/1  150
10/2  150

どちらも同じ結果です。pivot_table は1行で書け、groupby+unstack は途中の集計結果を確かめながら進められます。

エラー「takes 1 positional argument but 4 were given」

古い記事にある df.pivot("日付", "店舗", "売上") のような書き方は、pandas 2.0以降はTypeErrorになります(2.0で引数がキーワード専用になりました。What’s new in 2.0.0の「Disallow passing non-keyword arguments to DataFrame.pivot()」)。

df = pd.DataFrame({"日付": ["10/1", "10/1"], "店舗": ["渋谷", "新宿"], "売上": [120, 200]})
try:
    df.pivot("日付", "店舗", "売上")
except TypeError as e:
    print("TypeError:", e)
TypeError: DataFrame.pivot() takes 1 positional argument but 4 were given

index=・columns=・values= を付けて書けば動きます。

ワイド形式からロング形式へ戻す(melt)

pivot()の逆の操作は melt() です。reset_index() で日付を列に戻してから、店舗の列を縦に並べ直します。

df = pd.DataFrame({
    "日付": ["10/1", "10/1", "10/1", "10/2", "10/2", "10/2"],
    "店舗": ["渋谷", "新宿", "池袋", "渋谷", "新宿", "池袋"],
    "売上": [120, 200, 90, 150, 180, 60],
})
w = df.pivot(index="日付", columns="店舗", values="売上")[["渋谷", "新宿", "池袋"]]
long = w.reset_index().melt(id_vars="日付", var_name="店舗", value_name="売上")
print(long)

# pd.pivot(df, ...) という関数の形でも同じ
print(pd.pivot(df, index="日付", columns="店舗", values="売上")
      .equals(df.pivot(index="日付", columns="店舗", values="売上")))
     日付  店舗   売上
0  10/1  渋谷  120
1  10/2  渋谷  150
2  10/1  新宿  200
3  10/2  新宿  180
4  10/1  池袋   90
5  10/2  池袋   60

True

melt()の引数は「pandasのmelt()の使い方」で詳しく扱っています。

Rのpivot_wider()との対応

Rのtidyrで pivot_wider() を使っていた人向けに、引数の対応をまとめます(Pivot data from long to wide — pivot_wider • tidyr、2026年10月15日確認)。

tidyrのpivot_wider() pandas メモ
id_cols index pandasでは行の見出しになる
names_from columns 値が新しい列名になる
values_from values 複数指定で列が2段になる
values_fill pivot()の後に fillna() pivot_tableなら fill_value
values_fn(重複を集計) pivot_table(aggfunc=...) pivot()は重複でエラー
names_sep(列名をつなぐ) 列名を自分で f"{a}_{b}" とつなぐ 上の「普通の表に戻す」を参照

逆向きの pivot_longer() にあたるのが melt() です。

pivot・pivot_table・unstackの使い分け

やりたいこと 使うもの
重複の無いデータを横長にするだけ pivot()
合計・平均などで集計しながら横長にする、総計も付けたい pivot_table()
行の見出し(MultiIndex)の一部を列に回す unstack()
横長を縦長に戻す melt()(または stack())

組み替えの全体像は公式ユーザーガイドの「Reshaping and pivot tables」にまとまっています。表の組み替えは、データ分析や機械学習の前処理で毎回のように出てくる操作で、テックジムのAIエンジニア養成コース(16章で機械学習とディープラーニングを学ぶコース)でも第0章「データ分析入門とデータ可視化」から扱います。

よくある質問

Q. pivotとpivot_tableの違いは何ですか?

pivotは並べ替えるだけで集計をしないため、行と列の組み合わせが重複するとエラーになります。pivot_tableは重複を合計や平均で集計でき、総計(margins)や空白を埋めるfill_valueも指定できます。

Q. 「Index contains duplicate entries, cannot reshape」と出たらどうすればいいですか?

indexとcolumnsの同じ組み合わせが2行以上あるという意味です。duplicatedで重複行を確認し、二重登録ならdrop_duplicatesで消し、正しいデータならpivot_tableかgroupbyで集計してください。

Q. df.pivot(“A”, “B”, “C”)と書くとエラーになるのはなぜですか?

pandas 2.0以降、pivotの引数はキーワード専用になったためです。df.pivot(index=”A”, columns=”B”, values=”C”)のように引数名を付けて書けば動きます。

Q. pivotの結果を普通の列に戻すにはどうしますか?

reset_index()で行の見出しを列に戻し、columns.nameをNoneにします。列が2段になっている場合は、列名を「売上_新宿」のように1段へつなげてから戻します。

Q. Rのpivot_widerに当たるのはどれですか?

pandasではpivotが当たります。id_colsがindex、names_fromがcolumns、values_fromがvaluesに対応し、重複を集計するvalues_fnを使う場合はpivot_tableを使います。


pandas|集計・グループ化の関連記事

groupbyや各種集計関数で、データを要約する操作の記事です。

pandas全体の使い方は「pandasの使い方を初心者向けに解説」でまとめています。

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら