2012-04-16 12 views
5

Hoy me di cuenta de un comportamiento extraño con mi código R. Intenté un paquete {boot.StepAIC} que incluye una función de arranque para los resultados de la regresión paso a paso con el AIC. Sin embargo, no creo que el fondo estadístico sea aquí el problema (eso espero).
Puedo usar la función en el nivel superior de R. Este es mi código de ejemplo.funciona (boot.stepAIC) pero arroja un error dentro de otra función: ¿problema de entorno?

require(MASS) 
require(boot.StepAIC) 

n<-100 
x<-rnorm(n); y<-rnorm(n,sd=2); z<-rnorm(n,sd=3); res<-x+y+z+rnorm(n,sd=0.1) 
dat.test<-as.data.frame(cbind(x,y,z,res)) 
form.1<-as.formula(res~x+y+z) 
boot.stepAIC(lm(form.1, dat.test),dat.test) # should be OK - works at me 

Sin embargo, quería envolverlo en una función propia. Paso los datos y la fórmula a esa función. Pero me da un error dentro de boot.stepAIC() diciendo:

el ajuste del modelo fracasó en 100 muestras de arranque Error en strsplit (nam.vars, ":"): argumento que no es de carácter

# custom function 
fun.boot.lm.stepAIC<-function(dat,form) { 
    if(!inherits(form, "formula")) stop("No formula given") 
    fit.lm<-lm(formula=form,data=dat) 
    return(boot.stepAIC(object=fit.lm,data=dat)) 
} 
fun.boot.lm.stepAIC(dat=dat.test,form=form.1) 
# results in an error 

Entonces, ¿dónde está el error? Supongo que debe tener algo que ver con el entorno local y global, ¿no?

+0

No he usado 'boot.stepAIC' antes, pero sospecho que también puede tener que ver con cómo se pasa la fórmula a la función (que también está relacionada con los problemas del entorno). Consulte http://stackoverflow.com/q/6877534, http://stackoverflow.com/q/7666807 para obtener algunas ideas. En particular, la invocación de 'lm' o' boot.stepAIC' a través de 'do.call' puede ser útil ya que los argumentos se evalúan antes de pasarlos. También puede investigar la sugerencia' as.name' en los comentarios. Estos problemas son difíciles: ¡buena suerte! – Aaron

+0

http://stackoverflow.com/q/8998884/210673 también parece ser el mismo problema. – Aaron

+0

sí. Leí esto ya. Supongo que los problemas están conectados. – Sebastian

Respuesta

4

Usando do.call como en anova test fails on lme fits created with pasted formula proporciona la respuesta.

no tiene acceso a form cuando se ejecuta dentro de una función; que se puede recrear en el entorno global de esta manera; Vemos que lm usa form.1 como fórmula y eliminarlo hace que falle.

> form.1<-as.formula(res~x+y+z) 
> mm <- lm(form.1, dat.test) 
> mm$call 
lm(formula = form.1, data = dat.test) 
> rm(form.1) 
> boot.stepAIC(mm,dat.test) 
# same error as OP 

El uso de do.call funciona. Aquí también uso as.name; de lo contrario, el objeto mm lleva todo el conjunto de datos en lugar de solo el nombre.

> form.1<-as.formula(res~x+y+z) 
> mm <- do.call("lm", list(form.1, data=as.name("dat.test"))) 
> mm$call 
lm(formula = res ~ x + y + z, data = dat.test) 
> rm(form.1) 
> boot.stepAIC(mm,dat.test) 

Para aplicar esto al problema original, lo haría esto:

fun.boot.lm.stepAIC<-function(dat,form) { 
    if(!inherits(form, "formula")) stop("No formula given") 
    mm <- do.call("lm", list(form, data=as.name(dat))) 
    do.call("boot.stepAIC", list(mm,data=as.name(dat))) 
}  
form.1<-as.formula(res~x+y+z) 
fun.boot.lm.stepAIC(dat="dat.test",form=form1) 

Esto también funciona, pero todo el conjunto de datos se incluyen en el objeto final de salida, y la salida final a la consola , también.

+0

Gracias. Debido a la explicación exhaustiva, veo el punto. También leí las dos publicaciones relacionadas. Honestamente, todavía tengo un dolor de cabeza con estos problemas. ¿Cuál es el "caso de uso" para ese comportamiento? Paso dos objetos a esa función, por lo que debe ejecutarse en el contexto de la función de llamada. No veo sentido en R o boot.stepAIC (no sé a quién culpar) para redirigir al entorno global.El punto es cómo puedo estar seguro en qué contexto una función busca los objetos. Mi comprensión hasta ahora es, siempre uso do.call() en lugar de la función directamente. Alguna estrategia sobre eso? – Sebastian

+0

Bueno, jugué un poco con eso y aún trato de entender el contexto. En su último ejemplo, básicamente pasa el nombre de la variable global (o principal) y accede a la función la variable global dat.test. ¿Es una llamada por referencia? ¿Podría ser que las funciones de modelado usen a veces una estrategia de llamada por referencia incluso supongo que es puramente llamada por valor? – Sebastian

+0

1) 'boot.stepAIC' usa' update', que vuelve a ejecutar la llamada del modelo lineal; si la llamada tenía el nombre de un objeto de función (como 'form'), entonces ese objeto debe estar accesible. 2) Cada función tiene un entorno (en el que se creó, normalmente) y una cadena de entornos principales que busca para encontrar objetos. Sin embargo, ejecutar una función dentro de otra función no cambia esta cadena principal. Al final de la cadena se encuentra el entorno global, por lo que cuando 'form' se encuentra en el entorno global, puede encontrarlo. Pero cuando 'form' está en el entorno de la función de llamada, no puede. – Aaron

Cuestiones relacionadas