groupby後に合計が減ったら、まず「集計キーが空欄の行」を調べます。ただし、dropna=Falseで合計が一致しても、金額の未入力まで解決したとは限りません。 行数、入力済み金額の件数、分かっている金額の小計を、別々に照合しましょう。

対象は、CSVを読み込んで部署別・月別の集計を作り始めた人です。Pythonの変数と表の列を選ぶ操作が分かれば進められます。機械学習モデルの知識は不要です。売上や請求の確定処理ではなく、小さな練習データで集計の仕組みを理解する記事です。

公式資料確認日:2026年10月5日。教材は編集部が作成した架空の8行です。実行確認環境はPythonとpandas 2.2.3で、参照した現行公式ドキュメントはpandas 3.0.6です。バージョン間で既定値が異なる箇所があるため、本稿では重要な引数を明示します。

合計の差を「消えた行」と「不明な金額」に分ける

集計前に、何を一件として数えるか決める

最初に「この表の一行は何か」を一文で書きます。本稿は、架空の備品購入記録一件を一行にした表です。同じ部署が何度出ても別の記録であり、部署名が重複していること自体は異常ではありません。集計で数えたいものは部署の種類数ではなく、元の記録の件数です。

実務のCSVには、一つの注文が商品明細ごとに分かれるものもあれば、一つの注文を一行にまとめたものもあります。その二つに同じ「件数」という見出しを付けると、計算が正しくても説明が食い違います。まず元データの粒度と、提出する表の粒度を別々に決めてください。

次に、照合する対象を固定します。日付の絞り込み、キャンセルの除外、別表との結合をすべて済ませた後なのか、読み込んだ直後なのかを記録します。集計前の合計を前日のCSVから取り、集計後を今日のCSVから取っていれば、groupbyを調べても原因は見つかりません。

作業用の元表をそのまま残し、整形後の表には別名を付けます。確認用の件数や合計も、表を変更する前に控えます。「元の値だったはず」と記憶で比べず、同じ時点のデータ同士を照合するためです。教材では8行を固定しているので、紙の足し算でも基準を作れます。

CSVの入口で文字コードやIDが変わっている場合は、先頭ゼロと文字化けの確認を先に行いましょう。集計の前に別表をつないだなら、merge後の行数の検算が別の確認工程になります。ここでは結合済みデータの問題まで一度に扱いません。

8行の教材で、キーの欠損と値の欠損を別々に見る

次の表には、部署名のない行と、金額が分からない行があります。空欄の意味を意図的に分けています。部署不明でも金額700円が確認できる記録は、小計に含められます。一方、部署Bと分かっていても金額不明なら、その金額を推定して足すことはできません。

架空の備品購入記録。金額は円、未入力はゼロではない
記録ID部署金額
R01A1,200
R02A800
R03B未入力
R04B500
R05C0
R06部署不明700
R07D未入力
R08部署不明300

入力済みの金額は6件で、その小計は3,500円です。8件すべての最終的な総額が3,500円と決まったわけではありません。R03とR07の金額が後で判明すれば、全体の金額も変わります。この段階では「入力済み6件の小計3,500円、金額未入力2件」と書くのが、表の状態に合った説明です。

部署Cの0円は入力済みの値として扱います。例えば無償の備品を記録したという教材上の設定です。「0」と「まだ分からない」を同じにしないことが、今回の重要な練習です。現実の記録で0円が妥当かどうかは、業務の定義に照らして確認します。

以下のコードを、新しいノートブックの一つのセルで実行できます。元の業務データを外部サービスへ送る必要はありません。すでに会社で定められた実行環境がある場合は、その環境の利用ルールに従ってください。

import pandas as pd

df = pd.DataFrame({
    "record_id": ["R01", "R02", "R03", "R04", "R05", "R06", "R07", "R08"],
    "department": ["A", "A", "B", "B", "C", None, "D", None],
    "amount": pd.Series([1200, 800, None, 500, 0, 700, None, 300], dtype="Float64"),
})
print(pd.__version__)
print(df)
assert len(df) == 8
assert df["record_id"].is_unique
assert df["amount"].count() == 6
assert df["amount"].sum(min_count=1) == 3500

