2011-06-23 11 views
8

que he tenido problemas para entender todos los días la documentación sobre cómo se llaman métodos S3, y esta vez me está mordiendo.S3 y el orden de las clases

me disculparé por adelantado para pedir más de una pregunta, sino que están estrechamente relacionados. En el corazón de un complejo conjunto de funciones, creo muchos ajustes para glmnet, en particular los logísticos. Ahora, la documentación glmnet especifica su valor de retorno para tener ambas clases "glmnet" y (para la regresión logística) "lognet". De hecho, estos se especifican en este orden.

Sin embargo, mirando al final de la ejecución de glmnet, más justo después de la llamada a (la función interna) lognet, que establece la clase de fit a "LogNet", veo esta línea de código justo antes del regreso (de la variable fit):

class(fit) = c(class(fit), "glmnet") 

partir de esto, llego a la conclusión de que el orden de las clases es de hecho "LogNet", "glmnet".

Por desgracia, el ajuste que tenía, tenía (al igual que el documento sugiere):

> class(myfit) 
[1] "glmnet" "lognet" 

El problema con esto es la forma en métodos S3 se envían para ello, en particular, predict. Aquí está el código para predict.lognet:

function (object, newx, s = NULL, type = c("link", "response", 
    "coefficients", "class", "nonzero"), exact = FALSE, offset, 
    ...) 
{ 
    type = match.arg(type) 
    nfit = NextMethod("predict") #<- supposed to call predict.glmnet, I think 
    switch(type, response = { 
     pp = exp(-nfit) 
     1/(1 + pp) 
    }, class = ifelse(nfit > 0, 2, 1), nfit) 
} 

He añadido un comentario para explicar mi razonamiento. Ahora cuando llamo predecir en este myfit con un nuevo Datamatrix mydata y type="response", así:

predict(myfit, newx=mydata, type="response") 

, yo no, según la documentación, ver las probabilidades predichas, pero las combinaciones lineales, que es exactamente el resultado de llamar al predict.glmnet inmediatamente.

he intentado invertir el orden de las clases, así:

orgclass<-class(myfit) 
class(myfit)<-rev(orgclass) 

y luego hacer el predecir llamar de nuevo: he aquí: funciona! I do obtener las probabilidades.

lo tanto, aquí vienen algunas preguntas:

  1. Estoy en lo cierto 'habiendo aprendido' que S3 métodos se envían con el fin de aparición de las clases?
  2. Estoy en lo cierto al suponer el código en glmnet causaría el orden equivocado para el correcto envío de predict?
  3. En mi código no hay nada que manipule las clases explícita/visiblemente que yo sepa. ¿Qué podría causar la orden de cambiar?

Para completarlo: aquí algunos ejemplos de código para jugar con (como estoy haciendo yo ahora):

library(glmnet) 
y<-factor(sample(2, 100, replace=TRUE)) 
xs<-matrix(runif(100), ncol=1) 
colnames(xs)<-"x" 
myfit<-glmnet(xs, y, family="binomial") 
mydata<-matrix(runif(10), ncol=1) 
colnames(mydata)<-"x" 
class(myfit) 
predict(myfit, newx=mydata, type="response") 
class(myfit)<-rev(class(myfit)) 
class(myfit) 
predict(myfit, newx=mydata, type="response") 
class(myfit)<-rev(class(myfit))#set it back 
class(myfit) 

En función de los datos generados, la diferencia es más o menos evidente (en mi verdadero conjunto de datos noté valores negativos en las llamadas probabilidades, que es la forma en que recogí el problema), pero en realidad debería ver una diferencia.

Gracias por cualquier entrada.

Editar:

acabo de descubrir la horrible verdad: cualquier orden trabajó en glmnet 1.5.2 (que está presente en el servidor donde me encontré con el código real, lo que resulta en el ajuste con el fin de clases invertido), pero el código de 1.6 requiere que el orden sea "lognet", "glmnet". Todavía tengo que verificar lo que sucede en 1.7.

Gracias a @Aaron por recordarme los conceptos básicos de la informática (además de 'si todo lo demás falla, reinícielo': 'verifique sus versiones'). Había asumido erróneamente que un paquete de los dioses del aprendizaje estadístico estaría protegido contra este tipo de error), y a @Gavin para confirmar mi reconstrucción de cómo funciona S3.

+2

Cuando ejecuto el código obtengo el orden '" lognet "" glmnet "' después de la primera llamada de 'clase', que está al revés de lo que dices que obtuviste. Tengo glmnet 1.7; ¿Qué versión tienes? – Aaron

Respuesta

6

Sí, el orden de envío está en el orden en que las clases se enumeran en el atributo de clase. En el caso simple de todos los días, sí, la primera clase indicada es la que primero se elige mediante el envío del método, y solo si no se encuentra un método para esa clase (o se llama al NextMethod) pasará a la segunda clase , o fallando esa búsqueda para un método default.

No, no creo que tenga razón en que el orden de las clases es incorrecto en el código. La documentación aparece mal. La intención es claramente llamar primero al predict.lognet(), usar el caballo de batalla predict.glmnet() para hacer los cálculos básicos para todos los tipos de modelos de red elástica/elástica equipados con glmnet, y finalmente hacer un procesamiento posterior de esas predicciones generales. Que predict.glmnet() es no exportado desde glmnet NAMESPACE mientras que los otros métodos son, tal vez, también está diciendo.

No estoy seguro de por qué cree que la salida de este:

predict(myfit, newx=mydata, type="response") 

está mal? Obtengo una matriz de 10 filas y 21 columnas, con las columnas relacionadas con la predicción del modelo de solo interceptación más las predicciones con 20 valores de lambda a los que se han calculado los coeficientes del modelo a lo largo de la trayectoria de red lazo/elástica. Estas no parecen ser combinaciones lineales y son una de las escalas de respuesta que usted solicitó.

El orden de las clases no está cambiando. Creo que estás malinterpretando cómo se supone que el código funciona. Hay un error en la documentación, ya que el orden se establece incorrectamente allí. Pero el código está funcionando como creo que debería.

+0

Gran respuesta, pero una pequeña queja: no se puede alterar la clase durante el envío del método: https://gist.github.com/1043952 (bueno, puede, simplemente no afecta el despacho) – hadley

+0

Además, parece que la intención es 'prediction.lognet' luego' prediction.glmnet'. Pero cuando lo leí, el OP dice que está ejecutando 'predic.glmnet' primero en su sistema porque el orden de las clases se invierte. – Aaron

+0

@hadley gracias por señalar eso. Debo haber olvidado eso. Corregido ahora. –

Cuestiones relacionadas