我有一个从 R 运行的数据库查询,它可以有多个填充 NA 的列,其中一些列我需要进一步向下,但如果所有值都是 NA,则可以删除一个特定列。
我通常使用 purrr::discard(~all(is.na(.))) 删除全部 NA 的列,但由于此数据帧可以包含多个带有 NA 的列,我只想删除一个我正在努力删除的列使其特定于 tidyverse 解决方案中的列。
我目前有这个解决方法:
if(sum(is.na(Orders$Originator)) == nrow(Orders)) {
Orders <- Orders %>%
select(-Originator)
}
Run Code Online (Sandbox Code Playgroud)
但如果我可以在 tidyverse 解决方案中使用它,它会提高可读性。希望有人可以提供帮助!
谢谢!
解决此问题的规范 tidyverse 方法是利用内部使用的谓词函数select(where(...)),并将其与按变量名称进行选择相结合。
首先,我们可以编写一个自定义谓词函数,在其中where仅选择仅包含NAs 的列。
# custom predicate function
all_na <- function(x) {
all(is.na(x))
}
Run Code Online (Sandbox Code Playgroud)
我们可以将此函数与布尔表达式一起使用,表示我们不想ifselect y (read AND &) it is all_na:
library(dplyr)
df <- data.frame(
x = c(1,2,NA),
y = NA,
z = c(3,4,5)
)
df %>%
select(!(y & where(all_na)))
#> x z
#> 1 1 3
#> 2 2 4
#> 3 NA 5
Run Code Online (Sandbox Code Playgroud)
为了检查这是否真的有效,让我们重新定义y,使其不仅包含NAs,我们将看到这次它没有被取消选择:
df2 <- data.frame(
x = c(1,2,NA),
y = c(1,2,NA),
z = c(3,4,5)
)
df2 %>%
select(!(y & where(all_na)))
#> x y z
#> 1 1 1 3
#> 2 2 2 4
#> 3 NA NA 5
Run Code Online (Sandbox Code Playgroud)
我们可以在内部使用 lambda 函数来代替自定义函数where:
df %>%
select(!(y & where(~ all(is.na(.x)))))
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2021 年 12 月 7 日创建(v0.3.0)
在更大的 tidyverse 中,我们还可以使用参数purrr::lmap_at并选择,然后创建一个 lambda 函数,说明 if then 使用空(= 删除列),否则保留列:y.atall(is.na(.x))list().x
library(purrr)
library(dplyr)
df %>%
lmap_at("y", ~ if(all(is.na(.x))) list() else .x)
#> # A tibble: 3 x 2
#> x z
#> <dbl> <dbl>
#> 1 1 3
#> 2 2 4
#> 3 NA 5
Run Code Online (Sandbox Code Playgroud)
由reprex 包于 2021 年 12 月 7 日创建(v2.0.1)