ここでのassertは、教材の前提が変わっていないかを確かめるものです。自分のCSVにそのまま8や3,500を当てはめる用途ではありません。実務では元システムの対象期間や件数など、独立して確かめられる基準に置き換えます。

dropna=TrueとFalseを比べ、部署不明の1,000円を見つける

pandas公式のgroupbyリファレンスでは、dropnaの既定値はTrueです。集計キーに欠損がある場合、その行はグループから除外されます。Falseを指定すると、欠損キーも一つのグループとして扱えます。

教材では、部署不明のR06とR08に合計1,000円があります。この2行を集計対象から外すと、部署別の入力済み金額を足しても2,500円にしかなりません。元表の入力済み小計3,500円との差額は1,000円です。これは丸め誤差ではなく、集計対象の行が変わったことによる差です。

without_missing_key = df.groupby("department", dropna=True)["amount"].sum(min_count=1)
with_missing_key = df.groupby("department", dropna=False)["amount"].sum(min_count=1)

assert without_missing_key.sum(min_count=1) == 2500
assert with_missing_key.sum(min_count=1) == 3500
print(df.loc[df["department"].isna(), ["record_id", "amount"]])

ただし、dropna=Falseを常に正解として使うのではありません。「部署が確定した記録のみを対象にする」という報告なら、除外すること自体が仕様の場合もあります。その場合は「対象6件、部署不明2件は別表、除外分の入力済み金額1,000円」と範囲を説明します。黙って行が落ちることを防ぐのが目的です。

表示用に欠損を「部署不明」という文字へ変える方法もありますが、元表に同じ文字の正規の部署名があると混ざる可能性があります。まず欠損のまま検算し、提出用の表示にするときだけ適切な名称を決めると、計算と見せ方を切り分けられます。

空文字や空白だけの文字列は、実際の欠損値と同じとは限りません。見た目が空欄でもisnaで見つからない場合は、値の一覧や文字数を確認します。業務上意味のある空白まで一律に削らず、どの表記を未入力として扱うかを決めてから整形してください。

元データ 8行既知の小計 3,500円部署あり 6行 → 小計 2,500円金額未入力2件を含む部署不明 2行 → 小計 1,000円dropna=Trueでは集計から外れる
図は横にスクロールできます。編集部作成。元の行数と、分かっている金額の小計をそれぞれ照合します。

sizeとcountを並べると、未入力の2件が残る

合計の隣に「件数」を表示するときも、どの関数を使ったかが重要です。公式のsizeはグループ内の行数を返します。countは、対象列の欠損を除いて数えます。どちらが優れているという関係ではなく、答える質問が異なります。

部署Bには2行ありますが、金額が入力されているのはR04の1行です。したがってsizeは2、amount列のcountは1になります。部署Dは1行あるのに、金額のcountは0です。この違いを出しておけば、担当者は入力待ちの部署を探せます。

金額のcountだけを「取引件数」として報告すると、金額未入力の取引が存在しないように見えることがあります。一方、sizeだけでは、全部の金額がそろっているか分かりません。表の列名を「記録件数」「金額入力済み件数」「金額未入力件数」と具体的にすると、読む人も意味を区別できます。

集計キーを複数にするときは、どのキーの欠損が除外に関係するかも確認します。部署は入っていても月が欠けている行があれば、部署×月の集計で落ちる可能性があります。最初から複数キーに進まず、一つのキーで行数が保存されることを確かめてから列を増やすと、原因を追いやすくなります。

なお、カテゴリ型の列ではobservedの設定も結果に関わります。現行公式では3.0から既定値が変わったことが示されています。本稿の部署列はカテゴリ型へ変換していないため、その違いを教材の主因にはしていません。既存コードを別環境へ移す際は、実際のdtypeとpandasのバージョンを記録して調べてください。

min_countで全件未入力をゼロに見せない

部署Dの金額は1件とも未入力です。これを「部署Dは0円だった」と説明すると、データにない情報を足してしまいます。本稿ではsumにmin_count=1を指定し、少なくとも一つ有効な値がないグループは欠損のまま残します。

