其中quo_name的机会

问题描述 投票:9回答:2

嗨,关注Programming with dplyr我注意到可以使用quo_name添加名称。我想知道如何为多列执行此操作,例如。像quos_name的种类。例如。:

   my_mutate <- function(df, expr) {
  expr <- enquo(expr)
  mean_name <- paste0("mean_", quo_name(expr))
  sum_name <- paste0("sum_", quo_name(expr))

  mutate(df, 
    !!mean_name := mean(!!expr), 
    !!sum_name := sum(!!expr)
  )
}

   my_mutate <- function(df, ...) {
  exprs <-quos(...)
  mean_names <- paste0("mean_", quos_name(exprs))
  sum_names <- paste0("sum_", quos_name(exprs))

  mutate(df, 
    !!!mean_names := mean(!!!exprs), 
    !!!sum_names := sum(!!!exprs)
  )
}

即。为...中指定的所有列添加mean和sum列,当然这仅作为示例,并且quos_names不存在。如果有办法,这将是非常有帮助的。

我知道有可能在data.table DT[,(Col_names):=lapply(Cols,mean)]中做这样的事情(这段代码不起作用,但我之前做过类似的事情)。

r dplyr nse rlang
2个回答
2
投票

免责声明:虽然@aosmith提出的mutate_at在我看来是最好和最简单的解决方案,但我认为如果rlang不存在,看看如何使用mutate_at工具来解决问题可能是有益的。对于科学!

如评论中所述,您将需要查看purrr::map()函数族。您还将遇到!!!mean_names := mean(!!!exprs)的单独问题,因为!!! splice运算符不能在赋值的左侧使用。

最好的rlang方法是将你的mutate表达式组成一个命名列表。使用quo执行表达式算术和stringr::str_c(或者你正在做的paste0)用于字符串算术:

library( tidyverse )

my_mutate <- function(df, ...) {
  exprs <- enquos(...)

  mean_exprs <- set_names(
    map(exprs, ~quo(mean(!!.x))),               # mpg becomes mean(mpg)
    str_c("mean_", map_chr(exprs, quo_name)) )  # mpg becomes "mean_mpg"

  sum_exprs <- set_names(
    map(exprs, ~quo(sum(!!.x))),                # mpg becomes sum(mpg)
    str_c("sum_", map_chr(exprs, quo_name)) )   # mpg becomes "sum_mpg"

  mutate(df, !!!mean_exprs, !!!sum_exprs)
}

mtcars %>% my_mutate( mpg, cyl )
#    mpg cyl disp  hp ... mean_mpg mean_cyl sum_mpg sum_cyl
# 1 21.0   6  160 110 ... 20.09062   6.1875   642.9     198
# 2 21.0   6  160 110 ... 20.09062   6.1875   642.9     198
# 3 22.8   4  108  93 ... 20.09062   6.1875   642.9     198
# 4 21.4   6  258 110 ... 20.09062   6.1875   642.9     198

奖励:您会注意到我们在上面的表达式定义中重复了一大堆代码。我们可以将它拉出一个独立的函数,该函数使用提供的函数自动构造表达式并相应地命名这些表达式:

mutator <- function(f, ...) {
  f_expr <- enquo(f)
  exprs <- enquos(...)

  ## Same code as in my_mutate above, but with an arbitrary function
  set_names(
    map( exprs, ~quo((!!f_expr)(!!.x)) ),
    str_c( quo_name(f_expr), "_", map_chr(exprs, quo_name) )
  )
}

## Example usage
mutator( sd, mpg, cyl )
# $sd_mpg
# <quosure>
#   expr: ^^sd(^mpg)
#   env:  0x555e05260020

# $sd_cyl
# <quosure>
#   expr: ^^sd(^cyl)
#   env:  0x555e05273af8

我们现在可以使用新的mutator函数将my_mutate重新定义为一个简单的单行:

my_mutate2 <- function(df, ...) {
  mutate( df, !!!mutator(mean, ...), !!!mutator(sum, ...) )
}

0
投票

您似乎找到了使用mutate_at的答案,但如果您需要在另一个上下文中执行此操作,我将添加以下方法。

如果您使用以下函数,您将看到quos(...)返回与您的参数对应的quosures列表。

watch_quos <- function(...){
    quos_args <- quos(...)
    return(quos_args)
}  
# Returns a list of closures
watch_quos(hello, iam, several, arguments)

因此,您可以使用quosquo_name中的一个将sapply的结果轻松转换为将lapply应用于每个引用参数的字符列表(或矢量):

quo_names <- function(...) {
   quos_args <- quos(...)
   char_args <- lapply(quos_args, quo_name)
   return(char_args)
}
# Returns a character list
quo_names(hello, iwill, be, char, arguments)
© www.soinside.com 2019 - 2024. All rights reserved.