【Pandasデータ操作】条件に応じて値を置換!where()とmask()を徹底解説


 

データ分析において、「特定の条件を満たす値だけを別の値に置き換えたい」というニーズは頻繁に発生します。例えば、売上データでマイナス値をゼロに修正したり、特定のカテゴリに該当する顧客の情報を匿名化したりするケースです。Pandasは、このような条件に基づいた値の置換を効率的に行うための強力なメソッドとして、**where()mask()**を提供しています。

この記事では、これら2つのメソッドの基本的な使い方から、それぞれの違い、そして知っておくと便利な応用例まで、短いサンプルコードと丁寧な解説を交えてご紹介します。


 

条件に応じた値の置換とは?なぜ必要なのか?

 

条件に応じた値の置換は、データのクレンジングや整形、特定の値のハイライトなど、多岐にわたるデータ操作において不可欠なプロセスです。

なぜこのような置換が必要なのでしょうか?

  • データクレンジング: 不正な値や異常値を修正し、データの品質を向上させます。

    • 例: 負の売上値を0に、ありえない年齢をNaNに変換する。

  • 特徴量エンジニアリング: 特定の条件に基づいて新しい特徴量を作成したり、既存の特徴量を加工したりします。

    • 例: 特定のスコア以下の生徒を「低成績」カテゴリに分類する。

  • データの匿名化・秘匿化: 機密性の高い情報を条件に基づいて置き換え、プライバシーを保護します。

    • 例: 特定の条件を満たすユーザーの個人情報を「非公開」に置換する。

  • 分析の準備: 欠損値の扱い方を調整したり、特定の値を分析から除外したりするために使用します。


 

where()メソッド:条件がFalseの場所を置換

 

where()メソッドは、指定した条件がFalseである要素を、別の値で置換します。条件がTrueである要素はそのまま残ります。

 

基本的な使い方

 

Python
 
import pandas as pd
import numpy as np

# サンプルDataFrameの作成
df = pd.DataFrame({
    '商品': ['A', 'B', 'C', 'D'],
    '売上': [100, -50, 200, -10],
    '在庫': [5, 0, 15, 3]
})
print("オリジナルDataFrame:\n", df)

# 売上がマイナスの場合、0に置換
# 条件: df['売上'] > 0 (Trueならそのまま、Falseなら置換)
df_sales_corrected = df['売上'].where(df['売上'] > 0, 0)
print("\n売上マイナス値を0に置換後:\n", df_sales_corrected)

# DataFrame全体に適用する場合
df_corrected_all = df.where(df > 0, 0)
print("\nDataFrame全体で0より小さい値を0に置換後:\n", df_corrected_all)

解説:

  1. df['売上'].where(df['売上'] > 0, 0): '売上'列の各要素に対し、df['売上'] > 0という条件を評価します。

    • 条件がTrue(値が0より大きい)の場合、元の'売上'の値をそのまま維持します。

    • 条件がFalse(値が0以下)の場合、指定した置換値0で置き換えます。

  2. DataFrame全体に適用する場合も同様に、各要素に対して条件が評価されます。数値列以外にはNaNが適用される点に注意してください。


 

mask()メソッド:条件がTrueの場所を置換

 

mask()メソッドは、where()とは逆に、指定した条件がTrueである要素を、別の値で置換します。条件がFalseである要素はそのまま残ります。

 

基本的な使い方

 

Python
 
# 在庫が0の場合、NaNに置換
# 条件: df['在庫'] == 0 (Trueなら置換、Falseならそのまま)
df_stock_masked = df['在庫'].mask(df['在庫'] == 0, np.nan)
print("\n在庫0をNaNに置換後:\n", df_stock_masked)

# 商品が'A'の場合、価格を999に置換
df_item_masked = df.mask(df['商品'] == 'A', 999)
print("\n商品Aの行を999に置換後:\n", df_item_masked)

解説:

  1. df['在庫'].mask(df['在庫'] == 0, np.nan): '在庫'列の各要素に対し、df['在庫'] == 0という条件を評価します。

    • 条件がTrue(値が0)の場合、指定した置換値np.nanで置き換えます。

    • 条件がFalse(値が0でない)の場合、元の'在庫'の値をそのまま維持します。

  2. DataFrame全体に適用する場合も同様です。この例ではdf['商品'] == 'A'Trueとなる行全体が999に置換されています。


 

where()mask()の使い分け

 

where()mask()は互いに逆の動作をするため、どちらを使うかは「何を保持したいか」によって選びます。

  • where(): 「この条件を満たすものだけを残し、他を置換したい」場合に便利です。

    • (条件がTrueのものを残す)

    • 例: df.where(df['売上'] > 0, 0) -> 売上が正の値のものを残し、それ以外を0に。

  • mask(): 「この条件を満たすものだけを置換し、他は残したい」場合に便利です。

    • (条件がTrueのものを置換する)

    • 例: df.mask(df['売上'] < 0, 0) -> 売上が負の値のものを0に置換し、他はそのまま。

どちらも同じ結果を得られることが多いですが、コードの意図がより明確になる方を選ぶと良いでしょう。


 

その他の応用例

 

 

複数条件での置換

 

複数の条件を組み合わせて値を置換することも可能です。

Python
 
# 売上が0以下かつ在庫が5未満の場合、その売上をNaNに置換
df_complex_cond = df['売上'].where(~((df['売上'] <= 0) & (df['在庫'] < 5)), np.nan)
# または maskを使って
# df_complex_cond = df['売上'].mask((df['売上'] <= 0) & (df['在庫'] < 5), np.nan)
print("\n複雑な条件で売上をNaNに置換後:\n", df_complex_cond)

解説:

&(AND)や|(OR)、~(NOT)などの論理演算子を使って複数の条件を組み合わせることができます。

 

置換値に別の列の値やNaNを指定する

 

置換する値を固定値だけでなく、別の列の値や、Pandasの標準欠損値であるnp.nanなどを指定することもよくあります。

Python
 
# 在庫が0の場合、売上をNaNに置換
df_nan_replace = df.mask(df['在庫'] == 0, np.nan)
print("\n在庫0の行をNaNでマスク後:\n", df_nan_replace)

解説:

DataFrame全体にmaskを適用し、df[‘在庫’] == 0の条件がTrueの行全体がnp.nanで埋められます。元のデータ型によっては型変換が発生することがあります。


 

まとめ

 

Pandasのwhere()mask()メソッドは、DataFrameやSeriesの要素を特定の条件に基づいて効率的に置換するための強力なツールです。where()は条件がFalseの要素を、mask()は条件がTrueの要素を置換するという、互いに逆の役割を持ちます。

これらのメソッドを使いこなすことで、データクレンジング、特徴量エンジニアリング、そしてデータの匿名化など、様々なデータ前処理のタスクを柔軟かつ簡潔に記述できます。適切なメソッドを選択し、あなたのデータ分析ワークフローをさらに効率的かつ堅牢なものにしていきましょう。