pivotで表を横に広げようとして、重複エラーで止まることがあります。店舗を行、商品を列にする表なら、同じ店舗と商品の組へ二つ以上の値がある状態です。
その重複が誤入力なのか、別々の売上明細なのかで対応は変わります。pivotは値を一つに決める集計を行わないため、複数の明細を合計して表へ置く場合はpivot_tableを使い、集計方法も指定します。
同じ組をすべて確認へ出す
次は店舗Aの商品Pが二明細、店舗Bの商品Pが一明細ある架空の表です。まず同じ組の行を取り出し、pivotが拒否することを確かめます。その後、明細を合計してよいという条件で集計します。
import pandas as pd
df = pd.DataFrame({
"店舗": ["A", "A", "B"],
"商品": ["P", "P", "P"],
"金額": [100, 50, 30],
})
duplicates = df[df.duplicated(["店舗", "商品"], keep=False)]
print("重複候補の行数:", len(duplicates))
try:
df.pivot(index="店舗", columns="商品", values="金額")
except ValueError:
print("pivotは重複した組を拒否")
else:
raise AssertionError("重複した組が検出されません")
table = df.pivot_table(
index="店舗", columns="商品", values="金額",
aggfunc="sum", fill_value=0,
)
for shop in ["A", "B"]:
print(shop, table.loc[shop, "P"])
assert table.loc["A", "P"] == 150
assert table.loc["B", "P"] == 30
重複候補はAの二行です。合計を指定した表ではAが150、Bが30になります。Windows・Python 3.12.10・pandas 3.0.2で、pivotの例外と合計結果を確認しました。
keep=Falseは同じ組の最初の行も確認候補へ含める指定です。二行目だけを見るより、どの値が並んでいるかを比較できます。候補へ出すことと、削除することは別の処理です。
合計してよい値かを先に決める
売上明細の金額なら、条件がそろう場合に合算できます。商品単価や現在の状態、更新日時などは、同じ組だからといって足せる値ではありません。最新の値を選ぶ場合も、何をもって最新とするかを決める必要があります。
誤って二重に取り込んだデータを合計すると、間違いを集計結果へ含めてしまいます。取り込み元の明細IDなどを見て、本来別々の行かどうかを確かめてください。
重複エラーをなくすためだけにdrop_duplicatesで一行へ減らすと、正しい別明細まで失う可能性があります。削除の条件が決まっていなければ、重複候補を別表へ出すところで止めます。
集計方法を省略しない
pivot_tableの集計方法の既定値はmeanです。上のAでは100と50の平均75になるため、合計150を求めるならaggfunc="sum"を明示します。エラーが出ずに表ができたことだけで、求めた値になったとは判断しません。
fill_value=0も表の空いた組み合わせを0と表示するという条件です。元の金額が欠損した行を正しい0として扱う指定と混同しないようにします。集計前の件数、全体の金額、表の合計を比べると、変形に伴う差を見つけやすくなります。
集計表の作成はCSV集計の基本、何を同じデータとみなすかは重複判定の考え方で確認できます。
参考資料
pivotとpivot_tableの公式資料を2026年11月1日に確認しました。
