PythonでExcelのピボットテーブルのように集計する手順|pandasのpivot_tableで行と列に分ける
PythonでExcelのピボットテーブルのように、店舗と月などの2つの項目で合計する手順を、pandasの公式の資料をもとに解説します。合計の行と列の付け方、空欄を0にする方法、平均になってしまうなどのつまずきを紹介します。
本記事はプロモーションを含みます。紹介する情報は、実際の成果や効果を保証するものではありません。
目次
この記事でわかること
- pandasのpivot_tableで、行と列の2つの項目で合計した表を作る方法
- 合計の行と列(margins)と、空欄を埋めるfill_valueの使い方
- 結果を別のExcelのファイルに保存し、元の表を残す手順
- 平均になってしまう、文字の売上がつながるなど、つまずきやすいところ
店舗ごと・月ごとの売上を、毎月Excelのピボットテーブルで作り直していると、範囲の選び直しや集計の方法の設定に手間がかかります。この記事では、PythonのpandasでExcelのピボットテーブルのように、行と列の2つの項目で合計した表を作り、別のファイルに保存する手順を紹介します。架空の表で動かした結果もあわせて紹介します。
pandasの関数の説明は、2026年10月25日に公式のAPIリファレンスとユーザーガイドを読んで確かめています。動作の確認に使ったのは、この記事のために作った架空の売上の表です。実在の会社や店舗のデータは使っていません。
先に結論: pivot_tableにaggfunc="sum"を付けて、別のファイルに保存する
先に結論を書くと、行と列の2つの項目で合計するときは、pivot_tableで行にする列(index)・列にする列(columns)・集計する列(values)を決め、aggfunc="sum"を付けます。 指定ごとの役割は、次の表のとおりです。
| 指定 | 役割 |
|---|---|
| index | 行に並べる列 |
| columns | 列に並べる列 |
| values | 集計する列 |
| aggfunc | 合計か平均か |
| fill_value | 空欄の値 |
| margins | 合計の行と列 |
pivot_tableで行と列に分けて集計する
pandasのpivot_tableは、表計算ソフトのようなピボットテーブルを、DataFrameの形で作る関数です。行に並べる項目をindex、列に並べる項目をcolumns、集計する列をvaluesで指定します。
集計の方法はaggfuncで決めます。pandasの資料では、aggfuncの初期の設定は平均(mean)です。売上を合計したいときは、aggfunc="sum"をはっきり付けます。
並び方は、sortで決めます。初期の設定では結果を並べ替えるので、行と列の見出しは、元の表に出てきた順ではなく、値の順に並びます。
合計の行と列、空欄の扱い
margins=Trueを付けると、行と列に合計が足されます。pandasの資料では、その行と列の名前は初期の設定で「All」で、margins_nameで変えられるとしています。
元の表に1行も無い組み合わせ(たとえば、9月にしか売上の無い店舗の10月)は、空欄(NaN)になります。fill_valueを付けると、集計の後の空欄を、その値で埋められます。
もう1つ、dropnaにも注意が要ります。pandasの資料では、dropnaの初期の設定では、どれかの列に欠損値がある行を、合計を計算する前に外すとしています。
手順: 店舗と月で売上を合計してファイルに書き出す
下のコードでは、架空の売上の表 sales.xlsx を読み込み、店舗を行、月を列にして売上を合計し、合計の行と列を付けて、別のファイル(sales_pivot.xlsx)に保存します。sales.xlsxは読み込むだけで、書き換えません。手元の表で使うときは、ファイル名と列名を合わせて書き換え、念のため元のファイルの写しを残しておきます。
import pandas as pd
# sales.xlsx は読み込むだけ(上書きしない)
sales = pd.read_excel("sales.xlsx")
# 店舗を行、月を列にして、売上を合計する(合計の行と列も付ける)
table = pd.pivot_table(sales, values="売上", index="店舗", columns="月",
aggfunc="sum", fill_value=0,
margins=True, margins_name="合計")
print(table)
# 店舗の名前も残したいので、index は付けたままにする
table.to_excel("sales_pivot.xlsx")
実行には、Pythonとpandasのほか、xlsxのファイルを扱うopenpyxlが要ります。この表では店舗の名前が行の見出し(index)になるので、to_excelではindex=Falseを付けずに書き出しています。
実行した結果
架空の表(8行。店舗・月・売上の3列、店舗は4つ、月は9月と10月)で試すと、次の表が表示されました。
- 名古屋は9月の5000だけで、10月は0になりました
- 東京は9月が2行の合計の20000、10月が15000、合計の列が35000になりました
- いちばん下の合計の行は、9月が34000、10月が32000、全体が66000で、元の表の売上の合計と同じでした
- sales_pivot.xlsxには、店舗の名前と合計の行・列が入り、元のsales.xlsxは変わりませんでした
動作を確かめたのは Mac の作業PCで、Python 3.12.15に、pandas 3.0.6とopenpyxl 3.1.5を入れた環境です。
自分で直すか、相談するかの判断
判断の目安は、「合計の行の全体の値が、元の表の売上の合計と同じになるか」です。同じなら、行や列の取りこぼしはありません。合わないときは、店舗や月が空欄の行や、売上が文字で入っている行が無いかを確かめます。「東京」と「東京 」のように表記が揺れていると、同じ店舗が2行に分かれます。集計の前に表記を整える方法は、PythonでExcelの表の文字の前後の空白と全角・半角をそろえる手順にまとめています。
月の区切り方(締め日)や、どの売上を数えるかは、表を受け取る人の決まりで変わります。集計の前に、表を受け取る人と決めておきます。
つまずきやすいところ
- aggfuncを付け忘れる: 初期の設定は平均のため、架空の表では東京の9月が合計の20000ではなく、平均の10000になりました
- fill_valueを付けない: 架空の表では、データの無い組み合わせがNaNになり、ほかの値も小数の形で表示されました
- 売上が文字で入っている: 売上が「12,000」のようなカンマ付きの文字だと、架空の表ではエラーにならず、「12,0008,000」のように文字がつながりました。数値に直してから集計します
- 店舗が空欄の行が消える: 架空の表に店舗が空欄の行(売上3000)を1つ足すと、合計の行の全体は66000のままで、元の表の合計の69000と合いませんでした
- 1つの項目だけで集計したいとき: 店舗ごとの合計を縦に並べるだけなら、groupbyで足ります。方法は、PythonでCSVを集計する手順で紹介しています
- 集計の後に並べ替えたいとき: 合計の大きい順に並べるときは、PythonでExcelの表を並べ替えて上位の行を取り出す手順が参考になります。別の表の商品名を足してから集計するときは、PythonでExcelの2つの表を共通の列で結合する手順で紹介しています
- 月ごとの列が横に並んだ表から集計したいとき: 月が列になった横持ちの表は、先にmeltで店舗・月・売上の縦持ちに並べ直すと、pivot_tableで集計できます。手順は、PythonでExcelの横持ちの表を縦持ちに並べ直す手順で紹介しています
まとめ
- 行と列の2つの項目で合計するときは、pivot_tableでindex・columns・valuesを決め、aggfunc="sum"を付けます
- margins=Trueで合計の行と列を足し、fill_value=0で空欄を0にします
- 合計の行の全体の値が、元の表の売上の合計と同じかを確かめます
- 結果は別のファイルに書き出し、元の表は書き換えません
よくある質問
pivot_tableで合計したはずが、数が小さいのはなぜですか?
aggfuncを付けていない可能性があります。pandasの資料では、aggfuncの初期の設定は平均(mean)です。架空の表でも、aggfuncを付けないと、東京の9月は合計の20000ではなく平均の10000になりました。合計するときはaggfunc="sum"を付けます。
表の中にNaNが出るのはなぜですか?
その行と列の組み合わせのデータが、元の表に1行も無いためです。fill_valueで、集計の後の空欄を埋める値を決められます。架空の表でも、fill_value=0を付けると0になりました。
合計の行と列を付けるには、どうしますか?
margins=Trueを付けます。pandasの資料では、行と列に「All」という名前の合計の行と列が足されるとしています。margins_nameで名前を変えられるので、記事のコードでは「合計」にしています。
groupbyとpivot_tableは、どう使い分けますか?
1つの項目ごとの合計を縦に並べるだけならgroupbyで足ります。店舗と月のように、行と列の2つの項目で表にしたいときはpivot_tableが向いています。
集計すると、元のExcelのファイルも変わりますか?
変わりません。記事のコードは元のファイルを読むだけで、結果は別の名前のファイルに書き出します。架空の表で試したときも、元のsales.xlsxは変わりませんでした。