Montaje de un modelo lineal con múltiples LHS

Soy nuevo en R y quiero mejorar el siguiente script con una función *apply (He leído sobre apply , pero no pude lograr usarlo). Quiero usar la función lm en múltiples variables independientes (que son columnas en un dataframe). solía

 for (i in (1:3) { assign(paste0('lm.',names(data[i])), lm(formula=formula(i),data=data)) } 

Formula(i) se define como

 formula=function(x) { as.formula ( paste(names(data[x]),'~', paste0(names(data[-1:-3]), collapse = '+')), env=parent.frame() ) } 

Gracias.

Si no te malinterpreté, estás trabajando con un conjunto de datos como este:

 set.seed(0) dat <- data.frame(y1 = rnorm(30), y2 = rnorm(30), y3 = rnorm(30), x1 = rnorm(30), x2 = rnorm(30), x3 = rnorm(30)) 

x1 , x2 y x3 son covariables, y y1 , y2 , y3 son tres respuestas independientes. Está tratando de encajar tres modelos lineales:

 y1 ~ x1 + x2 + x3 y2 ~ x1 + x2 + x3 y3 ~ x1 + x2 + x3 

Actualmente está utilizando un ciclo a través de y1 , y2 , y3 , que se ajusta a un modelo por vez. lapply acelerar el proceso reemplazando el ciclo for con lapply .

Estás en el camino equivocado. lm() es una operación costosa. Siempre que su conjunto de datos no sea pequeño, el costo del bucle for es insignificante. Reemplazar for loop con lapply no da ganancias de rendimiento.

Como tiene el mismo RHS (lado derecho de ~ ) para los tres modelos, la matriz del modelo es la misma para tres modelos. Por lo tanto, la factorización QR para todos los modelos solo necesita hacerse una vez. lm permite y puedes usar:

 fit <- lm(cbind(y1, y2, y3) ~ x1 + x2 + x3, data = dat) #Coefficients: # y1 y2 y3 #(Intercept) -0.081155 0.042049 0.007261 #x1 -0.037556 0.181407 -0.070109 #x2 -0.334067 0.223742 0.015100 #x3 0.057861 -0.075975 -0.099762 

Si marca str(fit) , verá que esta no es una lista de tres modelos lineales; en cambio, es un modelo lineal único con un único objeto $qr , pero con múltiples LHS. Entonces $coefficients , $residuals y $fitted.values son matrices. El modelo lineal resultante tiene una clase "mlm" adicional además de la clase usual "lm". Creé una etiqueta especial de mlm recostackndo algunas preguntas sobre el tema, resumidas por su etiqueta wiki .

Si tiene muchas más covariables, puede evitar escribir o pegar fórmula usando . :

 fit <- lm(cbind(y1, y2, y3) ~ ., data = dat) #Coefficients: # y1 y2 y3 #(Intercept) -0.081155 0.042049 0.007261 #x1 -0.037556 0.181407 -0.070109 #x2 -0.334067 0.223742 0.015100 #x3 0.057861 -0.075975 -0.099762 

Precaución: no escribir

 y1 + y2 + y3 ~ x1 + x2 + x3 

Esto tratará a y = y1 + y2 + y3 como una sola respuesta. Use cbind() .


Seguir:

Estoy interesado en una generalización. Tengo un dataframe df , donde las primeras n columnas son variables dependientes (y1,y2,y3,....) y las siguientes m columnas son variables independientes (x1+x2+x3+....) . Para n = 3 y m = 3 , se fit <- lm(cbind(y1, y2, y3) ~ ., data = dat)) . Pero cómo hacer esto automáticamente, usando la estructura del df . Me refiero a algo así como (for i in (1:n)) fit <- lm(cbind(df[something] ~ df[something], data = dat)) . Ese "algo" lo he creado con paste y paste0 . Gracias.

Así que está progtwigndo su fórmula, o quiere generar / construir dinámicamente fórmulas de modelo en el ciclo. Hay muchas formas de hacerlo, y muchas preguntas sobre el Desbordamiento de stack se tratan de esto. Hay comúnmente dos enfoques:

  1. usar reformulate ;
  2. use paste / paste0 y formula / as.formula .

Prefiero reformulate por su pulcritud, sin embargo, no admite múltiples LHS en la fórmula. También necesita algún tratamiento especial si desea transformar el LHS . Entonces en lo siguiente usaría la solución de paste .

Para su dataframe df , puede hacer

 paste0("cbind(", paste(names(df)[1:n], collapse = ", "), ")", " ~ .") 

Una forma más agradable es usar sprintf y toString para construir el LHS:

 sprintf("cbind(%s) ~ .", toString(names(df)[1:n])) 

Aquí hay un ejemplo usando el conjunto de datos del iris :

 string_formula <- sprintf("cbind(%s) ~ .", toString(names(iris)[1:2])) # "cbind(Sepal.Length, Sepal.Width) ~ ." 

Puede pasar esta fórmula de cadena a lm , ya que lm la forzará automáticamente en la clase de fórmula. O puede hacer la coerción usted mismo usando la formula (o as.formula ):

 formula(string_formula) # cbind(Sepal.Length, Sepal.Width) ~ . 

Observación:

Esta fórmula múltiple de LHS también se admite en otras partes del núcleo R:

  • el método de fórmula para aggregate función ;
  • ANOVA análisis con aov .
    Intereting Posts