備忘ログ

チラシの裏的備忘録&メモ

Rで任意の列でNA(欠損値)が含まれている行のみを削除したり、取り出したりしたいメモ

要旨

lm()glm()などでは指定した従属変数や独立変数に欠損値がある行が削除される(ペアワイズ)が、ここで削除された行はどんな行なのか確認したいと思ったのでその方法のメモ。

逆に、削除されなかった行たちも確認したいと思った。

また、そもそもこうやって取り出さなくても任意の列(複数列)でNAが含まれていない行のみを取り出したり、逆にNAが含まれている行のみを取り出したいと思ったのでその方法のメモ。

lm()glm()などでペアワイズに削除された行を確認する(そして使われたデータも確認する)

Rのlm()glm()で回帰分析を行うときに従属変数または独立変数に指定した変数に欠損値がある場合、その行は削除されて計算される(ペアワイズ)。

model_lm <- lm(Temp ~ Solar.R + Wind, data = airquality)
summary(model_lm)
## 
## Call:
## lm(formula = Temp ~ Solar.R + Wind, data = airquality)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -17.6521  -5.0358   0.9309   5.0250  18.0943 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 84.899708   2.476595  34.281  < 2e-16 ***
## Solar.R      0.025697   0.007337   3.503 0.000615 ***
## Wind        -1.155726   0.188311  -6.137 7.82e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.944 on 143 degrees of freedom
##   ( 7 個の観測値が欠損のため削除されました )
## Multiple R-squared:  0.2687, Adjusted R-squared:  0.2585 
## F-statistic: 26.27 on 2 and 143 DF,  p-value: 1.916e-10

ここでペアワイズで除去された行はオブジェクトの中(今回の場合はmodel_lm)の中にna.actionと行数があるので、model_lm$na.actionで何行目が削除されたのか確認できる。

model_lm$na.action
##  5  6 11 27 96 97 98 
##  5  6 11 27 96 97 98 
## attr(,"class")
## [1] "omit"

これで元のデータフレームから5、6、11、27、96、97、98行目が削除されたデータフレームで計算されたことがわかる。

どのような行が削除されたのか確認するにはデータフレームでその行を指定すればよいので、次のようにするといい。

airquality[model_lm$na.action, ]
##    Ozone Solar.R Wind Temp Month Day
## 5     NA      NA 14.3   56     5   5
## 6     28      NA 14.9   66     5   6
## 11     7      NA  6.9   74     5  11
## 27    NA      NA  8.0   57     5  27
## 96    78      NA  6.9   86     8   4
## 97    35      NA  7.4   85     8   5
## 98    66      NA  4.6   87     8   6

逆に使われた行(削除されていない行)を確認するなら、実際に使われた値(従属変数と独立変数として指定されたもの)だけを取り出したい場合はオブジェクトの中に、modelとして格納されているため、次のようにすると取り出せる。

# 長いから実行結果は載せない
model_lm$model

また、使わなかった行を指定したときの逆に、使わなかった行じゃない行をデータフレームで指定するとデータフレーム全体を取り出せる。

# 長いから実行しない
airquality[-model_lm$na.action, ]

データフレームから任意の列でNAとなっている行を除いたものを取り出す

ところで、今回のlm()の従属変数や独立変数などのように、任意の列にNAが含まれている行のみを削除し、そうではない列にNAが含まれている場合にはとりあえずそのままで取り出すという処理を考えてみる。

つまり任意の列のみを参照しna.omit()するイメージ、参照されなかったNAはそのままにしたいということ。ただデータフレームに対してna.omit()をするとNAが含まれている行がすべて削除されるので、そこまで削除したくないということ。

任意の列のみからなるデータフレームを作成し、complete.case()をつかってその中でNAが含まれていない行を探し、その行をデータフレーム全体で返す処理を考える。

汎用的に使えるように自作関数化する。

na.omit_select <- function(.data, ..., .retrieve = TRUE){
  select_case <- stats::complete.cases(dplyr::select(.data = .data, ...))
  if(.retrieve) .data[select_case, ]
  else .data[!select_case, ]
}

これは.dataにデータフレームを指定し、...に参照したい列名を入れるとうまくいく。

例えば次のようなデータフレームを考える。

example_data <- data.frame(value1 = c(1, 2, NA, NA, 10),
                           value2 = c(1, NA, 3:5),
                           value3 = c(NA, 1, 2, NA, 10))

ここでvalue3NAが含まれている行を削除したいと考えると次のようにするといい。

na.omit_select(example_data, value3)
##   value1 value2 value3
## 2      2     NA      1
## 3     NA      3      2
## 5     10      5     10

複数の列も指定できる。例として、value2value3NAが含まれている行を削除してみたい場合は次のようにする。

na.omit_select(example_data, value2, value3)
##   value1 value2 value3
## 3     NA      3      2
## 5     10      5     10

逆にNAが含まれているために除かれた行を取得するには、.retrieve = FALSEとするとよい。

na.omit_select(example_data, value2, value3, .retrieve = FALSE)
##   value1 value2 value3
## 1      1      1     NA
## 2      2     NA      1
## 4     NA      4     NA

どういうデータが欠損値となっているのか見ることができるようになる。

この関数はGitHubにアップしているパッケージに登録している。

github.com