pandas の where と mask で条件付きの値置換をする

条件に応じて値を書き換えたいとき、apply でラムダ式を書くことが多いかもしれません。しかし pandas には where と mask という専用メソッドがあり、ベクトル化された処理で高速に条件付きの値置換ができます。

where の基本

where は「条件を満たす値はそのまま残し、満たさない値を指定した値に置換する」メソッドです。

import pandas as pd

df = pd.DataFrame({
    "name": ["Alice", "Bob", "Charlie", "Diana"],
    "score": [85, 42, 73, 91]
})

df["result"] = df["score"].where(df["score"] >= 60, "不合格")
print(df)

60 点以上のスコアはそのまま残り、60 点未満の値は「不合格」に置き換わります。SQL の CASE WHEN に近い感覚で使えるメソッドです。

mask の基本

mask は where の逆で、「条件を満たす値を置換し、満たさない値はそのまま残す」という動作をします。

df["masked"] = df["score"].mask(df["score"] < 60, 0)
print(df)

この例では 60 点未満のスコアが 0 に置き換えられ、60 点以上の値はそのまま残ります。

where(条件, 置換値)

条件が True の値を残し、False の値を置換する

mask(条件, 置換値)

条件が True の値を置換し、False の値を残す

DataFrame 全体に適用する

where と mask は Series だけでなく DataFrame 全体にも適用できます。

df_num = pd.DataFrame({
    "math": [85, 42, 73],
    "english": [91, 58, 65],
    "science": [76, 38, 82]
})

result = df_num.where(df_num >= 60, "×")
print(result)

60 点未満のセルがすべて「×」に置き換わります。一括で条件判定できるため、ループを書く必要がありません。

NumPy の where との使い分け

より複雑な条件分岐が必要な場合は、NumPy の np.where も選択肢に入ります。

import numpy as np

df["grade"] = np.where(df["score"] >= 80, "A",
              np.where(df["score"] >= 60, "B", "C"))

np.where はネストすることで 3 段階以上の分岐が書けます。ただしネストが深くなると読みにくくなるため、分岐が多い場合は pd.cut やカスタム関数を検討したほうがよいでしょう。

置換値に別の列を使う

置換値として固定値ではなく、別の列や計算結果を渡すこともできます。

df["adjusted"] = df["score"].where(df["score"] >= 60, df["score"] + 20)

条件を満たさないスコアに 20 点を加算する処理です。固定値だけでなく柔軟な置換ができるのが where / mask の強みと言えます。

where と mask を覚えておくと、apply でラムダ式を書く場面を減らせます。ベクトル化された処理なのでパフォーマンスも良好であり、大きなデータセットほど差が出てきます。