公式のGroupBy.sumは、min_countで必要な有効値数を指定できると説明しています。現行3.0系ではskipnaなどの記述にも変更があるため、「どのバージョンでも全欠損なら既定で0になる」と一括りに覚えないでください。重要なのは、期待する扱いをコードと検算で確認することです。

部署Bは一部だけ未入力なので、min_count=1の結果は500円です。これはBの確定総額ではなく、判明している一件の小計です。min_count=1を付けただけで「未入力が一つでもあればグループ全体を不明にする」動作にはなりません。その目的なら、未入力件数を条件として別の表示列を作ります。

金額を0に置き換えることが妥当なのは、業務上「空欄は取引なしを意味する」などの定義が確認できる場合です。入力が遅れているだけのデータをゼロ埋めすると、欠損を見つける手がかりも消えます。元の列を残し、補完理由と対象行を記録してから行う作業です。

CSVの欠損と重複を確認する練習では、集計前の点検を扱っています。本稿のgroupbyの確認をその後に加えると、入口で把握した欠損が、最終表でも説明できる状態になっているかを確認できます。

検算できる集計表と、引き継げる確認記録を作る

件数・既知の小計・確定可否を一つの表にする

次は教材の集計表です。既知の小計と、金額がそろった場合にだけ表示する値を別の列にしています。「確定可否」という言葉は教材内の入力状態を指し、経理上の承認や支払確定を意味しません。現実の業務では承認状態を別に管理します。

g = df.groupby("department", dropna=False, sort=True)
summary = g.agg(
    rows=("record_id", "size"),
    amount_present=("amount", "count"),
    known_subtotal=("amount", lambda s: s.sum(min_count=1)),
)
summary["amount_missing"] = summary["rows"] - summary["amount_present"]
summary["complete_total"] = summary["known_subtotal"].where(
    summary["amount_missing"].eq(0)
)
print(summary)
assert summary["rows"].sum() == len(df)
assert summary["amount_present"].sum() == df["amount"].count()
assert summary["amount_missing"].sum() == 2
assert summary["known_subtotal"].sum(min_count=1) == 3500
assert pd.isna(summary.loc["B", "complete_total"])
assert pd.isna(summary.loc["D", "known_subtotal"])
assert summary.loc["C", "complete_total"] == 0
教材の期待結果。部署不明も独立したグループとして表示
部署行数/金額入力済み既知の小計/金額の揃った値
A2/22,000円/2,000円
B2/1500円/不明
C1/10円/0円
D1/0不明/不明
部署不明2/21,000円/1,000円(部署は未確定)

部署不明の1,000円は、金額の入力だけを見ればそろっています。しかし部署別の正式な報告先は決まっていません。一つの「OK」フラグで全部を済ませず、金額の状態と所属の状態を分ける必要があります。表を渡すときは、部署不明の扱いを脚注や別の確認欄に残してください。

このコードは金額列を最初から数値型として作っています。CSVで「1,200円」などの文字が混在している場合、そのまま同じ結果になるとは限りません。数値変換で失敗した値を黙って欠損へ置き換えると、新しい未入力を作ることがあります。変換前後の失敗件数と元の文字を確認する工程を追加します。

実際の表へ移す際は、集計キーを一列増やす前に、今回の五つのグループを説明してみてください。Aは金額がすべて判明、Bは一部未入力、Cは入力済みのゼロ、Dは金額が全件未入力、部署不明は所属だけ未確定です。五つを同じ「合計」という列だけで見せると、読み手が違いを判断しにくくなります。

例えば、未入力が残る部署だけを問い合わせ用に抜き出すなら、amount_missingが0より大きい行を選びます。これは「支出が多い部署」の抽出ではありません。金額の大小ではなく、確認が終わっていない部署を探す条件です。抽出条件と表のタイトルが一致しているかも点検しましょう。

部署不明の行を追う場合は、集計後の1,000円だけを見てもR06とR08の内訳に戻れません。元表のIDを保持し、departmentが欠損の行を別に表示します。合計表は説明を短くできますが、修正する単位は元の記録です。担当者への確認には、必要な記録IDと未確定の項目を添えます。

