2010-11-25 15 views
9

Al usar fórmulas que tienen factores, los modelos ajustados nombran los coeficientes XY, donde X es el nombre del factor e Y es un nivel particular de él. Quiero ser capaz de crear una fórmula a partir de los nombres de estos coeficientes.Conversión de nombres de coeficientes a una fórmula en R

El motivo: si ajusto un lazo a una matriz de diseño dispersa (como lo hago a continuación) me gustaría crear un nuevo objeto de fórmula que solo contenga términos para los coeficientes distintos de cero.

require("MatrixModels") 
require("glmnet") 
set.seed(1) 
n <- 200 
Z <- data.frame(letter=factor(sample(letters,n,replace=T),letters), 
       x=sample(1:20,200,replace=T)) 
f <- ~ letter + x:letter + I(x>5):letter 
X <- sparse.model.matrix(f, Z) 
beta <- matrix(rnorm(dim(X)[2],0,5),dim(X)[2],1) 
y <- X %*% beta + rnorm(n) 

myfit <- glmnet(X,as.vector(y),lambda=.05) 
fnew <- rownames(myfit$beta)[which(myfit$beta != 0)] 
[1] "letterb"    "letterc"    "lettere"    
[4] "letterf"    "letterg"    "letterh"    
[7] "letterj"    "letterm"    "lettern"    
[10] "lettero"    "letterp"    "letterr"    
[13] "letters"    "lettert"    "letteru"    
[16] "letterw"    "lettery"    "letterz"    
[19] "lettera:x"   "letterb:x"   "letterc:x"   
[22] "letterd:x"   "lettere:x"   "letterf:x"   
[25] "letterg:x"   "letterh:x"   "letteri:x"   
[28] "letterj:x"   "letterk:x"   "letterl:x"   
[31] "letterm:x"   "lettern:x"   "lettero:x"   
[34] "letterp:x"   "letterq:x"   "letterr:x"   
[37] "letters:x"   "lettert:x"   "letteru:x"   
[40] "letterv:x"   "letterw:x"   "letterx:x"   
[43] "lettery:x"   "letterz:x"   "letterb:I(x > 5)TRUE" 
[46] "letterc:I(x > 5)TRUE" "letterd:I(x > 5)TRUE" "lettere:I(x > 5)TRUE" 
[49] "letteri:I(x > 5)TRUE" "letterj:I(x > 5)TRUE" "letterl:I(x > 5)TRUE" 
[52] "letterm:I(x > 5)TRUE" "letterp:I(x > 5)TRUE" "letterq:I(x > 5)TRUE" 
[55] "letterr:I(x > 5)TRUE" "letteru:I(x > 5)TRUE" "letterv:I(x > 5)TRUE" 
[58] "letterx:I(x > 5)TRUE" "lettery:I(x > 5)TRUE" "letterz:I(x > 5)TRUE" 

De esto me gustaría tener una fórmula

~ I(letter=="d") + I(letter=="e") + ...(etc) 

Revisé fórmula() y all.vars() sin ningún resultado. Además, escribir una función para analizar esto es un poco molesto debido a los diferentes tipos de términos que pueden surgir. Por ejemplo, para x: letra cuando x es un valor numérico y la letra es un factor, o I (x> 5): letra como otro caso molesto.

Entonces, ¿no conozco alguna función para convertir entre fórmula y su representación de caracteres y viceversa?

+0

Esa no es una fórmula que reconozco en R –

+1

Quizás no entiendo bien, pero parece que no grep completamente las fórmulas del modelo de R. No incluye en la fórmula los bits XY, incluye la X y 'model.matrix()' y 'model.frame()' hacen lo suyo para expandir los niveles de la X a las columnas de matrices modelo correspondientes, la XY. –

+0

¿Podría explicar por qué quiere la fórmula? ¿Cuál es el uso final? –

Respuesta

3

Cuando ejecuté el código, obtuve algo un poco diferente, ya que set.seed() no se había especificado. En lugar de utilizar el nombre de la variable "letra", solía "letter_" como un cómodo marcador de división:

> fnew <- rownames(myfit$beta)[which(myfit$beta != 0)] 

> fnew 
[1] "letter_c" "letter_d" "letter_e" "letter_f" "letter_h" "letter_k" "letter_l" 
[8] "letter_o" "letter_q" "letter_r" "letter_s" "letter_t" "letter_u" "letter_v" 
[15] "letter_w" 

luego hizo la división y se empaqueta en una matriz de caracteres:

> fnewmtx <- cbind(lapply(sapply(fnew, strsplit, split="_"), "[[", 2), 
+ lapply(sapply(fnew, strsplit, split="_"), "[[", 1)) 

fnewmtx [, 1] [, 2]
letter_c "c" "letra" letter_d "d" "letra" letter_e "e" "letra" letter_f "f" "letra" cortó el resto

