在用户定义的函数中使用胶水进行变异

Posted

技术标签:

【中文标题】在用户定义的函数中使用胶水进行变异【英文标题】:Mutate using glue in a user defined function 【发布时间】:2021-10-07 22:34:03 【问题描述】:

我想使用glue 函数更改特定列中的值以包含另一列中的信息。

我通常是这样做的:

library(glue)
library(dplyr)
df = data.frame(x = c("Banana","Apple","Melon"),
                y = c(10,15,27),
                z = rep(c("something_else"),3))
df %>%
  mutate(x = glue("x (y)"))

输出:

#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

当我尝试使用数据框和列名作为用户定义函数中的输入来做同样的事情时,我的问题就出现了。

我最初的要求是使用双花括号和胶水函数来传递输入,但这会导致错误。

concatenate_value_to_string <- function(tbl,var1,var2) 
  tbl %>%
    mutate(var1 := glue("var1 (var2)"))


concatenate_value_to_string(df,x,y)
#> Error in UseMethod("mutate"): no applicable method for 'mutate' applied to an object of class "function"

由reprex package (v2.0.0) 于 2021 年 8 月 2 日创建

显然三重花括号不是这里的解决方案,有人可以帮我吗?

谢谢。

【问题讨论】:

【参考方案1】:

你可以使用pull()

concatenate_value_to_string <- function(tbl,var1,var2) 
  tbl %>%
    mutate(var1 :=  glue("pull(., var1) (pull(., var2))"))


concatenate_value_to_string(df,x,y)

concatenate_value_to_string(df,x,y)
#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

eval(expr(...))

concatenate_value_to_string <- function(tbl,var1,var2) 
  tbl %>%
    mutate(var1 :=  glue("eval(expr(var1)) (eval(expr(var2)))"))


concatenate_value_to_string(df,x,y)
#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

您尝试的方法不起作用,因为如果mutate() 是字符串的一部分,则foo 不能替换它,在上面的解决方案中,pull()expr() 这样做。

在这种情况下,我个人更愿意使用sprintf()

concatenate_value_to_string <- function(tbl,var1,var2) 
  tbl %>%
    mutate(var1 :=  sprintf("%s (%s)", var1, var2))


concatenate_value_to_string(df,x,y)
#>             x  y              z
#> 1 Banana (10) 10 something_else
#> 2  Apple (15) 15 something_else
#> 3  Melon (27) 27 something_else

【讨论】:

【参考方案2】:

当您想要传递参数名称而不是字符串时,这是另一个选项。函数enquo 用于扩散用户定义的变量,但不是ensym,它返回一个原始表达式enquo 返回一个quosure,它是一个绑定到环境的表达式。所以我们使用get_expr 来访问它的表达式,并用rlang::eval_tidybase::eval 包装它以在上下文中进行评估。

library(rlang)

concatenate_value_to_string <- function(tbl, var1, var2) 
  tbl %>%
    mutate(!!enquo(var1) := glue("eval_tidy(get_expr(enquo(var1))) (eval_tidy(get_expr(enquo(var2))))"))


concatenate_value_to_string(df, x, y)
            x  y              z
1 Banana (10) 10 something_else
2  Apple (15) 15 something_else
3  Melon (27) 27 something_else

【讨论】:

【参考方案3】:

另一种选择可能是:

concatenate_value_to_string <- function(tbl, var1, var2) 
    tbl %>%
        mutate(!!var1 := glue(".data[[var1]] (.data[[var2]])")) 


concatenate_value_to_string(df, "x", "y")

            x  y              z
1 Banana (10) 10 something_else
2  Apple (15) 15 something_else
3  Melon (27) 27 something_else

【讨论】:

以上是关于在用户定义的函数中使用胶水进行变异的主要内容,如果未能解决你的问题,请参考以下文章

遗传算法中适值函数的标定与大变异算法

GraphQL:如何重用相同的类型进行查询和变异?

使用胶水数据目录中定义的外部表红移光谱

变异位点的归一化(normalization of indel)

EXCEL 的自定义 VBA 函数中的用户定义警告

usort — 使用用户自定义的比较函数对数组中的值进行排序