使用dplyr对空列进行管道删除

15

我有一个参与者问卷响应的数据框,采用宽格式表示,每个列代表特定的问题/项目。

数据框看起来像这样:

id <- c(1, 2, 3, 4)
Q1 <- c(NA, NA, NA, NA)
Q2 <- c(1, "", 4, 5)
Q3 <- c(NA, 2, 3, 4)
Q4 <- c("", "", 2, 2)
Q5 <- c("", "", "", "")
df <- data.frame(id, Q1, Q2, Q3, Q4, Q5)

我希望R可以删除所有行的每个值都是NA或空白的列,因此我不想要Q1列(完全由NA组成)和Q5列(完全由""空白组成)。

根据这个thread,我可以使用以下代码来删除完全由NA组成的列:

df[, !apply(is.na(df), 2, all]

然而,该解决方案未解决空白值("")。由于我正在使用dplyr管道完成所有操作,是否有人可以解释一下如何将上述代码整合到dplyr管道中?

目前,我的dplyr管道如下所示:

df <- df %>%
    select(relevant columns that I need)

在此之后,我被卡住了并使用方括号[]来获取非NA列的子集。

谢谢!非常感激。


你的 dplyr 管道现在是什么样子? - De Novo
我已经更新了我的帖子,以反映我的dplyr管道现在的样子。 - DTYK
3个回答

32

我们可以使用 select_if 的一个版本。

library(dplyr)
df %>%
   select_if(function(x) !(all(is.na(x)) | all(x=="")))

#  id Q2 Q3 Q4
#1  1  1 NA   
#2  2     2   
#3  3  4  3  2
#4  4  5  4  2

或者不使用匿名函数调用

df %>% select_if(~!(all(is.na(.)) | all(. == "")))
你也可以修改你的apply语句为:
df[!apply(df, 2, function(x) all(is.na(x)) | all(x==""))]

或者使用colSums

df[colSums(is.na(df) | df == "") != nrow(df)]

与逆元素

df[colSums(!(is.na(df) | df == "")) > 0]

谢谢!select和select_if有什么区别? - DTYK
1
@DTYK select 期望选择要选择的列的名称,而 select_if 期望一个逻辑向量,只有当值为 TRUE 时才会选择该列。 - Ronak Shah

17

dplyr 版本 1.0 中,你可以在 select 中使用辅助函数 where() ,而不需要使用 select_if

library(tidyverse)
df <- data.frame(id = c(1, 2, 3, 4),
                 Q1 = c(1, "", 4, 5), 
                 Q2 = c(NA, NA, NA, NA),
                 Q3 = c(NA, 2, 3, 4), 
                 Q4 = c("", "", 2, 2), 
                 Q5 = c("", "", "", ""))

df %>% select(where(~ !(all(is.na(.)) | all(. == ""))))
#>   id Q1 Q3 Q4
#> 1  1  1 NA   
#> 2  2     2   
#> 3  3  4  3  2
#> 4  4  5  4  2

5
您可以使用select_if来实现此功能。
方法:
col_selector <- function(x) {
  return(!(all(is.na(x)) | all(x == "")))
}


df %>% select_if(col_selector)

输出:

  id Q2 Q3 Q4
1  1  1 NA   
2  2     2   
3  3  4  3  2
4  4  5  4  2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接