PythonでExcelの売上から前月比と累計を計算する手順|pandasで店舗ごとの増減を出す
Pythonのpandasで、店舗・年月・売上の表から、前月差・前月比・累計を店舗ごとに計算してExcelに書き出す手順を解説します。並べ替え忘れや抜けた月で数字がずれる例も、架空のデータで試した結果とともに紹介します。
目次
この記事でわかること
- 店舗・年月・売上の表から、前月の売上と前月差を出す方法(shift)
- 前月比を出す方法(pct_change)と、その値が割合で返ること
- 累計を出す方法(cumsum)と、店舗ごとに分けて計算する方法(groupby)
- 並べ替え忘れ・店舗の分け忘れ・抜けた月で、数字がずれる例
月ごとの売上の表に、前月からの増減や累計を毎回Excelの式で足していませんか。この記事では、pandasで店舗ごとに前月差・前月比・累計を計算して書き出す手順を紹介します。月ごとの合計の出し方は、PythonでExcelの日付から月ごとの合計を出す手順で紹介しています。
参照したのは、pandas 3.1.0の公式のAPIリファレンスです。Series と、groupby で分けた後のそれぞれの pct_change・shift・cumsum を、2026年10月30日に原文で読みました。例の店舗と売上は、この記事のための作り物です。
先に結論: 並べ替えてから、店舗ごとに計算する
店舗と年月の順に並べ替え、店舗でgroupbyしてから、shift・pct_change・cumsumを使います。 どれも「1つ前の行」や「上からの行」を使う計算なので、並び順と分け方で結果が変わります。
| 出したいもの | 使うもの |
|---|---|
| 前月の売上 | shift(1) |
| 前月差 | 売上 − 前月の売上 |
| 前月比 | pct_change |
| 累計 | cumsum |
前月の売上と前月差(shift)
shiftは、値を指定した数だけずらします。groupbyで店舗に分けてからshift(1)を使うと、それぞれの店舗の中で、1つ前の行の売上が隣に並びます。資料では、グループごとに指定した数だけずらすと説明しています。前月差は、売上からこの前月の売上を引いて出します。
前月比(pct_change)
pct_changeは、今の行と前の行の間の変化を、割合で計算します。資料では、初期の設定ではすぐ前の行からの変化を計算するとしています。
注意したいのは、名前に「pct」と付いていても、返すのは百分率ではなく割合だという点です。資料の注記でも、百分率が必要なら100を掛けるとしています。0.1は10%の増加、-0.1は10%の減少です。
累計(cumsum)
cumsumは、上から順に値を足していった累計を、元と同じ長さで返します。groupbyで分けてから使うと、それぞれのまとまりの中だけで累計を取ります。
手順: 店舗ごとの前月差・前月比・累計を書き出す
次のコードは、架空の表 monthly_sales.xlsx(店舗・年月・売上の3列)を読み込み、4つの列を足して monthly_growth.xlsx に書き出します。monthly_sales.xlsx は書き換えません。年月は「2026-09」のような文字で入っている前提です。
import pandas as pd
# 店舗・年月・売上の表を読む(元のファイルは上書きしない)
table = pd.read_excel("monthly_sales.xlsx")
# 店舗ごとに、年月の古い順に並べる
table = table.sort_values(["店舗", "年月"]).reset_index(drop=True)
by_store = table.groupby("店舗")["売上"]
# 前月の売上・前月差・前月比・累計を、店舗ごとに計算する
table["前月の売上"] = by_store.shift(1)
table["前月差"] = table["売上"] - table["前月の売上"]
table["前月比"] = by_store.pct_change()
table["累計"] = by_store.cumsum()
table.to_excel("monthly_growth.xlsx", index=False)
print(table)
動かす前に、pandasと、xlsxを読み書きするopenpyxlを入れておきます。
試した結果
作り物の表(本店が8月から11月の4か月、駅前店が8月・9月・11月の3か月。行の並びはばらばら)で動かしました。
- 本店は、9月の前月差が10,000・前月比0.1、10月が-11,000・-0.1、11月が21,000・約0.212で、累計は100,000・210,000・309,000・429,000と増えていきました
- 駅前店の累計は、本店とは別に50,000から始まり、11月で165,000になりました
- 両方の店舗の8月は、前月の売上・前月差・前月比が空(NaN)でした
- 10月の行がない駅前店の11月は、前月比が約0.091でした。9月の55,000と比べた値です
- 読み込んだmonthly_sales.xlsxは、実行の前後でバイト単位で同じでした
Python 3.12.15とpandas 3.1.0、openpyxl 3.1.5の入ったMacの作業PCで動かしました。Excelのアプリでの見た目は確かめていません。
自分で直すか、相談するかの判断
目安は、「表の月が、店舗ごとに抜けなくそろっているか」です。そろっていれば、この記事のコードで前月比を出せます。
閉店や開店で月が抜ける店舗がある、年度の初めで累計をやり直す、といった決まりがある場合は、計算の前に月をそろえる作業や、分け方の追加が要ります。数字を使う人と、抜けた月をどう扱うかを決めてから作り、手で計算した値と数か所を照らし合わせます。
つまずきやすいところ
- 店舗で分けずに計算する: 試したときに店舗で分けずにpct_changeを使うと、駅前店の8月が本店の11月と比べられ、約-0.583になりました。累計も2つの店舗を通して足され、最後は594,000でした
- 並べ替えずに計算する: 行がばらばらのまま店舗で分けると、前の行が前の月になりません。試したときも、本店の8月に約0.010という前月比が付きました
- 抜けた月に気づかない: 1つ前の行と比べるため、抜けた月の次は2か月前との比較になります。表の月がそろっているかを先に確かめます
- 割合を百分率と思い込む: pct_changeの0.1は10%です。Excelでパーセントの書式を付ける方法は、PythonでExcelに書き出すときに列の幅と数値の書式を整える手順で紹介しています
- 店舗を行、月を列に並べたい: 書き出した表を店舗×月の形に組み替える方法は、PythonでExcelのピボットテーブルのように集計する手順にまとめています
まとめ
- 店舗と年月の順に並べ替え、店舗でgroupbyしてから計算します
- 前月の売上はshift(1)、前月比はpct_change、累計はcumsumで出します
- pct_changeは割合を返します。0.1は10%です
- 最初の月は空になり、抜けた月があると2か月前と比べるので、月がそろっているかを先に確かめます
よくある質問
pct_changeの結果が0.1のように小さいのはなぜですか?
pct_changeは、百分率ではなく割合を返すためです。資料では、名前に反して割合の変化を計算し、百分率が必要なら100を掛けるとしています。0.1は10%の増加です。Excelでパーセントの書式を付けて見せる方法もあります。
最初の月の前月比が空になるのは、まちがいですか?
まちがいではありません。最初の月には比べる前の月がないため、前月の売上・前月差・前月比は空(NaN)になります。架空の表でも、両方の店舗の8月が空でした。表に残すか、外すかを決めておきます。
抜けている月があると、前月比はどうなりますか?
1つ前の行と比べるため、抜けた月の次の月は、2か月前と比べた値になります。資料でも、初期の設定ではすぐ前の行からの変化を計算するとしています。架空の表でも、10月がない駅前店の11月は、9月と比べた値でした。月がすべてそろっているかを先に確かめます。
累計を、年度の初めからやり直したいときはどうしますか?
年度の列を作り、店舗と年度の2つでgroupbyしてからcumsumを使います。累計は、groupbyで分けたまとまりの中だけで足されるためです。年度の区切りの月は会社によって違うので、決まりを確かめてから列を作ります。
前年同月比も、同じやり方で出せますか?
月がすべてそろっていれば、shiftやpct_changeのperiodsを12にすると、12行前と比べられます。ただし、行の数で数えるので、抜けた月があると12か月前にはなりません。月の抜けがないことを確かめてから使います。