プログラミング
記事内に商品プロモーションを含む場合があります

欠損値(NaN)取り扱い方法を解説 | 機械学習におけるデータ予測精度向上のための手法

機械学習の欠損値処理
tadanori

はじめに

機械学習・データ分析の前処理として、欠損値(NaN)を処理する必要があります。欠損値の処理方法としては次のような方法が考えられます。

  1. 削除:欠損値を含む行または列を削除する方法。ただし、データが少ない場合や欠損値の割合が高い場合はデータが減ることに注意が必要。
  2. 置き換え:欠損値に代表的な値を設定する方法。数値の場合は、平均値や中央値、最頻値に置き換える方法。カテゴリカルデータの場合は最頻値や特定の値を代入。
  3. 欠損値フラグ:欠損値を示す専用のフラグを設定する方法。これにより、欠損値の情報が保持され、後続の処理で適切な扱いが可能。

ここでは、2つめの置き換えを行うコードを紹介します。

データが多い場合は、削除なども有効です。また、欠損値を示すフラグを設定したり、列の値が全て正の場合は、欠損値は-1にして区別できるようにするなども有効です。

nanを除去する

自分で処理する(fillna()

pandasのfillnaを使って、自分で置き換える方法です。まず、動作確認用のdfを以下のように作成したとします。

import math
import pandas as pd

df = pd.DataFrame([[1,2,3],[3,math.nan,5],[math.nan, 3, 4]], columns=['A','B','C'])
df
 ABC
01.02.03
13.0NaN5
2NaN3.04

フレーム全体を置換

例えば、データフレーム(df)全体のNaNを0に置き換える場合は、以下のコードを実行します。

df = df.fillna(0)
 ABC
01.02.03
13.00.05
20.03.04

NaNは、0に置き換えられます。

特例列を置換

なお、特定列を置換する場合は以下のように列を指定できます。

df = df.fillna({'A': -1.0})
ABC
01.02.03
13.0NaN5
2-1.03.04

他の列をコピー

他の列をコピーしたい場合には以下のようにすればOKです。

df = df.fillna({'B':df['C']})

ABC
01.02.03
13.05.05
2NaN3.04

平均値で置き換え

また、各列毎の平均値に置き換えたい場合などは以下のようにします。

df = df.fillna(df.mean(axis=0))
ABC
01.02.03
13.02.55
22.03.04

A列とB列のNaNは、各列の平均値と置換されます。このように、fillnaを使って各列のNaNを置き換えすることができます。

Simple Imputerを使う(scikit-learn)

scikit-learnのSimpleImputerを使っても欠損値の置き換えが可能です。まず、sklearnをインポートします。

from sklearn.impute import SimpleImputer

データフレームを一気に変換する例です。

imp = SimpleImputer(strategy="mean")
imp.fit(df)
df = pd.DataFrame(imp.transform(df), columns=df.columns)

最初の行でSimpleImputerのオブジェクトを作成しています。strategyとしては以下が設定できます。

mean平均値と置き換え
median中央値と置き換え
most_frequent最頻値と置き換え
constant固定値で置き換えl。固定値はfill_valueパラメータで設定

fitで、各列に対して置き換える値が計算し、transformで変換を実行します。なお、fit_transform()という計算・置き換えを一気に行う関数もありますが、トレーニングデータで計算した値で、トレーニングデータ、テストデータの両方の置き換えをしたい場合があるので、個別で行う方法を覚えていた方が良いです。

なお、各列を個別に変換(異なるstrategyで変換)したい場合には、書き方注意です.

imps = {}
for col, strategy in zip(df.columns, ['median', 'mean', 'mean']):
    imps[col] = SimpleImputer(strategy=strategy)
    df[col] = imps[col].fit_transform(np.array(df[col]).reshape(-1, 1))

上のコードのように、各列だけを変換する場合にはnumpyの配列に変換し、1列の行列に変換して入力する必要があります。

予測で用いるときは

新たに入力されたデータに対して予測などを行う場合には、各列の欠損値をどのような値で埋めたのかを覚えておき、新しい入力データにも同じ処理を行う必要があります。例えば、fillnaメソッドを使用する場合は、各列の中央値や平均値などで置換したデータを記憶しておく必要があります。また、SimpleImputerを使用する場合も、後で参照できるように変換毎に別のオブジェクトとして記憶しておきます。上記の例では、impsに記憶しています。

おすすめ書籍

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

記事URLをコピーしました