Object not found błąd z ddply wewnątrz funkcji
To naprawdę podważyło moją zdolność do debugowania kodu R.
Chcę użyć ddply()
, Aby zastosować te same funkcje do różnych kolumn, które są kolejno nazwane; np. a, b, c. w tym celu zamierzam wielokrotnie przekazywać nazwę kolumny jako ciąg znaków i używać eval(parse(text=ColName))
, aby umożliwić funkcji odwołanie się do niej. Chwyciłem tę technikę z innej odpowiedzi.
I to działa dobrze, dopóki nie umieszczę ddply()
wewnątrz innej funkcji. Oto przykładowy kod:
# 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
Jakieś pomysły? NewColName jest nawet zdefiniowana wewnątrz funkcji!
Pomyślałem, że odpowiedź na to pytanie, loops-to-create-new-variables-in-ddply , może mi pomóc, ale zrobiłem wystarczająco dużo w głowie na dziś i nadszedł czas, aby podnieść rękę i poprosić o pomoc.
5 answers
Możesz to zrobić za pomocą kombinacji do.call
i call
, aby skonstruować wywołanie w środowisku, w którym NewColName
jest nadal widoczne:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-30 08:54:00
Dzisiejszym rozwiązaniem tego pytania jest przekształcenie summarize
w here(summarize)
. np.
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)
, dodane 2012-02-12 (19: 00)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-27 18:38:26
Czasami napotykam takie problemy, gdy łączę ddply
z summarize
lub transform
lub czymś takim i nie będąc wystarczająco inteligentnym, aby odkrywać tajniki nawigacji w różnych środowiskach, zwykle robię krok na bok, po prostu nie używając summarize
, a zamiast tego używając mojej własnej anonimowej funkcji:
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)
Oczywiście robienie tego "ręcznie" jest kosztowne, ale często unika się bólu głowy związanego z rozwiązywaniem problemów związanych z oceną, które wynikają z połączenia ddply
i summarize
. To nie do powiedzmy, że Hadley nie znajdzie rozwiązania...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-05 13:47:21
Problem tkwi w kodzie samego pakietu plyr. W funkcji summarize znajduje się linia eval(substitute(...),.data,parent.frame())
. Wiadomo, że rodzic.frame() potrafi robić całkiem fajne i nieoczekiwane rzeczy. T
Rozwiązanie @James jest bardzo dobrym obejściem, ale jeśli dobrze pamiętam, sam @Hadley powiedział wcześniej, że pakiet plyr nie był przeznaczony do użycia w funkcjach.
Dlatego daję ci podstawowe rozwiązanie problemu:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-07 21:31:44
Wygląda na to, że masz problem ze środowiskiem. Globalny przydział rozwiązuje problem, ale kosztem własnej duszy: {]}
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
szuka rodzica.ramka (1) Więc jeśli zamiast tego zdefiniujesz NewColName poza Mojafunkcją, powinno działać:
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)
Używając get
do wyciągnięcia mojego.parse z wcześniejszego środowiska, możemy zbliżyć się znacznie bliżej, ale nadal musimy przekazać curenv jako globalny:
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
Podejrzewam, że ddply
ocenia wGlobalEnv już, dlatego wszystkie strategie parent.frame()
i sys.frame()
, które wypróbowałem, zawiodły.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-05 13:12:18