R:将表达式传递给内部函数

时间:2011-01-14 14:44:43

标签: r lazy-evaluation evaluation

进一步深入研究R评估的奥秘......这与我之前的问题(How to write an R function that evaluates an expression within a data-frame)密切相关。假设我想编写一个函数topfn,它接受​​一个数据框和一个涉及该数据框的列名的表达式。我想将这两个参数传递给另一个函数fn,它实际上在数据框的“环境”中评估表达式。 我希望fntopfn在传递数据框和表达式时正常工作

正如上述问题的答案中所建议的那样,我的第一次尝试是定义:

 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奇怪的标准非标准评估规则文件http://developer.r-project.org/nonstandard-eval.pdf,但在阅读之后并没有特别开明。对于我可以查看示例的函数源代码的任何指针也很有帮助。

2 个答案:

答案 0 :(得分:13)

通过将字符串传递给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")

编辑:

您可以让用户传入表达式,但为方便起见,请使用下面的字符串。

topfn更改为

topfn <- function(df, ex) 
{
  ex_txt <- deparse(substitute(ex))
  fn(df, ex_txt) 
}
topfn(df, a)             
topfn(df, 2 * a + b)

另一个编辑:

这似乎有效:

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)

答案 1 :(得分:1)

您可以使用三个点来收集参数并将它们传递给另一个函数,这就是您的意思吗?

ftop=function(...) f(...)
f=function(a,b) a[b]

a=data.frame(b=10)

ftop(a,"b")

f(a,"b")