在函数内部找不到对象ddply的错误
这真的挑战了我debuggingR代码的能力。
我想使用ddply()
将相同的function应用到按顺序命名的不同列; 例如。 a,b,c。 为此,我打算重复传递列名作为string,并使用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甚至在函数内部定义!
我认为这个问题的答案, 循环创build新variables在ddply ,可能会帮助我,但我今天做了足够的头撞,现在是时候举手,寻求帮助。
您可以使用do.call
和call
的组合在NewColName
仍然可见的环境中构build调用:
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(df,sv) b Ave 1 0 1.5 2 1 3.5
今天解决这个问题的方法就是summarize
here(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中,捕捉当前上下文。
偶尔遇到这样的问题时,把ddply
与summarize
或transform
或什么东西,而不是足够聪明,以神圣的导航各种环境的来龙去脉,我倾向于ddply
的问题,通过简单地不使用summarize
,而是使用我自己的匿名function:
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)
显然,手工做这件事是有代价的,但是往往避免了处理好ddply
和summarize
出来的评估问题的头痛。 当然,这并不是说哈德利不会出现解决scheme。
问题在于plyr包本身的代码。 在汇总函数中,有一行eval(substitute(...),.data,parent.frame())
。 这是众所周知的parent.frame()可以做相当时髦和意想不到的东西。 Ť
他的解决scheme@James是一个非常好的解决方法, 但是如果我记得正确@Hadley自己之前说过,plyr包不打算在函数中使用。
对不起,我错了。 目前已知的是,plyr软件包在这些情况下会出现问题。
因此,我给你一个问题的基本解决scheme:
myFunction <- function(x, y){ NewColName = "a" z = aggregate(x[NewColName],x[y],mean,na.rm=TRUE) return(z) } > myFunction(df,sv) ba 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) df = data.frame(a,b,c) sv = c("b") ColName = "a" ddply(df, 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=df,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=df,y=sv)
通过使用get
从早期的环境中拉出myparse,我们可以走得更近,但仍然必须通过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=df,y=sv) expression(a) <environment: 0x0275a9b4> b Ave 1 0 1.5 2 1 3.5
我怀疑ddply已经在ddply
中进行了评估,这就是为什么我尝试的所有parent.frame()
和sys.frame()
策略都失败了。