kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

Pandas で NaN を操作する : fillna() と interpolate()

先週紹介した学習コンテンツKaggle Courses : Pandas「欠損値 (Missing data) : NaN」の取り扱いを学んだけど,その後「Pandas ライブラリ活用入門」を読んでいたら「置換 : fillna() 関数」に多くのパラメータがあり,他にも「補間 : interoperete() 関数」という選択肢も載っていた.本書やドキュメントを読みながら,気になった機能を試していく💪

データセット 📈

今回の検証では,本書と同じく GitHub リポジトリ chendaniely/pandas_for_everyone に含まれているデータセット country_timeseries.csv を使う.「エボラ出血熱の発生数と死者数を国別にまとめたデータセット」となり,以下の通り,NaN を多く含んでいる(赤く強調しておいた🖍).なお,今回は結果を単純化するため以下の「5カラム」に限定して載せる.

  • Date : 日付
  • Cases_Guinea : ギニア(発生数)
  • Cases_Liberia : リベリア共和国(発生数)
  • Deaths_Guinea : ギニア(死者数)
  • Deaths_Liberia : リベリア共和国(死者数)
ebola = pd.read_csv('./country_timeseries.csv')
ebola.loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415152636p:plain

1. 置換 : fillna() 関数 📈

pandas.pydata.org

1-1. fillna(0)

まず,fillna() 関数を使うと簡単に NaN を置換できる.例えば,以下のように fillna(0) と実装すると全て 0.0 になる(NaN 以外は黄色く強調しておいた🖍).

ebola.fillna(0).loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415153231p:plain

1-2. fillna(ebola.mean()) / fillna(ebola.median())

とは言え,実践的に使う場合は 0.0 よりも具体的な値で置換することが多いと思う.例えば「平均値 : mean() 関数」「中央値 : median() 関数」と組み合わせると,DataFrame から算出した統計値で置換することもできる.

ebola.fillna(ebola.mean()).loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)
ebola.fillna(ebola.median()).loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415153336p:plain

1-3. fillna(method='pad') / fillna(method='backfill')

また fillna() 関数に method パラメータを指定すると「前の値で置換 : method='pad' もしくは method='ffill'したり「後の値で置換 : method='backfill' もしくは method='bfill'できる.「前の値で置換」をする場合,最初から NaN になっている部分は置換の対象外となり,実際に以下の例でも NaN が残っている.

ebola.fillna(method='pad').loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)
ebola.fillna(method='backfill').loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415152803p:plain

2. 補間 : interoperete() 関数 📈

Pandas では,特定の値で「置換」するだけではなく,DataFrame から近似した値で「補間」する方法もあり interoperete() 関数を使う.

pandas.pydata.org

2-1. interpolate()

まず,デフォルト設定のまま interoperete() 関数を使うと以下のようになる.カラムの値ごとに「線形的に」補間する.NaN 前後の値で補間をするため,最初から NaN になっている部分は補間の対象外となり,実際に以下の例でも NaN が残っている.

ebola.interpolate().loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415154042p:plain

2-2. interpolate(limit_direction='both')

次に interpolate() 関数で limit_direction パラメータを指定すると,補間する方向として forwardbackwardboth を指定できる.例えば limit_direction='both' のように指定すると,どちらの方向もサポートすることになり,全ての NaN を補間できるようになる.

ebola.interpolate(limit_direction='both').loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415153108p:plain

2-3. interpolate(limit_direction='both')

最後は method パラメータで,デフォルトでは「線形(カラム値を等間隔に補間): linearとなる.選択肢は他にもあり,例えば「インデックス(インデックス値をベースに補間): indexなど.もし index を指定する場合はインデックス値が数値型である必要がある.

ebola.interpolate(method='index').loc[:, ['Date','Cases_Guinea', 'Cases_Liberia', 'Deaths_Guinea', 'Deaths_Liberia']].head(10)

f:id:kakku22:20210415154322p:plain

まとめ 📈

引き続き Pandas を学んでいる.今回は「Pandas ライブラリ活用入門」を読みながら fillna() 関数と interoperete() 関数の気になった機能を試した💪パラメータは他にも多くあるため,ドキュメントも読みながらより理解を深めていく💡

Pandas 関連記事 📈

kakakakakku.hatenablog.com