この記事でわかること

  • 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を付け、結果は新しいファイルに保存して元の表を残します