PythonでExcelの日付から月ごとの合計を出す手順|pandasで日付を月にまとめて集計
Pythonのpandasで、Excelの売上の明細の日付から年月を取り出し、月ごとの合計と件数を集計して書き出す手順を解説します。日付が文字のままのときのエラーや、読めない日付の行の扱いも、架空のデータで試した結果とともに紹介します。
目次
この記事でわかること
- Excelの売上の明細の日付から、年月を取り出す方法(dt.to_period)
- 月ごとの売上の合計と件数を、名前を付けて一度に出す方法(groupbyとagg)
- 日付が文字のままのときのエラーと、日付として読めない行の扱い
- 年月を文字に直さずに書き出したときに起きること
日付の入った売上の明細から、月ごとの合計を毎月手で集計していませんか。この記事では、pandasで日付を月にまとめ、月ごとの合計と件数を出してExcelに書き出す手順を紹介します。
拠り所にしたのは、pandas 3.1.0の公式の資料です。to_datetime・Series.dt.to_period・DataFrame.groupbyのAPIリファレンスと、ユーザーガイドの「Group by」を、2026年10月30日に原文で読みました。例の店舗と売上の数字は、この記事のために作ったものです。
先に結論: 日付に直して、年月の列でまとめる
手順は3段です。pd.to_datetimeで日付の列を日付に直し、dt.to_period("M")で年月の列を作り、その列でgroupbyして合計と件数を出します。 書き出す前に、年月は文字に直しておきます。
| すること | 使うもの |
|---|---|
| 日付に直す | pd.to_datetime |
| 年月を取り出す | dt.to_period("M") |
| 月ごとにまとめる | groupbyとagg |
日付の列を日付に直す
Excelの日付の列は、日付のセルと、「2026/10/05」のような文字のセルが混ざっていることがあります。そのままでは、年月を取り出す.dtが使えません。
pd.to_datetimeは、初期の設定(errors="raise")では読めない値があると例外で止まり、errors="coerce"を付けると読めない値を空(NaT)にします。日付の直し方そのものは、PythonでExcelの日付を正しく読み込む手順で詳しく紹介しています。
年月を取り出す(dt.to_period)
Series.dt.to_periodは、日付を、決まった頻度の期間(Period)に変えます。頻度に"M"を渡すと、2026年9月3日も9月28日も「2026-09」という同じ月になります。資料の例でも、3月・5月・8月の月末の日付が、to_period("M")で「2000-03」「2000-05」「2000-08」になっています。
月ごとに合計と件数を出す(groupbyとagg)
DataFrame.groupbyは、ある列の値ごとに行を分けて計算し、結果をまとめます。年月の列で分ければ、月ごとの計算になります。
aggに「出力する列の名前=(元の列, 計算)」の形で渡すと、出力の列に名前を付けながら、複数の計算を一度に出せます。ユーザーガイドでは、この書き方を「名前付きの集計(named aggregation)」と呼んでいます。groupbyは初期の設定でグループの値を並べ替えるため、月は古い順に並びます。
手順: 売上の明細から月ごとの合計を書き出す
次のコードは、架空の売上の明細 sales.xlsx(日付・店舗・売上の3列)を読み込み、月ごとの合計と件数を monthly_total.xlsx に書き出します。sales.xlsx は書き換えません。自分の表に合わせるときは、ファイル名と列の名前を変えてください。
import pandas as pd
# 明細のファイルを読む(上書きはしない)
rows = pd.read_excel("sales.xlsx")
# 日付の列を日付に直す。読めない値は空(NaT)にして、その数を表示する
rows["日付"] = pd.to_datetime(rows["日付"], errors="coerce")
print("日付として読めなかった行:", rows["日付"].isna().sum())
# 日付から年月を取り出し、月ごとに合計と件数を出す
rows["年月"] = rows["日付"].dt.to_period("M")
monthly = rows.groupby("年月").agg(
売上合計=("売上", "sum"),
件数=("売上", "count"),
)
# 年月を「2026-09」のような文字にしてから書き出す
monthly.index = monthly.index.astype(str)
monthly.to_excel("monthly_total.xlsx")
print(monthly)
このコードの前に、pandasと、xlsxの読み書きに使うopenpyxlを入れておく必要があります。
実行した結果
架空の売上の明細(6行。日付のセル4つ、「2026/10/05」という文字の日付1つ、「不明」と書かれた行1つ)で動かしました。
- 「日付として読めなかった行: 1」と表示されました。「不明」の行です
- 月ごとの結果は、2026-09が売上合計20,000・件数2、2026-10が20,000・2、2026-11が9,000・1でした。文字だった「2026/10/05」の行も10月に入りました
- 「不明」の行の売上3,000は、どの月にも入っていませんでした。明細の合計52,000に対し、月ごとの合計を足すと49,000です
- 書き出したmonthly_total.xlsxの年月の列は、「2026-09」のような文字でした
- 読み込んだsales.xlsxは、実行の前後でバイト単位で同じでした
Macの作業PCで試しました。Pythonは3.12.15、pandasは3.1.0、openpyxlは3.1.5です。Excelのアプリで開いたときの見た目は確かめていません。
自分で直すか、相談するかの判断
目安は、「月の区切りが、暦の月(1日から月末まで)でよいか」です。暦の月でよければ、この記事のコードで足ります。
20日締めのように会社ごとの締め日で区切る場合や、返品・取り消しの行の扱いに決まりがある場合は、集計の作りが変わります。経理の担当の人と区切り方や除く行を決めてから作り、作ったものは手で集計した月の数字と一度照らし合わせます。
つまずきやすいところ
- 日付が文字のまま.dtを使う: 架空の明細でも、日付のセルと文字の日付が混ざった列に.dt.to_periodを使うと、「Can only use .dt accessor」で始まるエラーで止まりました。先にpd.to_datetimeで直します
- 読めなかった行に気づかない: errors="coerce"で空になった行は、groupbyで黙って外れます。試したときも、明細の合計と月ごとの合計の差は「不明」の行の3,000でした。読めなかった行の数を表示し、合計を照らし合わせます
- 年月を文字に直さずに書き出す: astype(str)を外して書き出すと、年月の列は「2026-09」ではなく、2026年9月1日のような月の初めの日付として入りました。月の表として見せるなら文字に直します
- 店舗ごと・月ごとの表にしたい: 行に店舗、列に月を並べる表の作り方は、PythonでExcelのピボットテーブルのように集計する手順で紹介しています
- 集計の結果を検算したい: 件数と合計を出して元のデータと照らし合わせる考え方は、PythonでCSVを集計する手順にまとめています
- 出した月の合計から、前月比や累計も出したい: 店舗ごとに前月差・前月比・累計を計算する手順は、PythonでExcelの売上から前月比と累計を計算する手順で紹介しています
まとめ
- 日付の列はpd.to_datetimeで日付に直し、読めなかった行の数を確かめます
- dt.to_period("M")で年月の列を作り、groupbyとaggで月ごとの合計と件数を出します
- 読めなかった行は集計から外れるので、明細の合計と月ごとの合計を照らし合わせます
- 書き出す前に、年月をastype(str)で「2026-09」のような文字に直します
よくある質問
「Can only use .dt accessor」で始まるエラーは、なぜ出るのですか?
日付の列が、日付ではなく文字などのまま入っているためです。架空の明細でも、日付のセルと文字の日付が混ざった列にそのまま.dt.to_periodを使うと、このエラーで止まりました。先にpd.to_datetimeで日付に直します。
日付として読めない行は、集計でどうなりますか?
errors="coerce"で直すと、その行の日付は空(NaT)になり、月の集計から外れます。groupbyは、初期の設定では、グループの値が空の行を除くためです。架空の明細でも「不明」の行の3,000円は、どの月にも入りませんでした。外れた行の数を必ず確かめます。
件数は、行の数とは違うのですか?
countは、空でない値の数を数えます。ユーザーガイドでは、countはグループの中の欠けていない値の数を数えるとしています。売上の列に空欄があると、その行は件数に入りません。行の数そのものを数えたいときはsizeを使います。
週ごとや年ごとにまとめることもできますか?
できます。to_periodに渡す頻度の文字を変えます。この記事では月ごとの"M"を使いました。どの文字が使えるかは、pandasの資料の期間の別名(period aliases)の一覧で確かめます。
毎月20日締めのように、暦の月と違う区切りで集計できますか?
to_period("M")は、暦の月(1日から月末まで)でまとめます。締め日で区切る場合は、日付を締め日に合わせてずらしてからまとめるなど、別の作りが要ります。締め日の決まりは会社ごとに違うので、経理の担当の人と区切り方を確かめてから作ります。