3

我正在尝试编写一个自定义函数,我想在其中使用该cor.test函数,但我无法取消引用创建工作公式所需的参数。

这是我目前无法使用的东西-

library(rlang)

# custom function
tryfn <- function(data, x, y) {
  stats::cor.test(
    formula = rlang::new_formula(NULL, {{ x }} + {{ y }}),
    data = data,
    method = "pearson"
  )
}

# using the function
tryfn(mtcars, wt, mpg)
#> Error in rlang::new_formula(NULL, {: object 'wt' not found

我尝试了这种方式,因为如果我不必在函数环境中取消引用公式,它似乎可以工作。

# without unquoting inside another function
print(rlang::new_formula(NULL, quote(x + y)))
#> ~x + y

关于如何实现这一点的任何想法?

4

2 回答 2

5

重要的是要记住这rlang::quobase::quote. 在实践中,后者最终基本上等同于rlang::expr. 插值与{{相应的环境创建quosures,因此它是以下情况的快捷方式:

x <- 0

with_curly <- function(foo) {
  x <- 1
  rlang::eval_tidy({{ foo }})
}

with_curly(x)
# 0

with_enquo <- function(foo) {
  x <- 1
  rlang::eval_tidy(rlang::enquo(foo))
}

with_enquo(x)
# 0

另一方面,除了用户输入的内容外,enexpr行为类似:quote

with_enexpr <- function(foo) {
  x <- 1
  rlang::eval_tidy(rlang::enexpr(foo))
}

with_enexpr(x)
# 1

根据我的经验,quosures 不能很好地(或根本不)与任何不明确支持它们的函数一起使用,并且许多 R 函数需要“原始”表达式。即使在打印过程中,您也可以看到它们的处理方式不同:

foo <- function(foo) {
  rlang::qq_show({{ foo }})
  rlang::qq_show(!!rlang::enexpr(foo))
  invisible()
}

foo(x)
# ^x
# x

这意味着,至少就目前而言,创建简单表达式没有捷径可走,而且您必须走很长的路:

编辑:不完全正确。简单的表达式没有捷径可走,但您仍然可以使用 quosures 创建公式。请参阅穆迪的回答和下面的评论。


时不时地退一步也是值得的,记住你不需要到处都进行非标准的评估:

tryfn <- function(data, x, y) {
  stats::cor.test(
    formula = as.formula(glue::glue("~ {x} + {y}")),
    data = data,
    method = "pearson"
  )
}

tryfn(mtcars, "wt", "mpg")
于 2019-07-25T21:39:05.813 回答
2

您的问题来自以下事实:

  • new_formula()需要调用或命名对象作为输入,并且您希望它使用 NSE :
rlang::new_formula(NULL, wt + mpg)
#> Error in rlang::new_formula(NULL, wt + mpg): objet 'wt' introuvable
rlang::new_formula(NULL, quote(wt + mpg))
#> ~wt + mpg
  • new_formula()不支持准报价:
quoted_expr <- quote(wt + mpg)
rlang::new_formula(NULL, !!quote(quoted_expr))
#> Error in !quote(quoted_expr): type de l'argument incorrect

(看怎么!!不识别)

解决这两个问题的一种方法是从支持准引用的函数创建带引号的表达式。这个功能是expr()


tryfn <- function(data, x, y) {
  stats::cor.test(
    formula = rlang::new_formula(NULL, rlang::expr({{x}} + {{y}})),
    data = data,
    method = "pearson"
  )
}

tryfn(mtcars, wt, mpg)
#> 
#>  Pearson's product-moment correlation
#> 
#> data:  wt and mpg
#> t = -9.559, df = 30, p-value = 1.294e-10
#> alternative hypothesis: true correlation is not equal to 0
#> 95 percent confidence interval:
#>  -0.9338264 -0.7440872
#> sample estimates:
#>        cor 
#> -0.8676594
于 2019-08-08T16:39:49.537 回答