2011-12-05 36 views
5

我想写一个自定义函数的包装,它需要一些向量作为输入(如:mtcars$hp,mtcars$am等)将输入作为数据帧名称(如data参数,例如:mtcars)和变量名称(如:hpam),如大多数标准函数一样。`With`使用内部函数(包装)

但我有一些问题,我提出了“演示”功能(大约mean的包装不起作用

代码:

f <- function(x, data=NULL) { 
    if (!missing(data)) { 
     with(data, mean(x)) 
    } else { 
     mean(x) 
    } 
} 

运行针对课程的载体作品:

> f(mtcars$hp) 
[1] 146.69 

with不幸失败:

> f(hp, mtcars) 
Error in with(d, mean(x)) : object 'hp' not found 

虽然在全球环境/没有我的自定义函数作品的权利:

> with(mtcars, mean(hp)) 
[1] 146.69 

我试图做一些实验substitutedeparse和其他人,但没有成功。任何暗示都会受到欢迎!

+5

看看@Hadley Wickham的wiki文章:https://github.com/hadley/devtools/wiki /评估 – Andrie

+1

它不应该是'f(hp,mtcars)'? – James

+1

您可能想要探索的另一个选项是使用公式,因此您可以稍微区别它 - foo(〜hp,mtcars) - 然后使用像model.frame这样的东西来获取值。 – Spacedman

回答

10

这里的谜题的关键部分:

f <- function(x,data=NULL) { 
    eval(match.call()$x,data) # this is mtcars$hp, so just take the mean of it or whatever 
} 

> f(hp,mtcars) 
[1] 110 110 93 110 175 105 245 62 95 123 123 180 180 180 205 215 230 66 52 65 97 150 150 245 175 66 
[27] 91 113 264 175 335 109 

# it even works without a data.frame specified: 
> f(seq(10)) 
[1] 1 2 3 4 5 6 7 8 9 10 

见@ Andrie的链接@哈德利的文档,为什么它的工作原理的解释。请参阅@ Hadley的注意事项:f()不能从另一个函数内部运行。

基本上R使用懒惰评估(例如,它不会评估的东西,直到他们实际使用)。所以你可以通过它hp逃脱,因为它仍然是一个未评估的符号,直到它出现在某个地方。由于match.call抓住它作为一个符号,并等待评估它,一切都很好。

然后eval在指定的环境中对其进行评估。根据?eval,第二个参数表示:

要评估expr的环境。也可以是NULL,一个 列表,一个数据帧,一个pairlist或一个指定给sys.call的整数。

因此,您的状态良好,可以是NULL(如果不传递data.frame)或data.frame。

证明懒惰的评价是,这不会返回一个错误(因为x是从来没有在函数中使用):

> g <- function(x) { 
+ 0 
+ } 
> g(hp) 
[1] 0 
+0

多么优雅的成语。感谢你(和哈德利)。 –

+0

大部分是哈德利。我记得它,但不足以在没有引用他(真棒)wiki的情况下将它从帽子里拿出来。 –

+0

确实非常整齐。总而言之,eveRy pRoblem是RT(F)M相关的... – aL3xa

-1

试试这个:

f <- function(x, data = NULL) { 
    if (is.null(data)) { 
     mean(x) 
    } else { 
     attach(data) 
     mean(x) 
     detach(data) 
    } 
} 

另外,在你的榜样,你输入的数据集而不是列。 你的榜样应当与F(HP,mtcars)

+0

不错的努力,但缺少一个括号,我不确定我更喜欢用'attach'来'',而且'f(hp,mtcars)'仍然会以“找不到hp”的方式失败。 –

3
f <- function(x, data=NULL) { 
    if (!missing(data)) { colname=deparse(substitute(x)) 
     mean(data[[colname]]) 
    } else { 
     mean(x) 
    } 
} 

f(hp, mtcars) 
[1] 146.6875 

(诚然不一样紧凑@ GSK的,我想我会尝试记住他的方法,并感谢Josh O'Brien指出现在已经修复的错误。)

+0

谢谢@DWin这个黑客! – daroczig