Pandas DataFrameの値を条件検索して書き換える方法色々 ~ mask/where/replace【python/データ加工】
目次
こんにちは。
普段pandasでデータ処理を行うことが多いのですが、「意外と知らないメソッドが多く活用しきれていないかも?」ということで、よく使う重要テクニックをまとめています。
今回は「データフレームのある条件にマッチした行の値を書き換えたい!」といったニーズに答える方法をいくつかご紹介します。
どれも似たようなことが実現できるので、場合によって使い分けられるようになりたいところです。
やりたいこと ~ データフレームの値を条件検索して書き換えたい
データはこのブログでも頻出のペンギンデータセットを使います。
df = pd.read_csv('../data/palmerpenguins/penguins_raw.csv')
df = df[['Sample Number','Species','Sex']]
中身はこんなデータです。

.mask(検索条件,置換後の値)
試しにSex
列のMALE
をM
に書き換えたいと思います。
df.Sex.mask(df.Sex == 'MALE', 'M')

おお、すごい。一発。
df.Sex=='MALE'
の部分でMALEがTrue
になるpd.Series
ができ、Trueの部分がM
に置き換わるんですね。
ちなみに、df.Sex.mask()
ではなくdf.mask()
としてデータフレームにmaskメソッドをかけると、置換したい列以外のすべての列の値がM
に置き換わってしまうので、注意です。
以降同じですが、上書きしたい場合は変数に代入しましょう。上記のコードを実行しただけでは上書きされず、「メソッドを適用した中身を表示」しただけです。
df.Sex = df.Sex.mask(df.Sex == 'MALE', 'M') # 列を上書き
df['Sex2'] = df.Sex.mask(df.Sex == 'MALE', 'M') # 別の列を作成して結果を保持
.where(検索条件,値)
今度はNaN以外の値をAny
に置き換えてみます。
df.Sex.where(df.Sex.isnull(),'Any')

SQLのwhere文と比較すると、なんとなく感覚と動作が逆ですね。whereで指定した条件は残して、それ以外をAnyに変えたような感じです。
つまりmask
と逆の動作をしているので、以下のコードでも同じことができます。
df.Sex.mask(~df.Sex.isnull(),'Any')
.replace(検索値,置換後)
同じ列内である1つの値を置き換えるのが目的なら、replace
も使えます。限定的ですが、シンプル。
df.Sex.replace('MALE','M')

ちなみに文字列str
のメソッドを使うと、完全一致でない部分一致の文字列も置換されます。
df.Sex.str.replace('MALE','M') # strをつけた場合
このように、FEMALE
という文字列中のMALE
も置換対象になり、FEM
になってしまいます。

df.replace
のように列を指定しないで使った場合、データフレーム全体で値を置き換えることができます。この場合も上と同様に、完全一致しないと置き換わりません。また、df.str.
のような使い方は、文字列でないと使えないので、文字列以外のデータが入っているとエラーになります。
whereとmaskの使いどころ
replace
と比べてwhere
とmask
の便利なところは、置き換えたい文字列以外でも検索できることです。
たとえば、性別がMALE
の列のSpecies
をオスペンギン
としたい場合。

このように検索する列と異なる別の列の値にアクセスが一発でできるので便利です。
データフレームの値を上書きで置き換える場合は、SettingWithCopyWarningの警告に注意
ちなみに、データフレームの一部に対して値を上書きで入れようとすると、SettingWithCopyWarning
という警告が出ます。
このようにデータフレームのから条件に一致する行を選択し、値を代入しようとすると...
df2 = df[df['Sex']=='MALE']
df2['Species'] = 'M'
Warning(警告文)が出ます。
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
self._setitem_single_column(loc, value, pi)
これはdf2
がdf
に対するView(のぞき穴のような状態)になっていて、「今、列全部に値を代入しようとしてるけど、View外の値に対してはどうすんねん」、っていうような警告だと捉えればよいです。(たぶん。)
特に致命的な問題ではなく、必要な結果が得られることがほとんどだと思います。が、警告が出るとあまり気持ちが良くないので、上記のmask
やwhere
などの方法で書き換えて警告を回避しましょう。
まとめ
というわけで今回は「データフレームの中で、ある条件にマッチした行の値を書き換えたい!」という場合に使えるメソッドを3つ紹介しました。
df['列名'].mask(条件、値)
- 条件に一致する行のデータを値に置き換える
df['列名'].where(条件、値)
- 条件に一致しない行のデータを値を置き換える
df['列名'].replace(値1、値2)
- 値1に完全一致するデータを値2に置き換える
- 数値でも使える
df['列名'].str.replace(文字列1、文字列2)
- 文字列1を文字列2に置き換える
- 部分一致でも置き換わる
- 文字列にしか使えない
mask
, where
の条件にはbool値の入ったpd.Series
であればよいので、.isnull()
や条件式( ==
,>
,<
,!=
など)と組み合せて使うことができます。
参考
私がPythonの学習に使用している本はこちらです。基礎から体系的に学習したい方におすすめです。
Pythonデータサイエンスハンドブック ―Jupyter、NumPy、pandas、Matplotlib、scikit-learnを使ったデータ分析、機械学習 単行本(ソフトカバー) –pandasの章のあとには機械学習や可視化の方法もまとめてあり、データサイエンスのスキルが幅広く習得できるようになっています。