在函数中ddply找不到对象的对象

问题描述:

这真的对我调试R代码的能力提出了挑战。在函数中ddply找不到对象的对象

我想用ddply()相同的功能,适用于按顺序命名不同的列;例如。 a,b,c。为此,我打算重复传递列名作为字符串,并使用eval(parse(text=ColName))来允许函数引用它。我从另一个答案中抓住了这个技巧。

这工作得很好,直到我把ddply()另一个函数内。以下是示例代码:

# Required packages: 
library(plyr) 

myFunction <- function(x, y){ 
    NewColName = "a" 
    z = ddply(x, y, summarize, 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 

a = c(1,2,3,4) 
b = c(0,0,1,1) 
c = c(5,6,7,8) 
df = data.frame(a,b,c) 
sv = c("b") 

#This works. 
ColName = "a" 
ddply(df, sv, summarize, 
     Ave = mean(eval(parse(text=ColName)), na.rm=TRUE) 
) 

#This doesn't work 
#Produces error: "Error in parse(text = NewColName) : object 'NewColName' not found" 
myFunction(df,sv) 

#Output in both cases should be 
# b Ave 
#1 0 1.5 
#2 1 3.5 

任何想法? NewColName甚至在函数内定义!

我认为这个问题的答案loops-to-create-new-variables-in-ddply可能对我有帮助,但是我今天做了足够的头撞,现在是时候举手并寻求帮助。

您可以用do.callcall组合做这个来构建呼叫的环境下NewColName仍清晰可见:

myFunction <- function(x,y){ 
NewColName <- "a" 
z <- do.call("ddply",list(x, y, summarize, Ave = call("mean",as.symbol(NewColName),na.rm=TRUE))) 
return(z) 
} 

myFunction(d.f,sv) 
    b Ave 
1 0 1.5 
2 1 3.5 

看起来像你有环境问题。全球分配解决了这个问题,但在一个人的灵魂的费用:

library(plyr) 

a = c(1,2,3,4) 
b = c(0,0,1,1) 
c = c(5,6,7,8) 
d.f = data.frame(a,b,c) 
sv = c("b") 

ColName = "a" 
ddply(d.f, sv, summarize, 
     Ave = mean(eval(parse(text=ColName)), na.rm=TRUE) 
) 

myFunction <- function(x, y){ 
    NewColName <<- "a" 
    z = ddply(x, y, summarize, 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 

myFunction(x=d.f,y=sv) 

eval正在寻找在parent.frame(1)。所以,如果你不是定义之外的MyFunction NewColName它应该工作:

rm(NewColName) 
NewColName <- "a" 
myFunction <- function(x, y){ 

    z = ddply(x, y, summarize, 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 
myFunction(x=d.f,y=sv) 

通过使用get拔出从早期环境my.parse,我们可以得出非常接近,但还是要过curenv作为一个全球性的:

myFunction <- function(x, y){ 
    NewColName <- "a" 
    my.parse <- parse(text=NewColName) 
    print(my.parse) 
    curenv <<- environment() 
    print(curenv) 

    z = ddply(x, y, summarize, 
      Ave = mean(eval(get("my.parse" , envir=curenv)), na.rm=TRUE) 
    ) 
    return(z) 
} 

> myFunction(x=d.f,y=sv) 
expression(a) 
<environment: 0x0275a9b4> 
    b Ave 
1 0 1.5 
2 1 3.5 

我怀疑ddply在.GlobalEnv评估已,这就是为什么所有的parent.frame()sys.frame()战略的我试过失败。

+0

我怀疑该解决方案可能需要@Hadley函数:-) –

+0

尝试所有这些努力。群头猛击永远是我的赞赏......我会保持灵魂 –

summarizetransform或东西结合时ddply,并且不是足够聪明可以洞察到浏览各种环境的来龙去脉我倾向于通过简单地不使用summarize到侧步的问题,偶尔会碰到这样的问题,而不是用自己的匿名函数:

myFunction <- function(x, y){ 
    NewColName <- "a" 
    z <- ddply(x, y, .fun = function(xx,col){ 
          c(Ave = mean(xx[,col],na.rm=TRUE))}, 
       NewColName) 
    return(z) 
} 

myFunction(df,sv) 

显然,是“手动”做这个东西成本,但它往往避免处理那些来自结合ddplysummarize评价问题的头痛。这并不是说,当然,哈德利将无法与解决方案展示了......

+2

在我修复这个错误之前,这是我推荐的解决方法。请注意,您可以在匿名函数中使用'transform'等。 – hadley

+0

@joran我实施了你的解决方案,它为我工作。我只是好奇为什么在ddply中有这个范围问题?是因为汇总创建了一个新的数据框,并且不能访问这个colName? –

+0

@ user3801801它与非标准评估取代函数参数有关。我必须对源代码进行筛选以提醒自己关于具体问题,但基本上它与R知道如何评估论据(即在当前机箱的环境中,在全球环境中,在某处之间)。 – joran

问题在于plyr软件包本身的代码。在汇总功能中,有一行eval(substitute(...),.data,parent.frame())。众所周知,parent.frame()可以做出非常时髦和意想不到的事情。 T

他对@James的解决方案是一个非常好的解决方法,,但如果我记得正确@Hadley自己说之前,plyr包不打算在函数内使用。

对不起,我在这里是错的。据了解,目前,plyr软件包在这些情况下会出现问题。

因此,我给你对这个问题的基础溶液:

myFunction <- function(x, y){ 
    NewColName = "a" 
    z = aggregate(x[NewColName],x[y],mean,na.rm=TRUE) 
    return(z) 
} 
> myFunction(df,sv) 
    b a 
1 0 1.5 
2 1 3.5 
+0

+1用于“避免总结”解决方案并提供问题的实际解释。 ;) – joran

+0

+1肯定是花时间来解释parent.frame()问题。看起来很奇怪,一个函数不能在另一个函数中使用,因为它迫使你编写连续的代码。也许@Hadley可以发表评论。 –

+0

我当然从来没有声称,plyr不打算在功能内使用 - 我一直说这是一个错误,我目前缺乏理解修复:( – hadley

今天的解决这个问题,使summarizehere(summarize)。例如

myFunction <- function(x, y){ 
    NewColName = "a" 
    z = ddply(x, y, here(summarize), 
      Ave = mean(eval(parse(text=NewColName)), na.rm=TRUE) 
    ) 
    return(z) 
} 

here(f),2012年12月添加到plyr,捕获当前上下文。

+0

辉煌!当一起使用lubridate和plyr时,请确保您特别提到plyr :: here()(因为lubridate不幸在这里重新定义()) –

+0

更多信息:https://github.com/hadley/plyr/问题/ 3 – Lennert