Pandas DataFrameの値を条件検索して書き換える方法色々 ~ mask/where/replace【python/データ加工】

2021-12-25
Main Image

目次

こんにちは。

普段pandasでデータ処理を行うことが多いのですが、「意外と知らないメソッドが多く活用しきれていないかも?」ということで、よく使う重要テクニックをまとめています。

今回は「データフレームのある条件にマッチした行の値を書き換えたい!」といったニーズに答える方法をいくつかご紹介します。

どれも似たようなことが実現できるので、場合によって使い分けられるようになりたいところです。

やりたいこと ~ データフレームの値を条件検索して書き換えたい

データはこのブログでも頻出のペンギンデータセットを使います。

ペンギンデータセットのダウンロード

df = pd.read_csv('../data/palmerpenguins/penguins_raw.csv')
df = df[['Sample Number','Species','Sex']]

中身はこんなデータです。

.mask(検索条件,置換後の値)

試しにSex列のMALEMに書き換えたいと思います。

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と比べてwheremaskの便利なところは、置き換えたい文字列以外でも検索できることです。

たとえば、性別が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)

これはdf2dfに対するView(のぞき穴のような状態)になっていて、「今、列全部に値を代入しようとしてるけど、View外の値に対してはどうすんねん」、っていうような警告だと捉えればよいです。(たぶん。)

特に致命的な問題ではなく、必要な結果が得られることがほとんどだと思います。が、警告が出るとあまり気持ちが良くないので、上記のmaskwhereなどの方法で書き換えて警告を回避しましょう。

まとめ

というわけで今回は「データフレームの中で、ある条件にマッチした行の値を書き換えたい!」という場合に使えるメソッドを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の章のあとには機械学習や可視化の方法もまとめてあり、データサイエンスのスキルが幅広く習得できるようになっています。

ads【オススメ】未経験からプログラマーへ転職できる【GEEK JOBキャンプ】
▼ Amazonオススメ商品
ディスプレイライト デスクライト BenQ ScreenBar モニター掛け式
スマートLEDフロアライト 間接照明 Alexa/Google Home対応

Author

Penta

都内で働くITエンジニアもどき。好きなものは音楽・健康・貯金・シンプルでミニマルな暮らし。AWSクラウドやデータサイエンスを勉強中。学んだことや体験談をのんびり書いてます。TypeScript / Next.js / React / Python / AWS / インデックス投資 / 高配当株投資 More profile

Location : Tokyo, JPN

Contact : Twitter@penguinchord

Recommended Posts

Copy Right / Penguin Chord, ペンギンコード (penguinchord.com) 2022 / Twitter@penguinchord