【问题标题】:Weird dplyr+NSE: using NSE in custom function inside mutate奇怪的 dplyr+NSE:在 mutate 的自定义函数中使用 NSE
【发布时间】:2018-12-29 01:39:36
【问题描述】:

dplyr::mutate 内的自定义函数中使用 NSE 时,我偶然发现了一个问题。考虑以下代码:

require(tidyverse)

f <- function(var) {
  varname <- deparse(substitute(var))
  v1      <- as.name(sprintf("%s.Width", varname))
  v2      <- as.name(sprintf("%s.Length", varname))
  return(substitute(v1 + v2))
}

iris %>% 
  mutate(
    test = f(Sepal) %>% eval()
  )

ff <- function(var) {
  varname <- deparse(substitute(var))
  v1      <- as.name(sprintf("%s.Width", varname))
  v2      <- as.name(sprintf("%s.Length", varname))
  substitute(v1 + v2) %>% eval.parent(n = 1)
}

iris %>% 
  mutate(
    test = ff(Sepal)
  )

这里f 工作正常,但需要对eval() 进行外部调用才能在mutate() 环境中执行代码。 这当然有点难看,并导致大量样板代码。我对这项工作的最佳猜测是ff,它试图在其调用环境中评估构造的表达式——我预计它是mutate() 环境。但是,这会引发 variable-not-found 错误。 关于如何进行这项工作以及潜在问题是什么的任何想法?本质上,我希望在 dplyr 动词中允许自定义“宏”。

【问题讨论】:

    标签: r dplyr nse


    【解决方案1】:

    使用!! tidy eval "unquote" 运算符:

    ff <- function(var) {
      varname <- deparse(substitute(var))
      v1      <- as.name(sprintf("%s.Width", varname))
      v2      <- as.name(sprintf("%s.Length", varname))
      substitute(v1 + v2)
    }
    
    iris %>% 
      head() %>% 
      mutate(
        test = !! ff(Sepal)
      )
    

    【讨论】:

    • 谢谢,但这只是 eval 的一个更好的变体,对吧?为什么我不能直接访问正确的环境?
    • @Jack 不完全是。 !! 运算符执行“取消引用”,而不是评估。我使用它是因为在新的 tidyeval 环境中它对我来说感觉更自然。但是您可以通过删除管道%&gt;% 来实现您正在尝试的内容(这会破坏调用环境的层次结构):eval.parent(substitute(v1 + v2), n = 1)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多