Object not found error with ddply inside function


To naprawdę podważyło moją zdolność do debugowania kodu R.
Chcę użyć funkcji
ddply ()
, aby zastosować te same funkcje do różnych kolumn z kolejnymi nazwami, takimi jak a, b, c. W tym celu zamierzam wielokrotnie przekazywać nazwę kolumny jako ciąg i używać
eval (parse (text = ColName))
, aby umożliwić funkcji odwoływanie się do niej. Zaczerpnąłem tę technikę z innej odpowiedzi.
I działa dobrze, o ile nie wstawię
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 zdefiniowane wewnątrz funkcji!
Pomyślałem, że odpowiedź na to pytanie

loops-to-create-new-variables-in-ddply
https://coderoad.ru/5873922/, może mi pomóc, ale na dziś wycierpiałem już wystarczająco dużo i czas podnieść rękę i poprosić o pomoc.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Dzisiejszym rozwiązaniem tego pytania jest zmiana
summarize
na
tutaj (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)
, dodane do plyr w grudniu 2012 r., odzwierciedla aktualny kontekst.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz to zrobić za pomocą kombinacji
do.call
i
call
, aby zbudować wywołanie w środowisku, w którym
NewColName
jest nadal widoczny:
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
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Czasami napotykam podobne problemy, łącząc
ddply
z
summarize
lub
transform
lub czymkolwiek, i nie będąc na tyle sprytnym, by odgadnąć wszystkie zawiłości poruszania się po różnych środowiskach, staram się ominąć ten problem, po prostu nie używając
summarize
, a zamiast tego używam własnej funkcji anonimowej:
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 warto to zrobić „ręcznie”, ale często pozwala to uniknąć problemów związanych z punktacją, gdy łączysz
ddply
i
summarize
. Oczywiście nie oznacza to, że Hadley nie znajdzie rozwiązania ...
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Problem leży w kodzie samego pakietu plyr. Funkcja podsumowująca zawiera wiersz
eval (substitute (...),. Data, parent.frame ())
. Powszechnie wiadomo, że parent.frame () może robić naprawdę niesamowite i nieoczekiwane rzeczy. T
Rozwiązanie @ Jamesa to bardzo fajne obejście,
<s>
ale jeśli dobrze pamiętam, sam @Hadley zwykł mawiać, że pakiet plyr nie jest przeznaczony do użycia w funkcjach.
</s>
Przepraszam pomyliłam się. Jednak obecnie wiadomo, że pakiet Plyr powoduje problemy w takich sytuacjach.
Podaję więc podstawowe rozwiązanie tego 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
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Wygląda na to, że masz problemy ze środowiskiem. Globalne zadanie 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
patrzy na parent.frame (1). Więc jeśli zamiast tego zdefiniujesz NewColName poza MyFunction, powinno to zadział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
, aby pobrać my.parse z wcześniejszego środowiska, możemy być znacznie bliżej, ale nadal musimy przekazać curenv jako globalne:
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
jest już oceniany w .GlobalEnv, więc wszystkie strategie
parent.frame ()
i
sys.frame ()
, które mam próby nie powiodły się.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się