【发布时间】:2011-06-09 04:46:26
【问题描述】:
进一步深入研究 R 评估的奥秘...这与我之前的问题 (How to write an R function that evaluates an expression within a data-frame) 密切相关。假设我想编写一个函数topfn,它接受一个数据框和一个涉及该数据框列名的表达式。我想将这两个参数传递给另一个函数fn,该函数实际上评估数据框“环境”内的表达式。 我希望 fn 和 topfn 在传递数据帧和表达式时都能正常工作
正如上述问题的答案所建议的,我的第一次尝试是定义:
fn <- function(dfr, expr) {
mf <- match.call()
eval( mf$expr, envir = dfr )
}
并像这样定义topfn:
topfn <- function(df, ex) {
mf <- match.call()
fn(df, mf$ex)
}
如果我有一个数据框
df <- data.frame( a = 1:5, b = 1:5 )
内部函数fn 工作正常:
> fn(df,a)
[1] 1 2 3 4 5
但是topfn 不起作用:
> topfn(df,a)
mf$ex
为了解决这个问题,我首先检查topfn(df,a) 的类,
> class(topfn(df,a))
[1] "call"
这让我想到了一个丑陋的黑客重新定义 fn 如下:
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
现在这两个函数都可以工作了:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
正如我所说,这看起来像一个丑陋的黑客。有没有更好的方法(或更标准的习语)来让这些工作? 我已经查阅了 Lumley 奇怪地命名为 Standard NonStandard Evaluation Rules 的文档 http://developer.r-project.org/nonstandard-eval.pdf,但在阅读后并没有特别开明。任何指向函数源代码的指针也很有帮助,我可以查看示例。
【问题讨论】:
-
Hadley Wickham 有一个很棒的关于 R 评估主题的 wiki:github.com/hadley/devtools/wiki/Evaluation
-
正如我建议的那样,您需要仔细区分交互式使用的函数和从其他函数调用的函数。调用任何使用替代和其他技巧的函数是非常困难的。换句话说,
fn和topfn都没有干净的方法来处理相同类型的输入 - 这是一件好事。 -
@hadley 我明白你的意思:为交互式使用而设计的函数可以使用替代/其他技巧来轻松在控制台上键入它们(即没有引号等)。并且仅设计为由其他函数调用的函数不应使用此类技巧,因为它们可能会意外中断。特别是,@Richie 在他的回答结束时提供的解决方案,即使它在我上面的特定场景中有效——在其他场景中使用时它可能会中断(尤其是
fn)——我认为这就是你的你说对吧? -
如果您能提供更多关于您想要实现的目标的详细信息,我将能够提供更具体的建议 - 很难在摘要中提供帮助。
-
两个选项:走 plyr/ggplot 路线并使用特殊函数引用。 .来自 plyr 可能会满足您的需求。否则,为每个函数编写一个程序员和交互式版本:交互式版本捕获表达式,然后调用。从长远来看,无论哪种方式都会为您节省很多痛苦。
标签: r lazy-evaluation evaluation