見せる表では欠損を空欄のままにするより、「金額未入力」「所属未確定」などの説明を付けると誤読を減らせます。ただし、計算する列をその文字列で上書きすると、後続の計算が複雑になります。集計用の数値列と、表示用の文字列を分けると、検算の条件を保ちながら見せ方を変えられます。

平均を追加したくなったときも、分母を確認してください。Bの既知の小計500円を記録2件で割ると250円ですが、金額入力済み1件あたりなら500円です。どちらを求めたいかを決めずに「平均金額」と書くと、欠損をゼロとして含めたような説明になります。この教材では平均を報告せず、必要なら別の問いとして設計します。

月別の比較では、未入力の割合が月によって違うこともあります。今月の小計が低くても、今月だけ入力待ちが多いなら、支出が減ったとは判断できません。集計表の見た目をそろえるだけでなく、金額がどの程度そろっているかを同じ列で示します。今回のamount_presentとamount_missingは、その比較の前提を確認する材料になります。

小さな教材の検算を実務へ持ち込むときは、値の一致だけでなく、未解決の行を誰がいつ確認するかも決めます。未入力を残すことは作業を放置することではありません。推測で埋めずに状態を明示し、正しい情報を持つ人へ確認をつなぐための処理です。

一致した合計だけで安心せず、意図的に一行変えて試す

検算コードが一度通ったら、教材のコピーで一つの条件を変えてみましょう。例えばR06の部署をAへ変更すると、全体の入力済み小計は3,500円のまま、Aが2,700円、部署不明が300円になります。このとき全体の合計確認だけでは、部署の付け替えを検出できません。

これは確認コードの弱点ではなく、確認している対象の違いです。総額の照合は金額の出入りに気づくためのものです。部署別の分類が正しいかは、記録IDと元資料を使う別の確認が必要です。テストを増やす前に、何の誤りを見つけたいのかを言葉にしてください。

次にR03へ200円を入力したと仮定すると、Bの金額がそろい、全体の既知の小計は3,700円になります。ここでは未入力件数が2から1に減ることと、Bのcomplete_totalが700円になることを確認します。金額だけでなく、状態の変化まで合っているかを見る練習です。

逆に、行を一つ二重に追加してから集計すると、合計と行数はどちらも増えます。元表自体の重複を許したまま「集計前後で一致した」だけでは、二重計上に気づけません。教材のrecord_id.is_uniqueは、その前提を確かめています。現実のデータでIDが重複してよい仕様なら、独自の一意性条件を決め直します。

浮動小数点を含む計算では、小さな誤差を考慮する比較が必要な場合があります。ただし、先に丸めて差を隠す方法は避けましょう。本稿は整数円の小さな教材なので単純な等号で比較しています。割合や平均を扱う段階では、許容誤差と丸めるタイミングを業務の表示規則に合わせます。

担当者に渡す記録は、数値より先に対象範囲を書く

集計結果だけを送ると、翌月同じ人が同じ条件で作り直せるとは限りません。引き継ぎには「対象期間、元ファイル、対象外にした行、欠損の扱い、確認結果、未解決事項」を短く残します。個人名や取引先情報が不要なら、共有用の記録には含めないでください。

教材なら、「入力8件。部署不明2件も別グループに含めた。金額入力済み6件の小計3,500円。金額未入力2件が残る。全8件の総額は未確定」と書けます。この一段落があれば、読む人は3,500円を確定した購入総額として扱わずに済みます。

集計メモに残す項目と教材の記入例
項目記入例後で分かること
対象架空記録R01〜R08、8行どの行を集計したか
除外なし。部署不明を含む欠損キーを落としていないか
未入力R03、R07の金額照会が必要な箇所
照合行8、入力済み6、小計3,500円どの基準と一致したか
環境pandasの実行版とコード保存先再実行条件

不明な金額を問い合わせるときも、表全体を丸ごと渡すより「R03の金額欄が未入力です。入力なしが正しいか、入力待ちか確認したい」と論点を狭めます。集計担当者が推定で補うより、データの意味を知る担当者へ戻すほうが適切な場合があります。

