R:将表达式传递给内部函数
Posted
技术标签:
【中文标题】R:将表达式传递给内部函数【英文标题】:R: passing expression to an inner function 【发布时间】: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 可能会满足您的需求。否则,为每个函数编写一个程序员和交互式版本:交互式版本捕获表达式,然后调用。从长远来看,无论哪种方式都会为您节省很多痛苦。
【参考方案1】:
通过将字符串传递给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)
【讨论】:
@richie:谢谢,是的,但我一直在寻找一种避免传递字符串的方法。我希望这些函数像 R 中的许多其他函数一样工作,这些函数将不带引号的表达式作为参数。 查看我对上一个问题的回答,了解fn
的第三个(格子样式)规范。 ***.com/questions/4682709/…
@Richie 是的,我看到了,谢谢,这实际上是让它为内部函数工作的最简单的方法,但是将它适应上面的嵌套情况同样有问题。
@Richie 我看到了你的更新:topfn
现在接受一个表达式,但内部 fn
仍然接受一个字符串。我想两者都表达。上下文是我写了一个有用的函数fn
,它接受一个表达式参数,我写了另一个有用的包装器topfn
,它也接受一个表达式arg,我想把它传递给fn
。
@Prasad:希望这个版本没问题;过度使用eval
和substitute
让我头疼。【参考方案2】:
您可以使用三个点来收集参数并将它们传递给另一个函数,这是您的意思吗?
ftop=function(...) f(...)
f=function(a,b) a[b]
a=data.frame(b=10)
ftop(a,"b")
f(a,"b")
【讨论】:
不完全。我不想使用点,我希望将显式参数传递给内部函数。以上是关于R:将表达式传递给内部函数的主要内容,如果未能解决你的问题,请参考以下文章
c++ - 如何将多维数组传递给没有内部维度的函数? [复制]