データ処理の前段階はデータを読み込むところから。ここで、手持ちのデータを読み込むと、しばしば空の列ができたり長さが揃っておらず不要な列ができて削除したいことがあります。次の表を読み込んだとします。
a | b | c | d |
---|---|---|---|
1 | 2 | 3 | NA |
2 | 3 | 4 | NA |
3 | 4 | NA | NA |
df <- data.frame(a = c(1,2,3),
b = c(2,3,4),
c = c(3,4,NA),
d = c(NA,NA,NA))
> df
a b c d
1 1 2 3 NA
2 2 3 4 NA
3 3 4 NA NA
dplyr::select_ifを活用する
library(dplyr)
NAが含まれるかどうか調べるanyNA()
を列ごとに適用し、返り値を論理ベクトルにして反転させる。
df %>% lapply(.,anyNA) %>% unlist %>% !.
a b c d
TRUE TRUE FALSE FALSE
これを、条件に合う列を選択する関数select_if()
に渡す。
df %>% select_if(lapply(.,anyNA) %>% unlist %>% !.)
a b
1 1 2
2 2 3
3 3 4
何とか1行のスクリプトで不要な列を削除できました。パイプのおかげで可読性もそんなに悪くないかと思います。
追記:purrr::negate()を活用する
@hkzm さんからのコメント参考になりました。
与えた関数の否定を渡すpurrr::negate()
を使うとよりストレートに、シンプルに記述できました。
library(tidyverse)
df %>% select_if(negate(anyNA))
a b
1 1 2
2 2 3
3 3 4
演算子!
で反転させ、~
でformulaにするのと同等です。
df %>% select_if(~ !anyNA(.))
a b
1 1 2
2 2 3
3 3 4
可読性が良いのはpurrr::negate()
を使う方かと個人的には思いました。
Pythonだと簡単なのに、Rだとなぜか苦労する
Pythonのpandasの場合、欠損値を削除するメソッドdropna()
が用意されており、行方向と列方向の両方に適用可能です。
参考:pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出
- NAを1つでも含む列の削除
dropna(how='any', axis=1)
- 全てNAの列の削除
dropna(how='all', axis=1)
ところが、Rだと欠損値を削除する関数は行方向のみです。
- NAを1つでも含む行の削除
na.omit()
google検索かけて列方向で削除できる方法を探してなかなか見つかりませんでした。やっと見つけたのがこちらの記事。
プログラミング言語により、得意不得意があるのかもしれません。なぜRで似たような関数がないのでしょうかね。