学習の成果として見せるなら、事務職の生成AIポートフォリオで紹介した考え方を応用し、架空データ、コード、期待結果、修正した点を一組にできます。実務の売上改善や時間短縮を測っていない場合は、それらを成果として付け足しません。

集計表とメモを二人で見比べる学習場面
集計の前提を別の人に説明して確かめるイメージ(AI生成)。実在の受講生ではありません。

つまずいた箇所に合わせて、独学・社内確認・講座を選ぶ

この8行の結果を説明できるなら、すぐに講座を申し込む必要はありません。部署を月へ変える、金額ではなく数量を集計するなど、小さな条件変更で練習を続けられます。社会人のPythonデータ分析入門では、CSVから成果物を作るまでの学習順を整理しています。

一方、欠損の意味が分からない原因が業務ルールなら、Pythonの講座だけでは解決しません。入力担当者や管理者へ定義を確認する作業です。文法が理解できない、エラーの読み方が分からない、週ごとの学習が続かないといった課題とは分けて考えましょう。

今回のつまずきに合う相談・学習先
方法向いている状況先に確認すること
公式資料と小さな独学課題コードを実行でき、引数の意味を調べたい自分のpandas版と参照資料の版
社内のデータ担当者空欄や0円の業務上の意味が不明元システムの定義と対象期間
Pythonの個別指導文法・データ操作から質問しながら学びたい集計の検算まで扱うか、質問範囲

Python Winnerは、Pythonの基礎やデータ分析を学ぶ選択肢です。2026年10月5日に公式案内でコースの掲載を確認しました。具体的に今回のような欠損・集計・検算の課題を質問できるかは、受講するコースと指導範囲を確認してください。無料相談が、持ち込みコードの修正サービスという意味ではありません。

検討しやすいのは、基礎から質問しながら学びたい人です。すでにpandasを業務で使い、統計分析やモデル開発の専門指導を求める人は、別の学習先も比較してください。申込前には、受講総額、必要時間、質問対応、使用する環境を確認しましょう。費用の分割表示だけで総額を判断しないことも大切です。

PR:学習範囲を相談したい場合は 【PythonWinner】 の公式案内をご確認ください。

よくある質問と、次の集計で確認する順番

よくある質問

Q. dropna=Falseを付ければ、合計が合わない原因は全部直りますか?
A.

いいえ。欠損キーによる除外には対応できますが、読み込み時の型、対象期間、重複、結合による行の増加、金額未入力は別の問題です。同じ元表で行数・入力済み件数・小計を順に照合してください。

Q. sizeとcountはどちらを件数に使えばよいですか?
A.

記録の行数ならsize、特定列に値がある件数ならcountです。何を一件とするかを決め、表の列名にもその意味を書きます。教材では記録8件と金額入力済み6件を両方表示します。

Q. 空欄を0にしてから集計してもよいですか?
A.

空欄が0を意味すると業務上確認できた場合に限って検討します。入力待ちや不明な値を0にすると、欠損の所在と意味が失われます。元の列と変更理由を残してください。

Q. 小計が一致しているのに、部署別の表が間違うことはありますか?
A.

あります。金額を変えずに部署だけ付け替えると全体の小計は同じです。総額の照合に加えて、元の記録IDと部署の対応も確認する必要があります。

Q. pandasの版が違っても同じコードを使えますか?
A.

実行する環境で確認してください。本稿は2.2.3で検算し、現行3.0.6の公式資料も確認しています。既定値や欠損処理の説明が版によって異なるため、引数の明示と期待値の検査をセットにします。

次の集計では、まず対象の行を固定し、元の件数を控えます。続けてキーの欠損を確認し、金額の入力済み件数を数え、最後に既知の小計を照合してください。結果を渡す際は、金額がそろっていないグループと、所属が未確定のグループを区別して残します。

「数字が一致した」で作業を終えるのではなく、「どの範囲の、何が一致したか」を説明できれば、小さな集計でも再利用しやすくなります。新しい関数を増やす前に、この8行を自分の言葉で説明するところまで練習してみましょう。