Y envuelve la función de pegar salida (s) en as.formula() que es la mitad de la respuesta a cómo "convertir entre fórmula y su representación de caracteres y volver". La otra mitad es as.character()

form <- as.formula(paste("~", 
      paste( 
       paste(" I(", fnewmtx[,2], "_ ==", "'",fnewmtx[,1],"') ", sep="") , 
      sep="", collapse="+") 
       ) 
      ) # edit: needed to add back the underscore 

Y la salida ahora es un objeto de la clase apropiada:

> class(form) 
[1] "formula" 
> form 
~I(letter_ == "c") + I(letter_ == "d") + I(letter_ == "e") + 
    I(letter_ == "f") + I(letter_ == "h") + I(letter_ == "k") + 
    I(letter_ == "l") + I(letter_ == "o") + I(letter_ == "q") + 
    I(letter_ == "r") + I(letter_ == "s") + I(letter_ == "t") + 
    I(letter_ == "u") + I(letter_ == "v") + I(letter_ == "w") 

Me parece interesante que la conversión as.formula hizo las comillas simples alrededor de la letras en comillas dobles.

Editar: Ahora que el problema tiene una dimensión adicional o dos, mi sugerencia es omitir la recreación de la fórmula. Tenga en cuenta que los rownames de MyFit $ beta son exactamente los mismos que los nombres de las columnas de X, por lo que en lugar de utilizar los rownames no nulos como índices para seleccionar las columnas de la matriz X:

> str(X[ , which(colnames(X) %in% rownames(myfit$beta)[which(myfit$beta != 0)])]) 
Formal class 'dgCMatrix' [package "Matrix"] with 6 slots 
    [email protected] i  : int [1:429] 9 54 91 157 166 37 55 68 117 131 ... 
    [email protected] p  : int [1:61] 0 5 13 20 28 36 42 50 60 68 ... 
    [email protected] Dim  : int [1:2] 200 60 
    [email protected] Dimnames:List of 2 
    .. ..$ : chr [1:200] "1" "2" "3" "4" ... 
    .. ..$ : chr [1:60] "letter_b" "letter_c" "letter_e" "letter_f" ... 
    [email protected] x  : num [1:429] 1 1 1 1 1 1 1 1 1 1 ... 
    [email protected] factors : list() 

> myfit2 <- glmnet(X[ , which(colnames(X) %in% rownames(myfit$beta)[which(myfit$beta != 0)])] ,as.vector(y),lambda=.05) 
> myfit2 

Call: glmnet(x = X[, which(colnames(X) %in% rownames(myfit$beta)[ 
              which(myfit$beta != 0)])], 
       y = as.vector(y), lambda = 0.05) 

    Df %Dev Lambda 
[1,] 60 0.9996 0.05 
+0

¡Gracias DWin! Esto está cerca, pero no es una solución general. He actualizado mi ejemplo. ¿Existe una solución rápida que extienda su solución? –

+0

Además, al crear fnewmtx, ¿no debería strsplit usar split = "_" en lugar de split = ""? –

+0

Muy bien. Editaré Estoy viendo si puedo lidiar con la complejidad añadida de una fórmula de interacción, pero no espero una respuesta rápida sobre esa ..... actualización: intenté editar pero los guiones bajos están en los segmentos de código del original y no se muestran en la página SO. Re-"codificado" y quizás ahora mejor. –

2

Christopher, lo que piden para aparece, después de alguna consideración y examen de sparse.model.matrix etc., estar algo involucrado. No ha explicado por qué no desea formar la matriz de modelo completo disperso para X_test por lo que es difícil aconsejar un camino a seguir que no sean las dos opciones a continuación.

Si usted tiene un gran número de observaciones en X_test y por lo tanto no desea para producir la matriz dispersa completo para su uso en predict() por razones de cálculo, que podría ser más conveniente para dividir X_test en dos o más trozos de muestras y forma las matrices de modelo dispersas para cada una a su vez, desechándolas después de su uso.

De lo contrario, deberá estudiar el código del paquete Matrix en detalle. Comience con sparse.model.matrix y tenga en cuenta que llama a Matrix:::model.spmatrix y busca llamadas al Matrix:::fac2Sparse en esa función. Probablemente necesite codificar el código de estas funciones, pero use un fac2Sparse modificado para lograr lo que desea lograr.

Lo siento, no puedo proporcionar una secuencia de comandos estándar para hacer esto, pero esa es una tarea de codificación sustancial. Si sigue esa ruta, consulte la viñeta Sparse Model Matrices en el paquete Matrix y obtenga las fuentes del paquete (de CRAN) para ver si las funciones que menciono están mejor documentadas en el código fuente (no hay archivos Rd para fac2Sparse por ejemplo). También puede pedir consejo a los autores de Matrix (Martin Maechler y Doug Bates), aunque tenga en cuenta que estos dos capítulos han tenido una carga de enseñanza especialmente pesada este trimestre.

¡Buena suerte!

Cuestiones relacionadas