我在看似简单的任务时遇到了一些问题:删除所有变量都NA
使用dplyr的所有行.我知道可以使用基本R(删除R矩阵中的所有数据为NA并删除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_
并首先使用(长)逻辑语句创建一个字符串来实现它,但似乎应该有一个更简单的方法.
另一种方法是使用rowwise()
和do()
:
na <- dat %>% rowwise() %>% do(tibble(na = !all(is.na(.)))) %>% .$na filter(dat, na)
但这看起来并不太好,虽然它完成了工作.其他想法?
由于dplyr 0.7.0新,因此存在范围过滤动词.使用filter_any,您可以轻松过滤至少包含一个非缺失列的行:
dat %>% filter_all(any_vars(!is.na(.)))
使用@hejseb基准测试算法,似乎该解决方案与f4一样有效.
@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))
使用Reduce
并且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