ITや趣味など気軽に投稿しています。

【Pandas】データフレームの欠損値を埋める

データ分析において、欠損値(NaN/None)の処理は避けて通れない前処理のひとつです。データに欠損があると、集計や機械学習の処理に支障が出るため、適切な方法で補完する必要があります。

この記事では、Pandasのデータフレームで欠損値を補完するさまざまな方法を紹介します。

Pandasバージョン

本記事は、Pandas 2.2.3の情報を基に執筆しています。

import pandas as pd
print(pd.__version__)

>>
2.2.3

使用するデータフレーム

今回は以下の欠損値(NaNおよびNone)を含むデータフレームをサンプルとして使用します。

import pandas as pd

df = pd.DataFrame(
    data={"A":[1,3,None,None,None,11],
          "B":["dog", "cat", "monkey", None, "rabbit", None],
          "C":["a", None, "c", "d", "e", "f"],
          "D":[None,None,None,None,None,None]})

>>
      A       B     C     D
0   1.0     dog     a  None
1   3.0     cat  None  None
2   NaN  monkey     c  None
3   NaN    None     d  None
4   NaN  rabbit     e  None
5  11.0    None     f  None

データフレームの欠損を補完する手法

データフレームの欠損値を補完するには、主にfillna()メソッドを使用します。引数の指定方法を変えることで、さまざまなルールに基づいた補完が可能です。

全ての欠損を同じ値で補完

すべての欠損値を同一の値で補完する場合は、fillna()の引数に値を直接渡します。

df1 = df.copy()
# すべての欠損値を0で置換
df1 = df1.fillna(0)

>>
      A       B  C  D
0   1.0     dog  a  0
1   3.0     cat  0  0
2   0.0  monkey  c  0
3   0.0       0  d  0
4   0.0  rabbit  e  0
5  11.0       0  f  0

文字列で補完することも可能です。

df1 = df1.fillna("elephant")

>>
          A         B         C         D
0       1.0       dog         a  elephant
1       3.0       cat  elephant  elephant
2  elephant    monkey         c  elephant
3  elephant  elephant         d  elephant
4  elephant    rabbit         e  elephant
5      11.0  elephant         f  elephant

列ごとに値を指定して補完

辞書で値を指定

fillna()に辞書{列名: 補完値}を渡すことで、列ごとに異なる値で補完できます。

df2 = df.copy()
# 列ごとに値を指定して置換(辞書)
df2 = df2.fillna({"A":"lion", "B":"lion", "C":"b", "D":"b"})

>>
      A       B  C  D
0   1.0     dog  a  b
1   3.0     cat  b  b
2  lion  monkey  c  b
3  lion    lion  d  b
4  lion  rabbit  e  b
5  11.0    lion  f  b

列ごとに異なる型で補完することも可能ですが、今後のバージョンで非推奨となる見込みです。

df2 = df.copy()
df2 = df2.fillna({"A":10, "B":"lion", "C":"b", "D":5})

>>
      A       B  C  D
0   1.0     dog  a  5
1   3.0     cat  b  5
2  10.0  monkey  c  5
3  10.0    lion  d  5
4  10.0  rabbit  e  5
5  11.0    lion  f  5

FutureWarning: Downcasting object dtype arrays on .fillna, .ffill, .bfill is deprecated and will change in a future version.

Seriesで値を指定

Series形式で列ごとの補完値を指定することもできます。Seriesのインデックスが列名に対応します。

fill_series = pd.Series(["lion", "lion", "z", "z"], index=["A", "B", "C", "D"])

>>
A    lion
B    lion
C       z
D       z
dtype: object

作成したSeriesをfillna()の引数として渡します。

df2 = df.copy()
df2 = df2.fillna(fill_series)

>>
      A       B  C  D
0   1.0     dog  a  z
1   3.0     cat  z  z
2  lion  monkey  c  z
3  lion    lion  d  z
4  lion  rabbit  e  z
5  11.0    lion  f  z

統計量で補完

データフレームの統計量をfillna()に渡すことで、各列の統計量に基づいた補完が可能です。ただし、この方法は数値型の列にのみ有効です。

