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

发布于 2024-10-11 17:36:10 字数 1660 浏览 8 评论 0原文

进一步深入研究R评估的奥秘...这与我之前的问题密切相关( 如何编写计算数据帧内表达式的 R 函数)。假设我想编写一个函数 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< /code> 不起作用:

> 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,但读完后并没有特别受启发。任何指向我可以查看示例的函数源代码的指针也很有帮助。

Further delving into the mysteries of R evaluation...This is closely related to my previous question ( How to write an R function that evaluates an expression within a data-frame ). Let's say I want to write a function topfn that takes a data-frame and an expression involving column-names of that data-frame. I want to pass both these arguments on to another function fn that actually evaluates the expression within the "environment" of the data-frame. And I want both fn and topfn to work correctly when passed a data-frame and an expression

My first attempt, as suggested in the answer to the above question, is to define:

 fn <- function(dfr, expr) {
   mf <- match.call()
   eval( mf$expr, envir = dfr )
 }

And define topfn like this:

topfn <- function(df, ex) {
  mf <- match.call()
  fn(df, mf$ex) 
}

Now if I have a data-frame

df <- data.frame( a = 1:5, b = 1:5 )

the inner function fn works fine:

> fn(df,a)
[1] 1 2 3 4 5

But the topfn does not work:

> topfn(df,a)
mf$ex

To fix this I first check the class of topfn(df,a),

> class(topfn(df,a))
[1] "call"

This gives me an idea for an ugly hack to re-define fn as follows:

fn <- function(dfr, expr) {
  mf <- match.call()
  res <- eval(mf$expr, envir = dfr)  
  if(class(res) == 'call')
    eval(expr, envir = dfr) else
  res
}

And now both functions work:

> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5

As I said, this looks like an ugly hack. Is there a better way (or more standard idiom) to get these working?
I've consulted Lumley's curiously-named Standard NonStandard Evaluation Rules document http://developer.r-project.org/nonstandard-eval.pdf but wasn't particularly enlightened after reading it. Also helpful would be any pointers to source-code of functions I can look at for examples.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

筱果果 2024-10-18 17:36:11

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

This is most easily avoided by passing strings into topfn instead of expressions.

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

EDIT:

You could let the user pass expressions in, but use strings underneath for your convenience.

Change topfn to

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

ANOTHER EDIT:

This seems to work:

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)
天涯离梦残月幽梦 2024-10-18 17:36:11

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

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

a=data.frame(b=10)

ftop(a,"b")

f(a,"b")

You can use three dots to gather arguments and pass them to another function, is that what you mean?

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

a=data.frame(b=10)

ftop(a,"b")

f(a,"b")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文