如何在 dplyr::select() 函数中使用动态的整洁选择表达式?

3

我需要在多个表达式中动态选择变量。考虑以下示例:

library(tidyverse)
set.seed(42)

df <- tibble(
  grey_dog = runif(n = 69),
  white_bear = runif(n = 69),
  blue_oyster = runif(n = 69),
  white_lobster = runif(n = 69),
  green_dog = runif(n = 69)
)

df %>% 
  dplyr::select(
    (contains("dog") & contains("green")) | 
    (contains("white") & contains("bear"))
  )

不是明确地进行选择,而是使用包含我想要基于其进行选择的信息的向量:

x <- c(green = "dog", white = "bear")

我希望拼接一个字符串,用作整洁选择的条件:

s <- paste0("(", paste0("contains(", names(x),") & contains(", x, ")"), ")", collapse = " | ")
dplyr::select(df, s)

这将导致以下错误:

Error: Can't subset columns that don't exist.
x Column `(contains(green) & contains(dog)) | (contains(white) & contains(bear))` doesn't exist.
Run `rlang::last_error()` to see where the error occurred.

有任何关于如何完成这个的想法吗?

2个回答

4

你不能只传入一个字符串。一个字符串不等同于一个表达式。一种方法是使用purrrrlang构建表达式,然后将其注入到select中。

library(purrr)
library(rlang)
query <- map2(
  map(x, ~expr(contains(!!.x))),
  map(names(x), ~expr(contains(!!.x))),
  ~expr((!!.x & !!.y))) %>% 
reduce(~expr(!!.x | !!.y))
dplyr::select(df, !!query)

如果你真的想把代码作为字符串构建,那么你需要先使用rlang::parse_expr将该字符串解析为表达式。只需要在字符串中加入引号,使其与之前使用的代码完全匹配即可。

s <- paste0("(", paste0("contains(\"", names(x),"\") & contains(\"", x, "\")"), ")", collapse = " | ")
dplyr::select(df, !!rlang::parse_expr(s))

0

@MrFlick的回答是创建整洁选择表达式的正确方法。

然而,既然您已经在以编程方式构建选择,那么与其使用整洁选择表达式,直接对名称进行相应的计算可能会更容易。

library(purrr)
set.seed(42)

df <- data.frame(
  grey_dog = runif(n = 5),
  white_bear = runif(n = 5),
  blue_oyster = runif(n = 5),
  white_lobster = runif(n = 5),
  green_dog = runif(n = 5)
)

x <- list(
  c("green", "dog"),
  c("white", "bear")
)

sel <- x |>
  map(sapply, grepl, names(df)) |>
  map(apply, 1, all) |>
  reduce(`|`)

df[, sel]
#>   white_bear  green_dog
#> 1  0.5190959 0.90403139
#> 2  0.7365883 0.13871017
#> 3  0.1346666 0.98889173
#> 4  0.6569923 0.94666823
#> 5  0.7050648 0.08243756

或者,你可以在选择函数内使用 map() 应用帮助程序,然后按照类似的步骤顺序执行对应于 &| 的集合操作:
df |>
  dplyr::select(
    x |>
      map(map, contains) |>
      map(reduce, intersect) |>
      reduce(union)
  )
#>    green_dog white_bear
#> 1 0.90403139  0.5190959
#> 2 0.13871017  0.7365883
#> 3 0.98889173  0.1346666
#> 4 0.94666823  0.6569923
#> 5 0.08243756  0.7050648

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