再次:在函数内设置环境

cof*_*nky 6 environment r function plyr

关于范围,环境和功能的讨论已经很多.参见此处此处.但是,我不确定我是否找到了解决以下问题的好方法:

 df <- data.frame(id=rep(LETTERS[1:2],each=2), x=1:4)
 d <- -1
 myfun <- function(df, d){
          require(plyr)
          new.dat <- ddply(df, .(id), transform, x=x*d) 
          return(new.dat)}
 myfun(df, 1)
Run Code Online (Sandbox Code Playgroud)

您可以轻松验证是否使用了全局定义d=-1,而不是d=1参数中提供的内容.(如果不d存在全局定义,则object not found返回消息)现在最大的问题是:如何d使用所使用的函数而不是全局定义的参数d

我的印象是以下应该有效:

      myfun2 <- function(df, d){
          here <- environment()
          new.dat <- ddply(df, .(id), transform, x=x*with(here,d)) 
          return(new.dat)}
      myfun2(df, 1)
Run Code Online (Sandbox Code Playgroud)

我的理解是从环境中with(here, d)检索对象.所以,结果应该是.但是,返回错误,说dhere1

  Error in eval(substitute(expr), data, enclos = parent.frame()) : 
   invalid 'envir' argument of type 'closure' 
Run Code Online (Sandbox Code Playgroud)

我不确定我理解为什么这不起作用,如果有人能够对此有所了解,或者如果你能提供替代解决方案,我会很高兴.请注意,将整个ddply-statement 包装起来with(...)似乎也没有帮助.

有效的解决方案是attach函数内的当前环境:

 myfun3 <- function(df, d){
   here <- environment()
   attach(here)
   new.dat <- ddply(df, .(id), transform, x=x*d) 
   detach(here)
   return(new.dat)
 }
Run Code Online (Sandbox Code Playgroud)

但我不喜欢这个解决方案,因为它通过屏蔽全局定义d的本地工作d,我认为不是很优雅.

任何评论/指针都表示赞赏.

Ric*_*ton 4

要唤醒惰性求值并确保您使用的是本地d参数,请使用force。添加这一行:

d <- force(d)
Run Code Online (Sandbox Code Playgroud)

到 开始myfun


好吧,看来我误解了这个问题。在这种情况下,问题是ddply具有非标准评估,并且仅在应用转换时查找内部变量,因此即使您它df也看不到本地变量。正如 Hadley 指出的,您需要将一个调用包装到.dforcetransformhere

myfun <- function(df, d){
      require(plyr)
      new.dat <- ddply(df, .(id), here(transform), x=x*d) 
      return(new.dat)}
Run Code Online (Sandbox Code Playgroud)

不相关的小代码改进:由于您没有对returns 的
情况执行任何操作,因此您应该将其替换为. 是一个改进的requireFALSElibrary
mutate直接替代替代transform
你不需要明确的return.

myfun <- function(df, d){
      library(plyr)
      ddply(df, .(id), here(mutate), x=x*d)}
Run Code Online (Sandbox Code Playgroud)