【问题标题】:How to define key argument of gather function using string concatenation如何使用字符串连接定义收集函数的关键参数
【发布时间】:2019-02-15 21:11:37
【问题描述】:

我有一个tibble,其中有几个因素作为列名的交互作用(参见下面两个因素的示例)。

ex <- structure(list(`Monday*FALSE` = 42.74, `Monday*TRUE` = 70.68, 
`Tuesday*TRUE` = 44.05, `Tuesday*FALSE` = 51.25, `Wednesday*TRUE` = 35.57, 
`Wednesday*FALSE` = 59.24, `Thursday*TRUE` = 85.3, `Thursday*FALSE` = 59.91, 
`Friday*TRUE` = 47.27, `Friday*FALSE` = 47.44, `Saturday*TRUE` = 62.28, 
`Saturday*FALSE` = 98.8, `Sunday*TRUE` = 57.11, `Sunday*FALSE` = 65.99), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -1L))

我想编写一个函数,允许gather 这个tibble,但另外根据输入的因子名称创建一个key 名称。但是,由于paste0 返回一个字符串,因此以下内容无法正常工作。

my_gather <- function(data, ...){
  vars <- enquos(...)
  data %>% 
    gather(key = paste0(!!!vars, sep = '*'), value = value, factor_key = TRUE)
}

my_gather(ex, day, cond) %>% head()
# A tibble: 6 x 2
  `paste0(day, cond, sep = ".")` value
  <fct>                          <dbl>
1 Monday*FALSE                    42.7
2 Monday*TRUE                     70.7
3 Tuesday*TRUE                    44.0
4 Tuesday*FALSE                   51.2
5 Wednesday*TRUE                  35.6
6 Wednesday*FALSE                 59.2

我尝试将* 替换为. 以创建一个有效的同步名称,然后将paste0 捕获为sym!!

my_gather <- function(data, ...){
   vars <- enquos(...)
   data %>% 
     gather(key = !!sym(paste0(!!!vars, sep = '.')), value = value, factor_key = TRUE)
}

但它会导致错误:

!vars 中的错误:参数类型无效

gather 似乎在必要时引用了keyvalue 参数,那么有没有办法在key 定义中评估paste0(...)

【问题讨论】:

  • 你能走臭名昭著的eval(parse(text = paste0(...)))路线吗?
  • 似乎也不起作用。

标签: r dplyr tidyeval


【解决方案1】:

这不起作用,因为你是双重取消引用:

!!sym(paste0(!!!vars, sep = '.'))

!! 中的所有内容都被正常评估,因此如果您使用另一个 unquote 运算符,它需要由另一个 quasiquoting 函数处理。 paste0() 不支持!!!

作为一般规则,最好使用复杂的语法(如!!)分几个步骤执行操作。它更具可读性,并且出错的机会更少。

第二件事是您使用enquos() 引用输入。这意味着它们可以是任何复杂的表达式而不是列名。如果您希望使用裸列,最好使用 ensyms(...) 代替(或者如果您希望使用不带任何引号的字符串,则只使用 syms(c(...)))。

my_gather <- function(data, ...){
  # ensyms() guarantees there can't be complex expressions in `...`
  vars <- ensyms(...)

  # Let's convert all symbols to strings and return a character vector
  keys <- purrr::map_chr(vars, as.character)

  # Now we can use paste() the normal way. It doesn't support `!!!`
  # but the standard way of dealing with vector inputs is the
  # `collapse` argument:
  key <- paste0(keys, collapse = '*')

  # Equivalently, but weird:
  key <- eval(expr(paste(!!!keys, sep = "*")))

  # Now the key can be unquoted:
  data %>%
    gather(key = !!key, value = value, factor_key = TRUE)
}

【讨论】:

  • 是的,非常有见地。谢谢!
猜你喜欢
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多