scikit-learnの「Input contains NaN」の原因と対処

モデルを学習させようとすると、scikit-learnがこう止める。

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

多くのscikit-learnの推定器は、欠損値(NaN)や無限大(inf)をそのまま受け付けない。入力のどこかにそれらが混じっている、というサインだ。

まずどこにNaNがあるか見る

print(X.isna().sum()) # 列ごとの欠損数(pandas)
import numpy as np
print(np.isinf(X.to_numpy()).sum()) # inf の数

欠損を補完する

行を捨てたくないなら、平均や中央値で埋める。前処理として入れておくのが安全だ。

from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy="median")
X_clean = imp.fit_transform(X)

inf を先にNaNへ変換する

infは補完の対象にならないので、いったんNaNにしてから埋める。

import numpy as np
X = X.replace([np.inf, -np.inf], np.nan)

行ごと落とす場合

数が少なく、捨ててよいなら削除する。

X = X.dropna()

まとめ

  • 原因は特徴量のNaNやinf
  • isna().sum()isinf で場所を特定
  • 残すなら SimpleImputer で補完、infは先にNaNへ変換
  • 捨ててよいなら dropna
  • 補完は学習用と本番で同じ基準を使う(fitした補完器を使い回す)