这确实挑战了我调试R代码的能力。
我想使用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可能会对我有所帮助,但我已经为今天做了足够的敲击,是时候举手并寻求帮助了。
答案 0 :(得分:22)
今天这个问题的解决方案是将summarize
变为here(summarize)
。 e.g。
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,捕获了当前的背景。
答案 1 :(得分:14)
您可以使用do.call
和call
的组合来完成此操作,以便在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
答案 2 :(得分:9)
在将ddply
与summarize
或transform
或其他内容结合使用时,我偶尔会遇到这样的问题,并且不够聪明,无法判断导航各种环境的细节我倾向于通过简单地不使用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)
显然,“手动”执行此操作需要付出代价,但这通常可以避免处理ddply
和summarize
合并后的评估问题。当然,这并不是说哈德利不会出现解决方案......
答案 3 :(得分:4)
问题在于plyr包本身的代码。在汇总函数中,有一行eval(substitute(...),.data,parent.frame())
。众所周知,parent.frame()可以做很多时髦和意想不到的事情。 Ť
因此,我为您提供了解决问题的基本解决方案:
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
答案 4 :(得分:3)
看起来你有环境问题。全球任务解决了这个问题,但却以牺牲一个人的灵魂为代价:
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()
策略都失败了。