41

すべての変数がNAdplyr を使用しているすべての行を削除するという、一見単純なタスクに問題があります。ベースR(すべてのデータがNAであるRマトリックスの行を削除しRのデータファイルの空の行を削除する)を使用して実行できることは知っていますが、dplyrを使用してそれを行う簡単な方法があるかどうか知りたいです.

例:

library(tidyverse)
dat <- tibble(a = c(1, 2, NA), b = c(1, NA, NA), c = c(2, NA, NA))
filter(dat, !is.na(a) | !is.na(b) | !is.na(c))

上記のfilter呼び出しは私が望むことを行いますが、私が直面している状況では実行不可能です (多数の変数があるため)。(長い) 論理ステートメントを使用して最初に文字列を作成することでそれを行うことができると思いfilter_ますが、もっと簡単な方法があるはずです。

もう 1 つの方法は、rowwise()andを使用することdo()です。

na <- dat %>% 
  rowwise() %>% 
  do(tibble(na = !all(is.na(.)))) %>% 
  .$na
filter(dat, na)

しかし、それは仕事を成し遂げますが、あまり見栄えがよくありません。他のアイデア?

4

9 に答える 9

18

ここでは素晴らしい janitor パッケージを使用することをお勧めします。Janitor は非常に使いやすいです。

janitor::remove_empty(dat, which = "rows")
于 2020-10-25T10:41:58.883 に答える
14

ベンチマーク

@DavidArenburg は、いくつかの代替案を提案しました。以下は、それらの簡単なベンチマークです。

library(tidyverse)
library(microbenchmark)

n <- 100
dat <- tibble(a = rep(c(1, 2, NA), n), b = rep(c(1, 1, NA), n))

f1 <- function(dat) {
  na <- dat %>% 
    rowwise() %>% 
    do(tibble(na = !all(is.na(.)))) %>% 
    .$na
  filter(dat, na)
}

f2 <- function(dat) {
  dat %>% filter(rowSums(is.na(.)) != ncol(.))
}

f3 <- function(dat) {
  dat %>% filter(rowMeans(is.na(.)) < 1)
}

f4 <- function(dat) {
  dat %>% filter(Reduce(`+`, lapply(., is.na)) != ncol(.))
}

f5 <- function(dat) {
  dat %>% mutate(indx = row_number()) %>% gather(var, val, -indx) %>% group_by(indx) %>% filter(sum(is.na(val)) != n()) %>% spread(var, val) 
}

# f1 is too slow to be included!
microbenchmark(f2 = f2(dat), f3 = f3(dat), f4 = f4(dat), f5 = f5(dat))

Reduceandを使用lapplyすると、最速のようです。

> microbenchmark(f2 = f2(dat), f3 = f3(dat), f4 = f4(dat), f5 = f5(dat))
Unit: microseconds
 expr        min          lq       mean      median         uq        max neval
   f2    909.495    986.4680   2948.913   1154.4510   1434.725 131159.384   100
   f3    946.321   1036.2745   1908.857   1221.1615   1805.405   7604.069   100
   f4    706.647    809.2785   1318.694    960.0555   1089.099  13819.295   100
   f5 640392.269 664101.2895 692349.519 679580.6435 709054.821 901386.187   100

より大きなデータセットを使用する107,880 x 40:

dat <- diamonds
# Let every third row be NA
dat[seq(1, nrow(diamonds), 3), ]  <- NA
# Add some extra NA to first column so na.omit() wouldn't work
dat[seq(2, nrow(diamonds), 3), 1] <- NA
# Increase size
dat <- dat %>% 
  bind_rows(., .) %>%
  bind_cols(., .) %>%
  bind_cols(., .)
# Make names unique
names(dat) <- 1:ncol(dat)
microbenchmark(f2 = f2(dat), f3 = f3(dat), f4 = f4(dat))

f5も遅すぎるので除外。f4以前よりも比較的うまくいっているようです。

> microbenchmark(f2 = f2(dat), f3 = f3(dat), f4 = f4(dat))
Unit: milliseconds
 expr      min       lq      mean    median       uq      max neval
   f2 34.60212 42.09918 114.65140 143.56056 148.8913 181.4218   100
   f3 35.50890 44.94387 119.73744 144.75561 148.8678 254.5315   100
   f4 27.68628 31.80557  73.63191  35.36144 137.2445 152.4686   100
于 2017-01-12T11:16:49.887 に答える
5

dplyr 1.0.4 でif_any()andif_all()関数が導入されました。

dat %>% filter(if_any(everything(), ~!is.na(.)))

または、より詳細:

dat %>% filter(if_any(everything(), purrr::negate(is.na)))

「データを取得し、エントリが非 NA であるすべての行を保持する」

于 2021-03-09T14:09:53.557 に答える