PythonでExcelの数値を区切って範囲ごとの件数を数える手順|pandasのcutで金額を分ける
Excelの表の金額のような数値を「1,000円未満」のような範囲に区切り、範囲ごとの件数を数える手順を、Pythonのpandasのcutと公式の資料をもとに解説します。区切りの端の扱いと、範囲の外の値の見つけ方も紹介します。
本記事はプロモーションを含みます。紹介する情報は、実際の成果や効果を保証するものではありません。
目次
この記事でわかること
- Excelの表の金額のような数値を、決めた区切りで範囲に分ける方法(pandasのcut)
- 区切りの値ちょうどの数が、どちらの範囲に入るかの決め方
- 範囲ごとの件数を、範囲の順に数える方法
- 範囲の外の値や空欄に気づき、結果を別のExcelのファイルに保存する手順
注文や売上の表で、「1,000円未満が何件、1,000〜5,000円未満が何件」のように、金額の範囲ごとに件数を数えたいことがあります。Excelでは範囲ごとに条件を書いて数えますが、範囲が増えると式も増えます。ここでは、Pythonのpandasで数値の列を範囲に区切り、範囲ごとの件数を数える手順を、架空の注文の表で動かした結果とあわせて紹介します。
根拠にしたのは、pandasの公式の資料(3.1.0の版のAPIリファレンスと、表の形を変える操作のユーザーガイド)で、2026年10月27日に原文で読みました。表は架空のもので、実在の店や人の数字は使っていません。
先に結論: 区切りと範囲の名前を決めて、cutで分けてから数える
先に結論を書くと、区切りの値と範囲の名前を先に決め、cutで金額の列に範囲を付けてから、value_counts(sort=False)で範囲の順に件数を数えます。 区切りの値ちょうどの数がどちらに入るかは、rightで決めます。この記事で使う指定と関数は、次の4つです。
| 指定・関数 | 働き |
|---|---|
| cut | 数値を範囲に分ける |
| right=False | 左の端を含める |
| value_counts | 範囲ごとに数える |
| isna | 範囲の外を探す |
cutで数値を範囲に分けるしくみ
cutは、値を区切りで分けた範囲に割り当てる働きをします。pandasの資料では、値を区切って並べたいときに使い、たとえば年齢を年齢の範囲のまとまりに変えられるとしています。
区切り(bins)には、区切りの値を並べたものか、整数を渡します。値を並べると、その値が範囲の境目になり、範囲の広さはそろっていなくてもかまいません。範囲の名前は、labelsに範囲と同じ数だけ並べて渡します。
区切りの値ちょうどの数の扱い(rightとinclude_lowest)
範囲の端の値がどちらに入るかは、rightで決まります。資料によると、初期の設定のright=Trueでは、区切り[1, 2, 3, 4]は「1より大きく2以下」「2より大きく3以下」「3より大きく4以下」の範囲になり、右の端を含みます。
「1,000円未満」「1,000〜5,000円未満」のように、左の端を含めて右の端を含めない範囲にしたいときは、right=Falseを付けます。
右の端を含める設定のままだと、いちばん小さい区切りと同じ値は、どの範囲にも入りません。資料では、include_lowest=Trueを付けると、最初の区切りと同じ値も最初の範囲に入るとしています。
範囲の外の値と空欄はNAになる
資料によると、元の値が空欄(NA)なら結果も空欄になり、区切りの範囲の外にある値は、どの範囲にも割り当てられず、空欄になります。マイナスの金額(返品など)や、いちばん大きい区切りを超える金額があると、件数から黙って外れます。
範囲ごとに数えるvalue_countsは、資料によると、初期の設定では空欄を数えません。そのため、範囲ごとの件数を合わせても、表の行数と合わないことがあります。記事のコードでは、isnaで範囲の外の行を数えて、先に表示しています。
手順: 注文の金額を範囲に分けて件数を数える
次のコードは、架空の注文の表 orders.xlsx(注文番号・金額の2列)を読み込み、金額を4つの範囲に分けて、範囲ごとの件数を数えます。範囲を足した明細と件数は、orders_ranges.xlsxという別のファイルの2つのシートに書き出し、元のorders.xlsxには手を加えません。自分の表で使うときは、列名・区切り・範囲の名前を合わせて変えてください。作業の前には、元のファイルの写しを別のフォルダーに残してください。
import pandas as pd
# 注文の表を読む(orders.xlsx 自体には書き込まない)
df = pd.read_excel("orders.xlsx")
# 区切りと範囲の名前を決める(左の端を含め、右の端は含めない)
edges = [0, 1000, 5000, 10000, float("inf")]
names = ["1,000円未満", "1,000〜5,000円未満", "5,000〜10,000円未満", "10,000円以上"]
df["金額の範囲"] = pd.cut(df["金額"], bins=edges, labels=names, right=False)
# どの範囲にも入らなかった行(空欄やマイナス)の数を表示する
print("範囲の外:", df["金額の範囲"].isna().sum(), "件")
# 範囲の順に件数を数える
counts = df["金額の範囲"].value_counts(sort=False)
print(counts)
# 範囲を足した明細と件数を、新しいファイルに書き出す
with pd.ExcelWriter("orders_ranges.xlsx") as writer:
df.to_excel(writer, sheet_name="明細", index=False)
counts.to_excel(writer, sheet_name="件数")
xlsxの読み書きにはopenpyxlを使うため、pandasと一緒に入れておきます。最後の区切りのfloat("inf")は「上限なし」の意味で、10,000円以上の金額をすべて最後の範囲に入れるために置いています。
実行した結果
架空の注文の表(9件。金額は500円・1,000円・4,999円・5,000円・9,800円・10,000円・23,000円と、空欄が1件、マイナス300円が1件)で試したところ、次のようになりました。
- 範囲の外は2件と表示され、空欄とマイナス300円の行の範囲が空欄になっていました
- 件数は「1,000円未満」1件、「1,000〜5,000円未満」2件、「5,000〜10,000円未満」2件、「10,000円以上」2件で、範囲の順に並びました
- 1,000円・5,000円・10,000円のちょうどの金額は、それぞれ左の端に含む範囲に入りました
- 保存したorders_ranges.xlsxには「明細」と「件数」の2つのシートができ、読み込んだorders.xlsxのほうは、実行の前とバイト単位で同じでした
動かしたのは、Macの作業PCの Python 3.12.15 に、pandas 3.1.0 と openpyxl 3.1.5 を入れた環境です。
自分で直すか、相談するかの判断
判断の目安は、「区切りの境目が、決まりとして決まっているか」です。社内の集計の決まりや、前回までの集計で使った境目があるなら、それに合わせて区切りを書けば、自分で進められます。
境目が決まっていないときや、境目の値ちょうどをどちらに入れるかで数が変わるときは、集計を頼んだ人に、境目と「以上・未満」の扱いを確かめてから決めます。範囲の外になった行の扱い(返品を除くかなど)も、あわせて確かめます。
つまずきやすいところ
- rightを付けずに「未満」の名前を付ける: 架空の表で、right=Falseを付けずに同じ名前を付けると、1,000円の注文が「1,000円未満」に入りました。名前と範囲の端の扱いが合っているかを確かめます
- 最初の区切りと同じ値が外れる: 初期の設定のまま区切りを0から始めると、0円の行は範囲の外になりました。include_lowest=Trueを付けると、最初の範囲に入りました
- 範囲の名前の数が合わない: 区切りが5つなら範囲は4つで、名前も4つ要ります。名前を5つ渡すと、ValueErrorで止まりました
- 件数が多い順に並ぶ: value_countsは初期の設定では件数の多い順に並べます。範囲の順に並べるときは、sort=Falseを付けます
- 2つの項目で集計したいとき: 範囲と担当者のように、2つの項目で件数をまとめる方法は、PythonでExcelのピボットテーブルのように集計する手順で紹介しています
- 金額の大きい順に一覧にしたいとき: 範囲ではなく、金額の上位だけを取り出す手順は、PythonでExcelの表を並べ替えて上位の行を取り出す手順にあります。空欄がどこにあるかを先に一覧にする方法は、PythonでExcelの表の空欄を見つけて一覧にする手順が参考になります
- 数える前に空欄を埋めておきたいとき: 範囲に分ける前に、空欄の意味が決まっている列を埋めておく方法は、PythonでExcelの表の空欄を決めた値で埋める手順にまとめています
まとめ
- 数値を範囲に分けるときは、区切りと範囲の名前を決めて、pandasのcutに渡します
- 「以上・未満」の範囲にするときは、right=Falseを付けます。最初の区切りと同じ値を含めるときは、include_lowest=Trueを使います
- 範囲の外の値と空欄はNAになり、value_countsでは数えられないので、isnaで先に数えます
- 範囲の順に数えるときはsort=Falseを付け、結果は新しいファイルに保存して元の表を残します
よくある質問
区切りの値ちょうどの数は、どちらの範囲に入りますか?
初期の設定(right=True)では、右の端を含み、左の端を含みません。区切りを[0, 1000, 5000]にすると、1,000は「0より大きく1,000以下」の範囲に入ります。right=Falseにすると、左の端を含み、右の端を含まない範囲になり、1,000は「1,000以上5,000未満」に入ります。
いちばん小さい区切りと同じ値が、空欄になるのはなぜですか?
初期の設定では、いちばん左の端は範囲に含まれないためです。pandasの資料では、include_lowest=Trueを付けると、最初の区切りと同じ値も最初の範囲に入るとしています。架空のデータでも、0円の行は、include_lowestを付けると最初の範囲に入りました。
区切りを決めずに、数だけ指定することはできますか?
できます。binsに整数を渡すと、値の幅を同じ広さで分けます。資料によると、そのときは最小と最大の値が入るように、範囲を両側に0.1%広げます。金額の区切りのように決まった境目があるときは、区切りの値を並べて渡す方が、結果を読みやすくなります。
範囲ごとの件数が、表の行数より少ないのはなぜですか?
範囲の外の値と空欄が、どの範囲にも入らず、空欄(NA)になるためです。value_countsは、初期の設定では空欄を数えません。記事のコードでは、範囲の外の件数を先に表示して気づけるようにしています。
範囲を足すと、元のExcelのファイルも変わりますか?
変わりません。記事のコードは元のファイルを読み込むだけで、範囲を足した表と件数は別の名前のファイルに書き出します。架空の表で試したときも、元のorders.xlsxの中身はそのままでした。