Aidemy 2020/10/29
はじめに
こんにちは、んがょぺです!バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
今回は、機械学習の前処理の3つめの投稿になります。どうぞよろしくお願いします。
*本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。
今回学ぶこと
・欠損値の取り扱い
・外れ値の取り扱い
・不均衡データの取り扱い
欠損値の扱い
欠損値について
・欠損値は「NaN」で表される中身のないデータのことである。
・NaNがデータに存在する場合、全体の平均や標準偏差を計算することができない。
・欠損値を1つでも含むデータを全て削除してしまうとデータに無駄や偏りが生じる。
欠損値発生のメカニズム
・前項で見たように、欠損値を含むデータは適切に処理しなければデータ分析が行えない。よって欠損値に対して適切な前処理を行う必要があるが、その方法は欠損値発生のメカニズムごとに異なる。
・欠損値発生のメカニズムには、以下の3種類がある。
1.MCAR:データの欠損する(NaNになる)確率が、データそのものと無関係である(無作為に生じている)時
ex)コンピュータの不具合でデータの一部が消失した。
2.MAR:データの欠損する確率が、その項目以外の項目から影響があると推測できる時
ex)男女を対象にしたアンケートで「性別」の項目が女性であると「年齢」の項目の欠損確率が高くなる。
3.NMAR:データの欠損する確率が、その項目から影響があると推測できる時
ex)男女を対象にしたアンケートで実際の年齢が高い人ほど「年齢」の項目の欠損確率が高くなる。
欠損値の対処
・欠損値発生のメカニズムごとに適切な対処法は異なる。
・MCARの場合、欠損値を含むデータを全て削除する「リストワイズ削除」を行うことも可能。これによりデータ数が少なくなりすぎる時は「代入法」(後述)も使える。
・MARの場合は「代入法」を使う。リストワイズ削除が不適切なのは、例で言えば、女性のデータが多く削除されてしまいデータに偏りが生じるからである。
・NMARの場合は適切に対処することが困難であるため、基本的にはデータを再収集する。
代入法
・欠損値の代入法は大きく分けて2種類ある。詳しくは後述。
1.単一代入法:欠損値を補完して完全なデータセットを一つ作り、それを使ってモデルを作る方法。
2.多重代入法:欠損値を補完した完全なデータセットを複数作り、そのそれぞれについてモデルを作り、最後にモデルを一つに統合する方法。
欠損値の可視化
・データを可視化することで、どこにNaNがあるかを調べる。
・NaNがどの列に何件あるかを簡易的に知りたい時は、pandasの「データ.isnull().sum()」を使えば良い。
・欠損値全体の状況を可視化したい時は、missingnoパッケージのmatrix関数を使うと良い。
単一代入法
・単一代入法において欠損値を補完する際には、その用途に合わせて三種類の方法がある。
・平均値代入法:欠損値NaNに、その項目の平均値を代入する。平均値が増える分全体の分散は小さくなるので、分散や誤差を考慮すべきときには使えない。
・確率的回帰代入法:詳しくは扱わないが、分散や誤差を考慮することができる。
・ホットデック法:欠損値を含むデータ行(レシピエント)とデータが近いデータ行(ドナー)から値をもらうことで補完する。
・データの近さは、「最近傍法」という方法を用いて判定する。
ホットデック法
・ホットデック法は以下のように記述して実行する。
knnimpute.knn_impute_few_observed(matrix, missing_mask, k)
・引数について、「matrix」にはnp.matrixに変換したデータを渡す。「missing_mask」には、matrixのどこに欠損値が含まれるかをnp.isnan(matrix)で行列化したデータを渡す。「k」は、「最近傍法」のKNNで考慮に入れる近くの点の個数を指定する。
・KNNは「教師あり学習(分類)」で学んだ手法で、特定のデータ点を分類するときに、その近くのk個の点を考慮に入れる手法である。
・また、データをnp.matrixに変換しているので、必要に応じて元のデータ形式に戻す必要がある。
多重代入法について
・単一代入法の場合、補完した値はあくまで予測値であるため、これを使ったモデルの分析結果が必ずしも正確とは言い切れない欠点がある。
・これに対し、多重代入法はデータの補完を複数回行ってデータセットを複数作り、それらの分析結果を一つに統合して最終結果を出すため、確実性の上がった予測を行うことが可能である。
・多重代入法で使うモデルはstatsmodelsのmiceを使って以下のように表せる。
mice.MICE(formula, optimizer, imp_data)
・各引数について、「formula」には、モデルで予測する変数の式を渡す。例えば、「distance」という変数について、「time」と「speed」で予測する線形重回帰モデルの場合、以下のように表す。
'distance ~ time + speed'
・「optimizer」では分析モデルを指定し、「imp_data」には、dataをMICEで扱えるようにするために作成する「mice.MICEData(data)関数」を渡す。
・これで作成したMICEモデルに対してfit()メソッドを使うことで補完した分析結果を取得できる。(多重代入法の実行)
・fit()の第一引数には、一度の補完のための試行回数を指定し、第二引数にはデータセットの作成数を渡す。
・この分析結果に対して、summary()メソッドを使うことで結果を確認できる。
外れ値について
外れ値によって起こる問題
・外れ値とは、他のデータと著しく離れたデータのことを指す。
・外れ値が混在すると、「分析結果が正確でなくなる」「モデルの学習が遅くなる」といった問題が生じる。
・よって、外れ値についても前処理の段階で検知し、除外する必要がある。
外れ値の可視化
・外れ値が存在するかどうかは可視化するとわかりやすい。
・可視化にはseabornのboxplot(x,y,whis)を使う。描画されるのは「箱ひげ図」であり、外れ値を「♦︎」で示してくれる。
・引数「x」「y」はx軸y軸のデータ、「whis」は外れ値とみなす基準を指定する。
・データが二次元の時はjoinplot(x,y,data)も使うことができる。散布図のように点がプロットされるので、外れ値を目視で検知する。
・引数「data」にはDataFrameを渡せば良い。
・コード(縦軸の離れ具合がわかれば良いので、y軸のみ指定する)
外れ値の検知 [LOF]
・外れ値が存在することがわかったら、実際に外れ値を検知する。
・検知には「どのような値を外れ値とするか」といった基準が必要になる。今回は、その基準が予め定められた上で検知を行う、scikit-learnの「LOF」という方法を扱う。
・LOFの外れ値判定は以下のように行われる。
①近くにデータ点が少ない点を外れ値と考える。
②「近く」の判定はk個の近傍点を使って行われる。
③この判定(データの密度)が周囲と相対的に低い点を外れ値と判定する。
・LOFはLocalOutlierFactor(n_neighbors=k)で使うことができる。
・n_neighborsには近傍点の数kの個数を指定する。
・あとは普通のモデルのようなfit_predict(data)メソッドでデータを学習させて、外れ値を検出する。
・dataにはDataFrameをそのまま渡すことができる。
・戻り値としてはarray([1,1,-1,1,...])のような配列が返される。このうち「-1」の部分が外れ値とみなされた部分になる。
・これに対してdata[戻り値を格納した変数 == -1]のように指定すると、外れ値とみなされた行を抽出できる。
外れ値の検知 [isolationForest]
・LOFとは別の外れ値検知の方法として、「isolationForest」というものがある。
・isolationForestでは、ランダムにデータを分割し、その深さに値を設定していくということを繰り返して外れ値を検知する。
・isolationForestは距離や密度に依存しないため、計算が複雑でなく省メモリである。また、大規模データであっても計算をスケールしやすいといった特徴もある。
・isolationForestもLOFと同様「IsolationForest()関数」を使うことで外れ値を予測できる。
分類モデルの作成はIsolationForest()で行い、これにfit()メソッドを使って学習を行わせ、predict()で予測を行う。この戻り値はLOFと同様「-1」が外れ値となるので、 data[predictions == -1]のようにして取得する。
不均衡データについて
不均衡データによって起こる問題
・データ値のうち特定の値が極端に多かったり少なかったりするデータを「不均衡データ」という。
・例えば、二値分類のように「0」か「1」の値を持つ場合に、1000件のデータのうち999件が「1」で1件が「0」のデータであったとする。このデータで予測する場合、「1」を予測するなら99.9%的中するが、「0」はほぼ予測できない。
・よって、不均衡データについても、データの前処理段階で適切に調整する必要がある。
・調整の方法には以下の3つがある。
・オーバーサンプリング:頻度が少ないデータを増やして均衡を取る方法。
・アンダーサンプリング:頻度が多いデータを減らして均衡を取る方法。
・SMOTE-ENN:少ない方を増やし(SMOTE)、多い方を減らし(ENN)て均衡を取る。
・不均衡データを調整するにあたり、はじめに行うのは「不均衡データがあるか」の確認、すなわち、それぞれの値の個数(頻度)を可視化することである。
・個数の可視化は以下のように行う。
データ['列'].value_counts()
オーバーサンプリング
・オーバーサンプリングは、頻度の少ないデータを増やして多いデータとの均衡を取る方法である。
・データの増やし方は何種類かあるが、簡単なのは「既存のデータをランダムに水増しする」手法である。
・水増しには、不均衡データを調整する際に使われるimbalanced-learnのRandomOverSampler(ratio='minority')が使われる。
・RandomOverSamplerを定義したら、実際に .fit_sample(X,y)で実行する。
・これには目的変数Xと説明変数yをわたし、水増ししたものを格納する変数としても、2つ用意する。
アンダーサンプリング
・アンダーサンプリングは、頻度が多いデータを減らして均衡を取る方法である。
・データの減らし方は、RandomUnderSampler()で行える。この時引数で指定するratioについて、今回は頻度の多い方を扱うので、'majority'とする。
SMOTE-ENN
・SMOTEはオーバーサンプリング(データの水増し)に使われ、ENNはアンダーサンプリング(データの削除)に使われる。
・また、SMOTEでは最近傍法(kNN)を使って、増やすべきデータを推測して水増しを行い、ENNでも、kNNと同じように減らすべきデータを推測して削除を行う。
・SMOTEとENNの使い方はSMOTEENN(smote=,enn=)で行う。基本的にはROSやRUSと同様であるが、引数ではkNNで使う近傍点の個数(k_neighbors,n_neighbors)を指定する必要がある。
まとめ
・欠損値は「NaN」で表される中身のないデータのことである。
・外れ値は他のデータと著しく離れたデータのことである。
・不均衡データは特定の値が極端に多かったり少なかったりするデータのことである。
・これらのデータは機械学習の妨げになるものなので、前処理をしなければならない。
・欠損値は「代入法」でNaNに数値を代入することで補完する。
・外れ値は「LOF」「isolationForest」で取得し、除外する。
・不均衡データは「オーバーサンプリング」「アンダーサンプリング」あるいはその両方を行うことでデータの均衡を取る。
今回は以上です。最後まで読んでいただき、ありがとうございました。