在mutate中使用引号:mutate _(。dots = ...)的替代方法

Cet*_*ttt 6 r dplyr rlang

我想将不同的功能应用于小标题中的同一列。这些功能存储在字符串中。我曾经用mutate_和这样的.dots参数来做到这一点:

library(dplyr)

myfuns <- c(f1 = "a^2", f2 = "exp(a)", f3 = "sqrt(a)")
tibble(a = 1:3) %>% 
  mutate_(.dots = myfuns)
Run Code Online (Sandbox Code Playgroud)

这种方法仍然可以正常工作,但mutate_不建议使用。我尝试使用mutaterlang软件包获得相同的结果,但是距离还很远。

在我的实际示例中,myfuns包含大约200个函数,因此不能一一键入。

提前致谢。

Kon*_*lph 6

对于采用单一输入的简单方程,提供函数本身就足够了,例如

iris %>% mutate_at(vars(-Species), sqrt)
Run Code Online (Sandbox Code Playgroud)

或者,当使用方程而不是简单函数时,通过公式:

iris %>% mutate_at(vars(-Species), ~ . ^ 2)
Run Code Online (Sandbox Code Playgroud)

当使用访问多个变量的方程时,您需要使用 rlang quosures 代替:

area = quo(Sepal.Length * Sepal.Width)
iris %>% mutate(Sepal.Area = !! area)
Run Code Online (Sandbox Code Playgroud)

在这里,quo创建一个“quosure” ——即你的方程的引用表示,与你使用字符串相同,除了与字符串不同的是,这个是正确的范围,可直接由 dplyr 使用,并且在概念上更清晰:它就像任何其他R 表达式,除非尚未评估。区别如下:

  • 1 + 2是一个带有 value 的表达式3
  • quo(1 + 2)是具有值的未计算的表达式1 + 2计算结果为 3,但需要明确地评价。那么我们如何评估一个未评估的表达式呢?好 …:

然后!!(发音为“bang bang”) 取消引用先前引用的表达式,即评估它 -在 的上下文中mutate。这很重要,因为Sepal.LengthSepal.Width只在mutate调用内部知道,而不是在调用外部知道。


在上述所有情况下,表达式也可以在列表中。唯一的区别是对于列表,您需要使用!!!而不是!!

funs = list(
    Sepal.Area = quo(Sepal.Length * Sepal.Width),
    Sepal.Ratio = quo(Sepal.Length / Sepal.Width)
)

iris %>% mutate(!!! funs)
Run Code Online (Sandbox Code Playgroud)

!!!操作称为“取消引用拼接”。这个想法是它将其参数的列表元素“拼接”到父调用中。也就是说,它似乎修改了调用,就好像它包含逐字逐字的列表元素作为参数(不过,这仅适用于mutate支持它的函数,例如)。


Art*_*lov 5

将字符串转换为表达式

myexprs <- purrr::map( myfuns, rlang::parse_expr )
Run Code Online (Sandbox Code Playgroud)

然后mutate使用quasiquotation将这些表达式传递给正则:

tibble(a = 1:3) %>% mutate( !!!myexprs )
# # A tibble: 3 x 4
#       a    f1    f2    f3
#   <int> <dbl> <dbl> <dbl>
# 1     1     1  2.72  1   
# 2     2     4  7.39  1.41
# 3     3     9 20.1   1.73
Run Code Online (Sandbox Code Playgroud)

请注意,这也适用于涉及多列的字符串/表达式。

  • @zeehio `parse_exprs` 不保留表达式名称(本例中为 `f1`、`f2`、`f3`),这些名称将成为结果的列名称。我今天早些时候打开了一个关于它的 [GitHub 问题](https://github.com/r-lib/rlang/issues/808)。 (2认同)