Pra*_*ani 14 evaluation r lazy-evaluation
进一步深入研究R评估的奥秘......这与我之前的问题(如何编写一个评估数据框内表达式的R函数)密切相关.假设我想编写一个函数topfn,它接受一个数据框和一个涉及该数据框的列名的表达式.我想将这两个参数传递给另一个fn实际评估数据框"环境"中表达式的函数.我想要两者fn并topfn在传递数据框和表达式时正常工作
根据上述问题的答案,我的第一次尝试是定义:
fn <- function(dfr, expr) {
mf <- match.call()
eval( mf$expr, envir = dfr )
}
Run Code Online (Sandbox Code Playgroud)
并定义topfn如下:
topfn <- function(df, ex) {
mf <- match.call()
fn(df, mf$ex)
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我有一个数据框架
df <- data.frame( a = 1:5, b = 1:5 )
Run Code Online (Sandbox Code Playgroud)
内部函数fn工作正常:
> fn(df,a)
[1] 1 2 3 4 5
Run Code Online (Sandbox Code Playgroud)
但是topfn不起作用:
> topfn(df,a)
mf$ex
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我首先检查一下topfn(df,a),
> class(topfn(df,a))
[1] "call"
Run Code Online (Sandbox Code Playgroud)
这给了我一个丑陋的黑客重新定义fn如下的想法:
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
Run Code Online (Sandbox Code Playgroud)
现在这两个功能都有效:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Run Code Online (Sandbox Code Playgroud)
正如我所说,这看起来像一个丑陋的黑客.是否有更好的方法(或更标准的习惯用法)来使这些工作?我已经查阅了Lumley奇怪的标准非标准评估规则文档http://developer.r-project.org/nonstandard-eval.pdf,但在阅读之后并没有特别开明.对于我可以查看示例的函数源代码的任何指针也很有帮助.
Ric*_*ton 14
通过将字符串传递给topfn而不是表达式,最容易避免这种情况.
topfn <- function(df, ex_txt)
{
fn(df, ex_txt)
}
fn <- function(dfr, expr_txt)
{
eval(parse(text = expr_txt), dfr)
}
df <- data.frame(a = 1:5, b = 1:5 )
fn(df, "a")
fn(df, "2 * a + b")
topfn(df, "a")
topfn(df, "2 * a + b")
Run Code Online (Sandbox Code Playgroud)
编辑:
您可以让用户传入表达式,但为方便起见,请使用下面的字符串.
更改topfn到
topfn <- function(df, ex)
{
ex_txt <- deparse(substitute(ex))
fn(df, ex_txt)
}
topfn(df, a)
topfn(df, 2 * a + b)
Run Code Online (Sandbox Code Playgroud)
另一个编辑:
这似乎有效:
topfn <- function(df, ex)
{
eval(substitute(fn(df, ex)))
}
fn <- function(dfr, expr)
{
eval(substitute(expr), dfr)
}
fn(df, a)
fn(df, 2 * a + b)
topfn(df, a)
topfn(df, 2 * a + b)
Run Code Online (Sandbox Code Playgroud)