2011-01-14 65 views
13

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

我第一次尝试都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 <- 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,但在阅读后并没有特别开悟。同样有帮助的是任何指向我可以查看示例的函数的源代码的指针。

+0

有R上的评价由哈德利韦翰的主题在这里有很大的wiki:HTTPS: //github.com/hadley/devtools/wiki/Evaluation – 2011-01-14 23:57:06

+1

正如我所建议的那样,您要仔细区分交互使用的函数和函数从其他功能被调用。调用任何使用替代和其他技巧的函数是非常困难的。换句话说,`fn`和`topfn`没有干净的方式来处理相同类型的输入 - 这是一件好事。 – hadley 2011-01-15 00:54:55

+1

@hadley我明白了你的观点:为交互式应用设计的功能可以使用替代/其他技巧,以便在控制台上输入它们(即不用引号等)。而仅被设计为被其他函数调用的函数不应该使用这些技巧,因为它们可能会不可预测地中断。特别是@Richie在他的回答结束时提供的解决方案,即使它在我上面的特定情况下工作 - 当在其他情况下使用时,它可能会中断(尤其是`fn`) - 我认为这就是'重新说,对吧? – 2011-01-15 01:05:02

回答

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") 

编辑:

您可以让用户通过表情,但骨子里使用字符串为您提供方便。

变化topfn

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

ANOTHER编辑:

这似乎工作:

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

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

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

a=data.frame(b=10) 

ftop(a,"b") 

f(a,"b")