Subscribed unsubscribe Subscribe Subscribe

SE Can't Code

A Tokyo based Software Engineer. Not System Engineer :(

データ解析における欠損値対応フロー

データ分析プロセスの中の欠損値対応についてまとめる。
分析をするデータには大抵欠損値が存在しており、多くの統計解析や機械学習の手法では欠損値が存在していないことを前提としているため、欠損値を取り除いてあげるか、補完してあげるかのアプローチを取らなければならない。

欠損値が発生するメカニズム


欠損値は以下3つに分類される。

  • MCAR (Missing Completely At Random)
  • MAR (Missing At Random)
  • MNAR (Missing Not At Random)


上記3つのメカニズムについて、JobPerformanceとIQの二つの変数のdataframeを作成して説明する。この変数で表していることは、人間のIQは仕事のパフォーマンスにどう関係しているか、というものである。

> employee.IQ.JP <- data.frame(IQ = c(78, 84, 84, 85, 87, 91, 92, 94, 94, 96, 99, 105, 105, 106, 108, 112, 113, 115, 118, 134), JobPerformance = c(9, 13, 10, 8, 7, 7, 9, 9, 11, 7, 7, 10, 11, 15, 10, 10, 12, 14, 16, 12))
> employee.IQ.JP
    IQ JobPerformance
1   78              9
2   84             13
3   84             10
4   85              8
5   87              7
6   91              7
7   92              9
8   94              9
9   94             11
10  96              7
11  99              7
12 105             10
13 105             11
14 106             15
15 108             10
16 112             10
17 113             12
18 115             14
19 118             16
20 134             12


MCARとは、欠損値が完全にランダムに発生しているケースであり、分析における他の変数や変数自体の値に対して無関係である。

> library(ggplot2)
> employee.IQ.JP$MCAR <- employee.IQ.JP$JobPerformance
> employee.IQ.JP$MCAR[c(1, 3, 10, 20)] <- NA
> p <- ggplot(data = employee.IQ.JP, aes(x = IQ, y = JobPerformance, colour = MCAR.is.missing)) + geom_point(aes(shape = MCAR.is.missing), size = 5) + theme_bw() %+replace% theme(legend.position = "bottom") 
> print(p)

f:id:fixxman:20151006032801p:plain

MARとは、欠損は変数自体の値には依存していないが、他の変数には依存関係を持っている。

> employee.IQ.JP$MAR <- employee.IQ.JP$JobPerformance
> employee.IQ.JP$MAR[1:5] <- NA
> employee.IQ.JP$MAR.is.missing <- as.factor(as.integer(is.na(employee.IQ.JP$MAR)))
> p <- ggplot(data = employee.IQ.JP, aes(x = IQ, y = JobPerformance, colour = MAR.is.missing)) + geom_point(aes(shape = MAR.is.missing), size = 5) + theme_bw() %+replace% theme(legend.position = "bottom")
> print(p)

f:id:fixxman:20151006033537p:plain

MNARとは、分析における他の変数及び、変数自体に対して依存関係を持っている。

> employee.IQ.JP$MNAR <- employee.IQ.JP$JobPerformance
> employee.IQ.JP$MNAR[c(4:6, 10:11)] <- NA
> employee.IQ.JP$MNAR.is.missing <- as.factor(as.integer(is.na(employee.IQ.JP$MNAR)))
> p <- ggplot(data = employee.IQ.JP, aes(x = IQ, y = JobPerformance, colour = MNAR.is.missing)) + geom_point(aes(shape = MNAR.is.missing), size = 5) + theme_bw() %+replace% theme(legend.position = "bottom")
> print(p)

f:id:fixxman:20151006034126p:plain

欠損値を含むデータを解析しようとする際、MCAR、MAR、MNARのいずれかであるかを検証する必要がある。たとえば、MCARについては、観測データと欠損データの平均値と共分散の特質性を仮定しているため、t検定などを用いて検証することができる。

欠損値対応のフロー


まず、欠損値のパターンの解析と可視化を行うことで欠損値を特定する。特定した欠損値に対してそれに適合する対応を行う。欠損値への対応は大きく分けて「欠損値の削除」と「欠損値の補完」の二つが挙げられるが、以下が欠損値への対応手法の一覧となる。リストワイズ法とペアワイズ法が欠損値の削除となり、それ以外が欠損値の補完の手法となる。

リストワイズ法

: 欠損値をもつサンプルの削除

ペアワイズ法

: 相関係数や分散等の算出において、2変数のいずれかが欠損値をもつサンプルを削除

平均値代入法

: 平均値により欠損値を補完

回帰代入法

: 欠損値のないサンプルに回帰分析を行い、欠損値を含む項目の推定式を元に欠損値を補完

確率的回帰代入法

: 回帰代入法により確定した値にランダムに誤差を加えて欠損値を補完

完全情報最尤推定

: サンプル毎に欠損パターンに応じた尤度関数を仮定して最尤推定を実施して得られる多変量正規分布を用いて平均値や分散共分散行列を推定

多重代入法

: 欠損値に代入したデータセット複数作成し、各データセットに対して分析を実行し、その結果を統合することにより欠損値を補完


伝統的な欠損値の対応としては、リストワイズ法やペアワイズ法、平均値代入法や回帰代入法が用いられてきたが、これらの方法には欠損値がランダムに生じるような状況でない限りは推定値にバイアスが生じてしまう。そういった伝統的な対応に対してよく用いられるのは、弱い仮定の下でバイアスを与える完全情報最尤推定法と多重代入法である。

欠損値のパターンの可視化


欠損値の発生パターンを特定するためには可視化をして直感的に捉えればいい。R言語には欠損値の可視化を助けてくれるパッケージ群が存在し、miceやVIMがよく使われる。
たとえば、miceパッケージのmd.pattern関数は、欠損値の組み合わせパターンを集計する。

> library(mice)
 要求されたパッケージ Rcpp をロード中です 
 要求されたパッケージ lattice をロード中です 
mice 2.22 2014-06-10
> md.pattern(nhanes)
   age hyp bmi chl   
13   1   1   1   1  0
 1   1   1   0   1  1
 3   1   1   1   0  1
 1   1   0   0   1  2
 7   1   0   0   0  3
     0   8   9  10 27


各項目(age, hyp, bmi, chl)に対して、欠損有無(1:欠損なし、0:欠損あり)の組み合わせパターンと頻度を表すことができる。

また、VIMパッケージを用いると直感的に理解がしやすい。
VIMパッケージのaggt関数は、単一のデータ項目に対して欠損値の棒グラフ及び、複数のデータ項目に対して欠損値パターンを可視化する。

> library(VIM)
 要求されたパッケージ colorspace をロード中です 
 要求されたパッケージ grid をロード中です 
 要求されたパッケージ data.table をロード中です 
data.table 1.9.6  For help type ?data.table or https://github.com/Rdatatable/data.table/wiki
The fastest way to learn (by data.table authors): https://www.datacamp.com/courses/data-analysis-the-data-table-way
VIM is ready to use. 
 Since version 4.0.0 the GUI is in its own package VIMGUI.

          Please use the package to use the new (and old) GUI.

Suggestions and bug-reports can be submitted at: https://github.com/alexkowa/VIM/issues

 次のパッケージを付け加えます: ‘VIM’ 

 以下のオブジェクトは ‘package:datasets’ からマスクされています: 

     sleep 

> aggr(nhanes, prop = FALSE, number = TRUE)

f:id:fixxman:20151006042958p:plain

左側の図では、単一のデータ項目に対して欠損値の棒グラフが図化されており、各項目の欠損値が何個あるかがわかる。 右側の図では、複数のデータ項目に対して欠損値パターンが図化されており、各項目の欠損値パターンが何個あるかがわかる。

また、VIMパッケージのmarginplot関数を用いると、2項目に対しての欠損状況をプロットできる。

> marginplot(nhanes[, c("hyp", "bmi")], col = c("blue", "red", "orange"), cex = 1.5, cex.lab = 1.5, cex.numbers = 1.3, pch = 20, ps = 1)

f:id:fixxman:20151006043951p:plain

この図からは、箱ひげ図によって項目の値の範囲が把握でき、また欠損が生じる値などの定量的な情報を視覚的に捉えることができる。

VIMパッケージのpbox関数を使えば、特定のデータ項目と他の項目の関係性について、欠損値の有無毎に箱ひげ図をプロットできる。

> pbox(nhanes, pos = 1, int = FALSE, cex = 1.2)

f:id:fixxman:20151006044520p:plain



以上が欠損値に対する大まかな対応フローと欠損値把握のための解析方法となる。このように欠損値のパターンを解析し欠損値を特定した後で、実際に欠損値を削るのか埋めるのかといった対応を行うのだが、もう夜も深いので次回に回そうかと思う。欠損値の対応方法としては、完全情報最尤推定法と多重代入法をまとめようと思う。

現場からは以上です。

参考

データ分析プロセス (シリーズ Useful R 2) | 福島 真太朗, 金 明哲 | 本 | Amazon.co.jp

http://koumurayama.com/koujapanese/missing_data.pdf

Remove all ads