web-dev-qa-db-ja.com

値の特定の割合がNAであるdplyrの列を条件付きで選択する

データ

以下で生成されたdata.frameに似たデータセットを使用しています。

set.seed(1)
dta <- data.frame(observation = 1:20,
                  valueA = runif(n = 20),
                  valueB = runif(n = 20),
                  valueC = runif(n = 20),
                  valueD = runif(n = 20))
dta[2:5,3] <- NA
dta[2:10,4] <- NA
dta[7:20,5] <- NA

列にはNA値があり、最後の列には観測値の60%以上がNAsあります。

> sapply(dta, function(x) {table(is.na(x))})
$observation

FALSE 
   20 

$valueA

FALSE 
   20 

$valueB

FALSE  TRUE 
   16     4 

$valueC

FALSE  TRUE 
   11     9 

$valueD

FALSE  TRUE 
    6    14 

問題

dplyrパイプラインのこの列をなんとかしてselect引数に渡して削除できるようにしたいと思います。

試み

これはbaseで簡単に実行できます。たとえば、50%NAs未満の列を選択するには次のようにします。

dta[, colSums(is.na(dta)) < nrow(dta) / 2]

これは以下を生成します:

> head(dta[, colSums(is.na(dta)) < nrow(dta) / 2], 2)
  observation    valueA    valueB    valueC
1           1 0.2655087 0.9347052 0.8209463
2           2 0.3721239        NA        NA

仕事

dplyrパイプラインで同じ柔軟性を実現することに興味があります。

Vectorize(require)(package = c("dplyr",         # Data manipulation
                               "magrittr"),     # Reverse pipe

char = TRUE)

dta %<>%
  # Some transformations I'm doing on the data
  mutate_each(funs(as.numeric)) %>% 
  # I want my select to take place here
12
Konrad

たぶんこんな感じ?

dta %>% select(which(colMeans(is.na(.)) < 0.5)) %>% head
#  observation    valueA    valueB    valueC
#1           1 0.2655087 0.9347052 0.8209463
#2           2 0.3721239        NA        NA
#3           3 0.5728534        NA        NA
#4           4 0.9082078        NA        NA
#5           5 0.2016819        NA        NA
#6           6 0.8983897 0.3861141        NA

更新colMeansの代わりにcolSumsを使用します。これは、行数で除算する必要がなくなったことを意味します。

そして、記録のために、ベースRではcolMeansを使用することもできます。

dta[,colMeans(is.na(dta)) < 0.5]
15

私はこれが仕事をしていると思います:

dta %>% select_if(~mean(is.na(.)) < 0.5) %>% head() 


 observation    valueA    valueB    valueC
  1           0.2655087 0.9347052 0.8209463
  2           0.3721239        NA        NA
  3           0.5728534        NA        NA
  4           0.9082078        NA        NA
  5           0.2016819        NA        NA
  6           0.8983897 0.3861141        NA

`

4
toscanouser

summarise_each/unlistで論理ベクトルを取得した後、extractからmagrittrを使用できます。

library(magrittr)
library(dplyr)
dta %>% 
    summarise_each(funs(sum(is.na(.)) < n()/2)) %>% 
    unlist() %>%
    extract(dta,.)

または、base RからFilterを使用します

Filter(function(x) sum(is.na(x)) < length(x)/2, dta)

または少しコンパクトなオプションは

Filter(function(x) mean(is.na(x)) < 0.5, dta)
3
akrun