欠損値の確認に便利 "naniar"パッケージ

欠損値処理に特化したnaniarパッケージの紹介(すでにかなり有名っぽい)も兼ねていますが、どちらかというと自分のため備忘録的な記事になります。

> The best thing to do with missing data is to not have any. 
by Gertrude Mary Cox



こんな言葉を残した統計学者もいるくらい欠損値の処理はめんどくさい...けれども、実世界のデータを扱う際にはほとんど避けては通れないステップ。

# "naniar" Package
naniarパッケージは欠損値の処理に特化したパッケージで、欠損値の要約や可視化を通して欠損値を含むデータの解釈をサポートしてくれるパッケージ。

その中でも当記事では「欠損値の確認」の部分にのみ焦点をあてている。
関数の使用例はパッケージに含まれているアメリカの生活習慣病のリスク行動調査を記録したriskfactorsデータを用いて行う。

```{r}
# install.packages("naniar")
library(naniar)
data(riskfactors) #2009年のデータ
```

[BRFSS 2009 Survey Data and Documentation](https://www.cdc.gov/brfss/annual_data/annual_2009.htm)

# 欠損値の確認


## n_miss() と n_complete()

`n_miss(data)`は`sum(is.na(data))`の代替となる関数。`n_complete()`は逆に欠損値ではない値の数を返してくれる。

```{r}
> n_miss(riskfactors$health_poor) #特定のカラムの欠損値の数を知りたいときは$を使えばよい
[1] 113
> apply(riskfactors, 2, n_miss) #全体を俯瞰したければapplyでMARGIN=2に設定すれば便利
           state              sex              age       weight_lbs      height_inch              bmi          marital         pregnant         children        education 
               0                0                0               10                2               11                1              215                0                1 
      employment           income          veteran         hispanic   health_general  health_physical    health_mental      health_poor     health_cover     provide_care 
               0                0                3                2                0                0                0              113                0                3 
activity_limited        drink_any       drink_days    drink_average        smoke_100       smoke_days       smoke_stop       smoke_last       diet_fruit       diet_salad 
               3                2              134              135                2              128              212              161                8                8 
     diet_potato      diet_carrot   diet_vegetable       diet_juice 
               8                8                8                8 
> n_complete(riskfactors$health_poor)
[1] 132
> sort(apply(riskfactors, 2, n_complete), decreasing = T)
           state              sex              age         children       employment           income   health_general  health_physical    health_mental     health_cover 
             245              245              245              245              245              245              245              245              245              245 
         marital        education      height_inch         hispanic        drink_any        smoke_100          veteran     provide_care activity_limited       diet_fruit 
             244              244              243              243              243              243              242              242              242              237 
      diet_salad      diet_potato      diet_carrot   diet_vegetable       diet_juice       weight_lbs              bmi      health_poor       smoke_days       drink_days 
             237              237              237              237              237              235              234              132              117              111 
   drink_average       smoke_last       smoke_stop         pregnant 
             110               84               33               30 
```

## prop_miss()

上の二つの関数は実数で帰ってくるのに対して`prop_miss()`は欠損値の割合を教えてくれる。(結構便利。むしろ上よりもこっちのほうが使いやすそう。)

```{r}
> prop_miss(riskfactors)
[1] 0.142377
> apply(riskfactors, 2, prop_miss)
           state              sex              age       weight_lbs      height_inch              bmi          marital         pregnant         children        education 
     0.000000000      0.000000000      0.000000000      0.040816327      0.008163265      0.044897959      0.004081633      0.877551020      0.000000000      0.004081633 
      employment           income          veteran         hispanic   health_general  health_physical    health_mental      health_poor     health_cover     provide_care 
     0.000000000      0.000000000      0.012244898      0.008163265      0.000000000      0.000000000      0.000000000      0.461224490      0.000000000      0.012244898 
activity_limited        drink_any       drink_days    drink_average        smoke_100       smoke_days       smoke_stop       smoke_last       diet_fruit       diet_salad 
     0.012244898      0.008163265      0.546938776      0.551020408      0.008163265      0.522448980      0.865306122      0.657142857      0.032653061      0.032653061 
     diet_potato      diet_carrot   diet_vegetable       diet_juice 
     0.032653061      0.032653061      0.032653061      0.032653061 
```

## miss_var_summary()

今まで紹介した三つの関数を合わせたようなものがこの`miss_var_summary()`。出力は変数名と欠損値の実数、さらには欠損割合。これが今の所一番使いやすそう。

```{r}
> miss_var_summary(riskfactors)
# A tibble: 34 x 3
   variable      n_miss pct_miss
   <chr>          <int>    <dbl>
 1 pregnant         215    87.8 
 2 smoke_stop       212    86.5 
 3 smoke_last       161    65.7 
 4 drink_average    135    55.1 
 5 drink_days       134    54.7 
 6 smoke_days       128    52.2 
 7 health_poor      113    46.1 
 8 bmi               11     4.49
 9 weight_lbs        10     4.08
10 diet_fruit         8     3.27
# … with 24 more rows
```

一目瞭然で俯瞰できるし、出力がtibble型なので、`filter(n_miss >= x)`とかで下限を指定して表示することもできるので使い勝手が良さそう。

# 可視化編

## vis_miss()

欠損値の状況を可視化してくれるもっともシンプルでわかりやすい関数。指定したデータセットの全ての変数を俯瞰できるのがとても便利。含みたくない変数などがあれば`select(data, -var)`とかで除けば簡単に対応できます。

```{r}
vis_miss(riskfactors)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83838/96db3f61-41df-0e2b-1c41-70fed90e0695.png)

含みたくない変数などがあれば`select(data, -var)`とかで除けば簡単に対応できます。
同様の機能を有した関数には`visdat::vis_dat()`が挙げられますが、グラフのx軸に欠損値の割合が表示される機能はそちらには見た感じなかったです。そのため`visdat::vis_dat()`の上位互換として機能しそうです。

## gg_miss_var()

変数の欠損値割合を比較するもう一つの手段が当関数。これは欠損値の割合が確認でき、デフォルトで順序がついてるところ特徴。`vis_miss()`で全体をざっとみて、`gg_miss_var()`を使って実際にどこから処理していくのか決めて行くのが良さそうです。

```{r}
gg_miss_var(riskfactors)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83838/064bf95a-b529-dc2e-82cc-ea3953d11e12.png)

デフォルトでラベルがMissingやVariablesとなっているが、ここは変更可能。ggplot2の構文で書かれているので`+ labs(x = "X", y = "Y", title = "TITLE")`のように簡単に変更できる。さらに背景のテーマなんかもggplot2の構文で普段通り変更可能です

# まとめ

当記事では、naniarパッケージのメインの関数しかまとめていないが、すでに便利そうな関数がたくさんある。一方で全て覚えるのは厳しそうなので、その都度確認できるようにこれからもまとめていきたい。

# 参考文献
+ [naniar package](https://cran.r-project.org/web/packages/naniar/index.html)
+ [Getting started with naniar](https://cran.r-project.org/web/packages/naniar/vignettes/getting-started-w-naniar.html)
+ [補足記事：naniarパッケージの紹介記事を書いたことと、プラスのまとめ](http://kokiando.hatenablog.com/entry/2019/05/11/143650)