平均値で補完

df3 = df.copy()
# 各列の平均値で置換
df3 = df3.fillna(df.mean(numeric_only=True))

>>
      A       B     C     D
0   1.0     dog     a  None
1   3.0     cat  None  None
2   5.0  monkey     c  None
3   5.0    None     d  None
4   5.0  rabbit     e  None
5  11.0    None     f  None

最大値で補完

df3 = df.copy()
# 各列の最大値で置換
df3 = df3.fillna(df.max(numeric_only=True))

>>
      A       B     C     D
0   1.0     dog     a  None
1   3.0     cat  None  None
2  11.0  monkey     c  None
3  11.0    None     d  None
4  11.0  rabbit     e  None
5  11.0    None     f  None

上記以外にも、median()(中央値)やstd()(標準偏差)など、任意の統計量で補完できます。

前後の値で補完

欠損値の前後にある値で補完する方法です。この場合はfillna()ではなく、専用のffill()およびbfill()メソッドを使用します。

注意: fillna(method="ffill")のようにmethodパラメータで指定する方法は非推奨となっており、将来のバージョンで削除される予定です。

前の値で補完(ffill)

前方の値で欠損を補完する場合はffill()を使用します。D列のように先頭行から欠損が連続する場合は補完できません。

df4 = df.copy()
# 前の値で置換
df4 = df4.ffill()

>>
      A       B  C     D
0   1.0     dog  a  None
1   3.0     cat  a  None
2   3.0  monkey  c  None
3   3.0  monkey  d  None
4   3.0  rabbit  e  None
5  11.0  rabbit  f  None

後ろの値で補完(bfill)

後方の値で欠損を補完する場合はbfill()を使用します。D列のように末尾まで欠損が続く場合は補完できません。

df4 = df.copy()
# 後ろの値で置換
df4 = df4.bfill()

>>
      A       B  C     D
0   1.0     dog  a  None
1   3.0     cat  c  None
2  11.0  monkey  c  None
3  11.0  rabbit  d  None
4  11.0  rabbit  e  None
5  11.0    None  f  None

線形補間

欠損値の前後の値を直線で結ぶように値を補間する方法です。interpolate()メソッドを使用します。

df5 = df.copy()
# 線形補間
df5 = df5.interpolate()

>>
      A       B     C     D
0   1.0     dog     a  None
1   3.0     cat  None  None
2   5.0  monkey     c  None
3   7.0    None     d  None
4   9.0  rabbit     e  None
5  11.0    None     f  None

A列を見ると、欠損の前後の値(3.0と11.0)を等間隔で補間した値(5.0, 7.0, 9.0)に置換されています。

注意: interpolate()数値型の列にのみ有効です。文字列型の列や全欠損の列には適用されません。

線形補間ができない場合

数値型の列であっても、欠損の前後どちらか一方に値が存在しない場合は線形補間が適用されません。

  • 欠損の前に値がない場合: 補間されない(NaNのまま)
  • 欠損の後ろに値がない場合: 前方の値で補完される(ffillと同等の結果)
df = pd.DataFrame(
data={"A":[1,3,None,None,None,None],
        "B":["dog", "cat", "monkey", None, "rabbit", None],
        "C":["a", None, "c", "d", "e", "f"],
        "D":[None,None,None,None,None,None]})
df = df.interpolate()

>>
A       B     C     D
0  1.0     dog     a  None
1  3.0     cat  None  None
2  3.0  monkey     c  None
3  3.0    None     d  None
4  3.0  rabbit     e  None
5  3.0    None     f  None

まとめ

今回は、Pandasでデータフレームの欠損値を補完するさまざまな方法を紹介しました。

  • fillna(): 固定値、辞書、Series、統計量による補完
  • ffill() / bfill(): 前方・後方の値による補完
  • interpolate(): 前後の値を用いた線形補間

どの方法を使用するかは、データの性質や分析の目的によって異なります。例えば、時系列データでは前方補完(ffill)、数値データの平滑化には線形補間(interpolate)が有効なケースが多いです。データの特性を十分に理解した上で、適切な補完方法を選択してください。