首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用dplyr删除所有变量都是NA的行。

使用dplyr删除所有变量都是NA的行。
EN

Stack Overflow用户
提问于 2017-01-12 09:51:44
回答 10查看 34.3K关注 0票数 44

对于一个看似简单的任务,我遇到了一些问题:使用dplyr删除所有变量都是NA的所有行。我知道可以使用基R (Remove rows in R matrix where all data is NARemoving empty rows of a data file in R)来完成它,但我很想知道是否有一种使用dplyr的简单方法。

示例:

代码语言:javascript
运行
复制
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_并首先使用(long)逻辑语句创建一个字符串来做到这一点,但是看起来应该有一种更简单的方法。

另一种方法是使用rowwise()do()

代码语言:javascript
运行
复制
na <- dat %>% 
  rowwise() %>% 
  do(tibble(na = !all(is.na(.)))) %>% 
  .$na
filter(dat, na)

但这看起来不太好,虽然它完成了工作。其他想法?

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2018-05-02 09:36:51

由于dplyr 0.7.0新的,范围过滤动词存在。使用filter_any,您可以轻松地筛选至少有一个不缺少的列的行:

代码语言:javascript
运行
复制
# dplyr 0.7.0
dat %>% filter_all(any_vars(!is.na(.)))

使用@hejseb基准测试算法,该解决方案似乎与f4一样有效。

更新:

由于dplyr 1.0.0,上述作用域动词被取代。相反,引入了跨函数族,它允许在多个(或所有)列上执行一个函数。过滤至少有一个列不是NA的行现在看起来如下所示:

代码语言:javascript
运行
复制
# dplyr 1.0.0
dat %>% filter(if_any(everything(), ~ !is.na(.)))
票数 74
EN

Stack Overflow用户

发布于 2020-10-25 10:41:58

我建议你用这个很棒的看门人包。看门人对用户非常友好:

代码语言:javascript
运行
复制
janitor::remove_empty(dat, which = "rows")
票数 19
EN

Stack Overflow用户

发布于 2017-01-12 11:16:49

基准测试

@DavidArenburg提出了一些备选方案。这里是他们的一个简单的基准。

代码语言:javascript
运行
复制
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))

使用Reducelapply似乎是最快的:

代码语言:javascript
运行
复制
> 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

代码语言:javascript
运行
复制
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似乎比以前做得更好。

代码语言:javascript
运行
复制
> 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
票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41609912

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档