欠損値の処理

欠損値とは

NumPyやpandasでは、データが存在しないことを表す欠損値として、NaN(非数値:Not A Number)を使います。 NaNが入ったデータを処理しても、基本的にエラーにはならず、結果もNaNになります。 欠損値は、欠測値ともいいます。

import numpy as np

data = [1, 3, np.nan]
print(sum(data) / 2)  # nan
print(np.mean(data))  # nan

ただし、pandasやNumPyの一部の関数では、欠損値を除いて計算します。

import pandas as pd

print(pd.Series(data).mean())  # 2.0
print(np.nanmean(data))  # 2.0

欠損値の判定

pandas.DataFrame.isna, pandas.DataFrame.isnull, pandas.Series.isna, pandas.Series.isnull, numpy.isnanで欠損値かどうか判定できます。 isnullisnaの別名で、全く同じものです。

欠損値の処理方法

欠損値を残したままの計算は、避けることが多いでしょう。 その場合、主に、次のどちらかの処理をします。

  • 欠損値のデータを削除する。
  • 欠損値を別の値で代替する。

欠損値のデータを削除する

pandasのdropnaで欠損値のデータを削除できます。 inplace=Trueをつけると変数の中身を変更します。つけないと、変更せずに、欠損値を削除した新しいデータを作成します。

sr = pd.Series([1, 3, np.nan])
sr.dropna(inplace=True)

DataFrameの場合は、行単位か列単位をaxisオプションで指定します。デフォルトは行単位で削除します。 Seriesと同じくinplace=Trueをつけると変数の中身を変更します。

df = pd.DataFrame([[0, 1, 2], [1, 3, np.nan], [2, np.nan, 4]])
df.dropna()  # 行単位に削除
df.dropna(axis=1)  # 列単位に削除

欠損値を別の値で代替する

十分に根拠がある場合は、欠損値を別の値で代替する方法も取られます。

  • 例その1:気温のセンサーデータに欠損値がある場合、急な気温の変動がないだろうと想定して、前後の値の平均値で代替する。
  • 例その2:売上データに欠損値がある場合、見込みではなく確実な売上額が欲しいので、0で代替する。
  • 例その3:風力のセンサーデータに欠損値がある場合、耐久試験用のデータが欲しいので、大きめの値で代替する。

平均値で代替すると、データはそれらしくなりますが、正しい値とは限らないので注意が必要です。 たとえば、株式投資でボラティリティ(変動率)を計算したいときに、欠損値を平均値で代替すると、本来のボラティリティより小さめの値となるでしょう。

pandasではfillnaで欠損値を別の値で代替できます。これまでと同様にinplace=Trueをつけると変数の中身を変更します。 詳細は、pandas.DataFrame.fillnaか、後述の関連PyQを参照ください。

df.fillna(0)  # 0で代替
df.fillna(method='ffill')  # 直前の値で代替
df.fillna(df.mean())  # 平均で代替

scikit-learnではSimpleImputerで欠損値を別の値で代替できます。 詳細は、Imputation of missing valuesを参照ください。

from sklearn.impute import SimpleImputer
imp = SimpleImputer()
imp.fit(df)
print(imp.transform(df))

※ scikit-learn 0.19 までは、sklearn.impute.SimpleImputerの代わりにsklearn.preprocessing.Imputerを使います。