【问题标题】:Nonstandard evaluation of list of variable names变量名列表的非标准评估
【发布时间】:2018-09-18 18:05:12
【问题描述】:

我正在 R 中编写一个估计程序,循环遍历用户声明的 data.frame 中的变量名称列表。我试图避免要求用户引用变量以使他们的生活更轻松(目标是将其上传到 CRAN,因此我们非常关心用户体验)。

为了防止 R 尝试计算变量名,我构造了函数 alt(),它类似于 c()list() 的替代方法,但不计算元素。

我的问题是如何优雅地取消alt() 函数,让用户可以少学习一个函数。这是一个简单的 MWE,希望能说明问题:

## Construct non-evaluating list function
alt <- function(...) {
    alt <- as.list(substitute(list(...)))
    return(alt[-1])
}

## Construct function that enquotes non-evaluated vectors
## contained in 'alt()'. Perhaps enquoting variable names 
## is unavoidable because the data set is stored as a 
## data.frame, but at least the user will not have to do it.
restring <- function(vector) {
    vector <- deparse(vector)
    if (substr(vector, start = 1, stop = 2) == "c(") {
        vector <- substr(vector, 3, nchar(vector) - 1)
        vector <- strsplit(vector, ", ")[[1]]
    }
    return(vector)
}

## Example of a function that loops over the list above
## for a given data set. The function simply prints out 
## the columns declared in each element of 'alt()'.
test <- function(data, vlist) {
    for (i in 1:length(vlist)) {
        print(paste0("Data set ", i, ":"))
        print(data[, restring(vlist[[i]])])
    }
}

## Construct example data
N <- 4
df <- data.frame(x1 = c(1, 2),
                 x2 = c(3, 4))

## Example of user-declared list of variables to loop over
vlist <- alt(x1, c(x1, x2))

## Output from running this example
> test(df, vlist)
[1] "Data set 1:"
[1] 1 2
[1] "Data set 2:"
  x1 x2
1  1  3
2  2  4

用户也可以声明

test(df, alt(x1, c(x1, x2)))

但如果我不必要求用户使用不同的函数来声明这些变量列表,那就太好了。如果它可以使用标准 R 函数工作,例如

test(df, list(x1, c(x1, x2)))

那太好了,但除了使用 deparse(substitute()) 执行一些笨拙的字符串操作之外,我找不到其他方法,类似于 restring() 函数(不确定 CRAN 对此有何感受)。

对于这个非标准评估问题的任何想法都将不胜感激。另外,如果alt() 使用起来很容易以至于不值得删除,那也很高兴知道。

【问题讨论】:

  • 如果您希望他们能够在主要的test() 函数调用之外使用符号,例如vlist &lt;- alt(x1, c(x1, x2)),那么您确实需要保留alt()。当您调用test() 时,您可以进行一些非标准评估,但是当您真正想要强制评估时,这将无济于事。做这些事情似乎是个好主意,但是当用户编写自己的函数来包装这些函数时,事情会变得非常混乱。如果他们只需要学习一个全新的范例,我不确定避免引用是否会使事情变得更容易。
  • 公式是人们捕捉符号而不是评估它们的另一种方式。例如vlist &lt;- list(~x1, ~x1+x2)
  • @MrFlick 非常感谢您的回复。我没有考虑过使用公式。但是你提到在test() 之外使用符号真的很重要,而且是我没有考虑过的。鉴于此,我认为我确实必须坚持使用 alt() 函数。同样,用户体验是我们关心的问题,如果主函数可以用于更复杂的设置,那么用户学习一个简单的辅助函数来列出变量的成本似乎是值得的。再次感谢您指出这一点!

标签: r list function dataframe evaluation


【解决方案1】:

更紧凑的选项是 en_exprs 来自 rlang

library(rlang)
alt1 <- function(...) enexprs(...)
test(df, alt1(x1, c(x1, x2)))
#[1] "Data set 1:"
#[1] 1 2
#[1] "Data set 2:"
#  x1 x2
#1  1  3
#2  2  4

或者不使用任何外部包,quotelist中的表达式

test(df, list(quote(x1), quote(c(x1, x2))))
#[1] "Data set 1:"
#[1] 1 2
#[1] "Data set 2:"
#  x1 x2
#1  1  3
#2  2  4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    • 2015-11-12
    • 1970-01-01
    • 2020-06-08
    • 2016-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多