記事の概要
前回の記事に続いて、今回は欠損値の扱いについてまとめてみた。
欠損値の扱い
欠損値をどう処理するかは、主に次のようなものが挙げられる。
- そのまま放置
- 列ごと削除
- 欠損に意味があるならカテゴリ化
- 代表値で埋める
- 他の特徴量の情報から埋める
- 欠損か否かを表す特徴量を作る
それぞれもう少し具体的に説明していく。
そのまま放置
XGBoostやLightGBMなど欠損値のままでも動くフレームワークであれば、欠損値を補完する必要がない。欠損していること自体に情報が含まれている、と考えると、欠損値を削除したり無理に補完するよりもそのまま取り扱った方が精度が良くなる可能性がある。
欠損値のままでは動かないモデルの場合は、0や-9999など通常はとりえない値を欠損値に代入することで欠損値のまま取り扱うのに近いやり方をすることができる。
列ごと削除
大部分が欠損している場合は、その特徴量ごと削除することを検討する。
ただし、以下で紹介する補完方法が使える場合はそちらを優先したほうが良いかも。
欠損に意味があるならカテゴリ化
欠損していること自体に意味が含まれている場合、欠損を一つのカテゴリにする。
例えば、PoolQcを見てみると大部分が欠損しているが、これを「プールがない」と解釈すれば実感に一致する。プールは普通の家にはないはずで、あるのはお金持ちの家くらい。したがって、欠損値を「None」や「NoPool」などに置き換える。(なお今回のコンペの場合、dataset内のdata_descriptionにその旨が記載されていた)
ちなみに、欠損数に着目するとこの種のパターンは見つけやすくなる。
例えば上のGarage関連の特徴量はそろって159個欠損している。さすがにこれが偶然とは考えづらいので、何かしらの関連があるとみるのが自然。
代表値で埋める
数値変数の場合は、平均値や中央値で欠損を埋めるのがメジャーな方法。ただし平均値は分布がゆがんでいると適切な代表値として機能しないので、中央値をつかうか、log変換して平均をとる。
平均値や中央値を取る範囲にもいろいろある。全体の平均・中央値で埋めるのが一番手っ取り早いが、他のカテゴリ変数でgroupbyして各groupごとの平均・中央値で埋める方法もある。
例えば、カテゴリ変数"Neighborhood"でgroupbyして、もし"Veenker"の行で欠損しているなら"Veenker"の中央値で埋める、といった具合。
カテゴリ変数の場合は、最頻値で埋める。
例えば"MSZooning"では全体の約8割が「RL(Residential Low Density)」なので、欠損値は「RL」で埋める。
ただし、欠損が多いときに最頻値で埋めるとあまりよろしくない場合がある。
下は「FireplaceQu」の欠損を最頻値で埋める前後の様子であるが、埋める前後で「Gd」がデータ全体に占める割合が約半分から約4分の3になってしまい、分布が大きく変わっている。
他の特徴量の情報から予測する
欠損している変数が他の変数と関連性がある場合は、他の変数を特徴量、欠損している変数を目的変数とみなして、欠損値をモデルの予測値で埋めるという方法も有効かも。
欠損か否かを表す特徴量を作る
新たな特徴量として「欠損しているか否か」を表す二値変数をつくると良い特徴量として機能する場合もある。
一つは、欠損している列は予測に使わないでおいて、欠損しているか否かを表す特徴量だけを予測に用いる方法。もう一つは、欠損値は埋めておくけれども、欠損していたという情報を損なわないために二値変数も予測に用いるというやり方。
参考
https://www.kaggle.com/dansbecker/handling-missing-values
https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard
https://www.kaggle.com/erikbruin/house-prices-lasso-xgboost-and-a-detailed-eda
https://www.kaggle.com/c/house-prices-advanced-regression-techniques/discussion/35968