Objeto no encontrado error con ddply dentro de una función

Esto realmente ha desafiado mi capacidad para depurar el código R.

Deseo usar ddply() para aplicar las mismas funciones a diferentes columnas que se nombran secuencialmente; p.ej. a B C. Para hacer esto, bash pasar repetidamente el nombre de la columna como una cadena y usar el eval(parse(text=ColName)) para permitir que la función haga referencia a él. Agarré esta técnica de otra respuesta.

Y esto funciona bien, hasta que coloque ddply() dentro de otra función. Aquí está el código de ejemplo:

 # 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 

¿Algunas ideas? ¡NewColName incluso está definido dentro de la función!

Pensé que la respuesta a esta pregunta, loops-to-create-new-variables-in-ddply , podría ayudarme, pero ya he hecho bastantes golpes de cabeza para hoy y es hora de levantar la mano y pedir ayuda.

Puede hacer esto con una combinación de do.call y call para construir la llamada en un entorno donde NewColName aún esté visible:

 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 

La solución de hoy a esta pregunta es hacer un summarize here(summarize) . p.ej

 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) , agregado a plyr en diciembre de 2012, captura el contexto actual.

Ocasionalmente me encuentro con problemas como este al combinar ddply con summarize o transform o algo así, y como no soy lo suficientemente inteligente como para adivinar los entresijos de navegar en varios entornos, tiendo a eludir el problema simplemente al no usar el summarize y usar mi propio función anónima:

 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) 

Obviamente, hay un costo para hacer esto "manualmente", pero a menudo evita el dolor de cabeza de lidiar con los problemas de evaluación que surgen al combinar ddply y summarize . Eso no quiere decir, por supuesto, que Hadley no aparezca con una solución ...

El problema radica en el código del paquete plyr en sí. En la función de resumen, hay una línea eval(substitute(...),.data,parent.frame()) . Es bien sabido que parent.frame () puede hacer cosas bastante originales e inesperadas. T

La solución de @James es una solución muy buena, pero si mal no recuerdo, el propio Harley dijo antes que el paquete plyr no estaba destinado a ser utilizado dentro de las funciones.

Lo siento, me equivoqué aquí. Sin embargo, se sabe que, por el momento, el paquete plyr presenta problemas en estas situaciones.

Por lo tanto, le doy una solución base para el problema:

 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 

Parece que tienes un problema de medioambiente. La asignación global soluciona el problema, pero a costa de su alma:

 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 está buscando en parent.frame (1). Entonces, si define NewColName fuera de MyFunction, debería funcionar:

 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) 

Al usar get para extraer my.parse del entorno anterior, podemos acercarnos mucho más, pero aún tenemos que aprobar curenv como global:

 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)  b Ave 1 0 1.5 2 1 3.5 

Sospecho que ddply está evaluando en .GlobalEnv, razón por la cual parent.frame() todas las parent.frame() y sys.frame() que probé.