Объект не обнаружил ошибку с ddply внутри функции
Это действительно оспаривало мою способность отлаживать 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, может помочь мне, но я сделал достаточно головокружительных на сегодняшний день, и мне пора поднять руку и обратитесь за помощью.
Ответы
Ответ 1
Вы можете сделать это с помощью комбинации 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
Сегодня решение этого вопроса состоит в том, чтобы сделать 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)
, добавленный в plyr в декабре 2012 года, фиксирует текущий контекст.
Ответ 3
Иногда я сталкиваюсь с такими проблемами при объединении 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
. Это не означает, конечно, что Хэдли не появится с решением...
Ответ 4
Проблема заключается в коде самого пакета plyr. В функции суммирования есть строка eval(substitute(...),.data,parent.frame())
. Хорошо известно, что parent.frame() может делать довольно забавные и неожиданные вещи. Т
его решение @James - очень приятное обходное решение, , но если я помню, как правильно сказал сам Хэдли, пакет 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
Ответ 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). Поэтому, если вы вместо этого определяете NewColName вне MyFunction, он должен работать:
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()
, которые я пробовал, не удались.