PythonでExcelの複数の条件から区分の列を作る手順|numpy.selectでIFの入れ子をやめる
Pythonのnumpy.selectで、Excelの表の金額と地域のような複数の条件から「最優先」「優先」「通常」などの区分の列を作る手順を解説します。条件の順番を間違えたときの結果や、エラーになる書き方も、架空の注文の表で試して紹介します。
目次
この記事でわかること
- 複数の列の条件から、区分の列を1回で作る方法(numpy.select)
- 条件を並べる順番で結果が変わる理由と、並べ方の決まり
- defaultを書き忘れたときや、&のまわりに括弧がないときのエラー
- 金額が空の行の扱いと、自分の表で使う前に確かめること
「金額が10万円以上で東京なら最優先、10万円以上なら優先、5万円以上なら通常」のような区分を、ExcelのIFを何重にも入れ子にした式で付けていませんか。条件が増えるたびに式が読みにくくなります。この記事では、条件とラベルを上から順に並べて、numpy.selectで区分の列を作る手順を紹介します。
拠り所は、NumPy 2.5のnumpy.selectの説明と、pandas 3.1.0のユーザーガイドのデータの選び方の章です。どちらも2026年10月31日に原文を開いて確かめました。使った注文の表は、説明のためにこしらえた架空のデータです。
先に結論: 条件は細かいものから順に並べる
条件のリストとラベルのリストを同じ順に並べ、numpy.selectに渡します。 1つの行が複数の条件に当たるときは、リストの前にある条件の区分になります。そのため、細かい条件ほど上に書きます。
| 順番 | 条件 | 区分 |
|---|---|---|
| 1 | 10万円以上かつ東京 | 最優先 |
| 2 | 10万円以上 | 優先 |
| 3 | 5万円以上 | 通常 |
| どれでもない | (default) | 対象外 |
numpy.selectのしくみ
numpy.selectは、条件の並び(condlist)に応じて、選ぶ値の並び(choicelist)から値を取り出した配列を返します。NumPyの資料では、複数の条件が満たされるときは、condlistで最初に出てくる条件が使われると説明しています。
choicelistは、condlistと同じ長さにします。どの条件も偽だった行には、defaultに渡した値が入ります。
pandasのユーザーガイドにも、新しい列を条件で作る例があります。2つの中から選ぶならnumpy.where、条件が複数あるならnumpy.selectを使えるとしています。
手順: 金額と地域から区分の列を作る
次のコードは、架空の注文の表 orders.xlsx の「金額」と「地域」から「区分」の列を作り、orders_labeled.xlsx という別の名前で保存します。読み込んだ orders.xlsx には書き込みません。
import numpy as np
import pandas as pd
# orders.xlsx を読み込む。結果は別の名前のファイルに書き出す
orders = pd.read_excel("orders.xlsx")
# 条件は上から順に判定する(先に当たった区分になる)
conditions = [
(orders["金額"] >= 100000) & (orders["地域"] == "東京"),
orders["金額"] >= 100000,
orders["金額"] >= 50000,
]
labels = ["最優先", "優先", "通常"]
orders["区分"] = np.select(conditions, labels, default="対象外")
print(orders["区分"].value_counts())
print("金額が空の行:", orders["金額"].isna().sum())
orders.to_excel("orders_labeled.xlsx", index=False)
numpyはpandasと一緒に入ります。xlsxの読み書きにはopenpyxlも要ります。金額のしきい値や地域の名前は、自分の表の決まりに合わせて書き換えます。
試した結果
注文が6行だけの作り物の表で動かしました。地域と金額は、東京・12万円、大阪・15万円、東京・3万円、福岡・8万円、大阪・空欄、東京・6万円です。
- 区分は上から順に、最優先・優先・対象外・通常・対象外・通常になりました
- 大阪の15万円は「10万円以上かつ東京」に当たらず、2番目の「優先」になりました
- 金額が空欄の大阪の行は、3万円の行と同じ「対象外」で、「金額が空の行: 1」と表示されました
- 実行の前と後で orders.xlsx のハッシュ値を比べ、同じであることを確かめました
使ったのは、作業PC(Mac)のPython 3.12.15と、numpy 2.5.4・pandas 3.1.0・openpyxl 3.1.5です。書き出したファイルをExcelのアプリで開いて見てはいません。
自分で直すか、相談するかの判断
目安は、「区分の決まりを、上から順に当てはめる表にできるか」です。結論の表のように、順番・条件・区分を書き出せるなら、そのままコードの2つのリストになります。
決まりが部署の慣習で決まっていて、例外が多い場合は、先に決まりの表を作るところから始まります。どの順番で判定するかは、区分を使う人と表を見ながら決めます。決めた後は、区分ごとの件数を数えて、思ったとおりに分かれたかを確かめます。
つまずきやすいところ
- 広い条件を先に書く: 試したときも、「5万円以上」を先頭に置くと、12万円と15万円の行まで「通常」になりました。細かい条件ほど上に書きます
- defaultを書き忘れる: defaultは省くと0です。ラベルが文字のときに省くと、試したときは「Choicelist and default value do not have a common dtype」というTypeErrorで止まりました。文字のラベルなら、defaultにも文字を渡します
- &のまわりの括弧を省く: pandasのユーザーガイドでは、&・|・~ で条件をつなぐときは括弧でまとめる必要があるとしています。括弧なしで書くと、試したときもTypeErrorになりました
- 金額の範囲だけで区分を付けたい: 条件が1つの列の数値の範囲だけなら、PythonでExcelの数値を区切って範囲ごとの件数を数える手順のpd.cutのほうが短く書けます
- 区分を付けずに行を取り出したい: 条件に合う行だけを残す方法は、PythonでExcelの表から条件に合う行を抽出する手順で紹介しています
- 区分ごとに集計したい: 作った区分の列で件数や金額をまとめる方法は、PythonでExcelのピボットテーブルのように集計する手順にまとめています
まとめ
- 条件のリストとラベルのリストを同じ順に並べ、numpy.selectに渡します
- 複数の条件に当たる行は前の条件の区分になるので、細かい条件から書きます
- 文字のラベルなら、defaultにも文字を渡します
- &でつなぐ条件は、1つずつ括弧で囲みます
よくある質問
2つの条件のどちらにも当たる行は、どの区分になりますか?
リストの前にある条件の区分になります。NumPyの資料でも、複数の条件が満たされるときは、condlistで最初に出てくるものが使われるとしています。細かい条件ほど上に置きます。
区分が2つだけのときも、numpy.selectを使いますか?
「当たれば A、外れれば B」の2つなら、numpy.whereで足ります。pandasのユーザーガイドでも、2つの中から選ぶ例をnumpy.whereで、条件が複数ある場合をnumpy.selectで示しています。
「東京または大阪」のように、どちらかに当たればよい条件は書けますか?
|でつなぎます。pandasのユーザーガイドでは、|が「または」、&が「かつ」、~が「否定」を表すとしています。&と同じく、つなぐ条件は1つずつ括弧で囲みます。
条件とラベルの数が合わないと、どうなりますか?
そろえて書く必要があります。資料では、choicelistはcondlistと同じ長さでなければならないとしています。条件を1つ足したら、ラベルも同じ位置に1つ足します。
金額が空の行は、どの区分になりますか?
空の値との比較は当たらないため、どの条件にも当たらず、defaultの区分になります。試した表でも、金額が空の行は「対象外」になりました。小さい金額の行と見分けたいときは、空の行を数えるか、空を判定する条件を先頭に置きます。