Ninguna de las respuestas hasta ahora ha apuntado en la dirección correcta.
La respuesta aceptada por @idr está haciendo confusión entre lm
y summary.lm
. lm
no se calcula ninguna estadística de diagnóstico; en cambio, summary.lm
hace. Entonces él está hablando de summary.lm
.
@Jake La respuesta es un hecho sobre la estabilidad numérica de la factorización QR y la factorización LU/Choleksy. La respuesta de Aravindakshan amplía esto, señalando la cantidad de operaciones de coma flotante detrás de ambas operaciones (aunque, como dijo, no contabilizó los costos para calcular el producto cruzado de la matriz). Pero no confundas los conteos de FLOP con los costos de memoria. En realidad, ambos métodos tienen el mismo uso de memoria en LINPACK/LAPACK. Específicamente, su argumento de que el método QR cuesta más RAM para almacenar el factor Q
es falso. El almacenamiento compactado como se explica en lm(): What is qraux returned by QR decomposition in LINPACK/LAPACK aclara cómo se calcula y almacena la factorización QR. Emisión de velocidad de QR v.s. Chol se detalla en mi respuesta: Why the built-in lm function is so slow in R?, y mi respuesta en faster lm
proporciona una pequeña rutina lm.chol
utilizando el método Choleksy, que es 3 veces más rápido que el método QR.
@Greg La respuesta/sugerencia del cliente para biglm
es buena, pero no responde la pregunta. Como se menciona biglm
, señalaría que QR decomposition differs in lm
and biglm
. biglm
calcula la reflexión del propietario para que el factor resultante R
tenga diagonales positivas. Vea Cholesky factor via QR factorization para más detalles. La razón por la que biglm
hace esto, es que el resultado R
será el mismo que el factor Cholesky, consulte QR decomposition and Choleski decomposition in R para obtener información. Además, aparte de biglm
, puede usar mgcv
. Lea mi respuesta: biglm
predict unable to allocate a vector of size xx.x MB para más.
Después de un resumen, es el momento de publicar mi respuesta.
Con el fin de ajustar un modelo lineal, lm
voluntad
- genera un marco de modelo;
- genera una matriz modelo;
- llamada
lm.fit
para la factorización QR;
- devuelve el resultado de la factorización QR, así como el marco del modelo en
lmObject
.
Dijo que su marco de datos de entrada con 5 columnas cuesta 2 GB para almacenar. Con 20 niveles de factor, la matriz de modelo resultante tiene alrededor de 25 columnas que toman 10 GB de almacenamiento. Ahora veamos cómo crece el uso de la memoria cuando llamamos al lm
.
- [entorno global] inicialmente usted tiene 2 GB de almacenamiento de la trama de datos;
- [
lm
envrionment] continuación, se copia a un modelo de marco, con un costo de 2 GB;
- [
lm
entorno] a continuación, se genera una matriz de modelo, con un costo de 10 GB;
- [
lm.fit
entorno] una copia de la matriz del modelo se sobrescribe luego por factorización QR, con un costo de 10 GB;
- [
lm
entorno] se devuelve el resultado de lm.fit
, con un costo de 10 GB;
- [entorno global] el resultado de
lm.fit
es devuelto por lm
, con un costo de otros 10 GB;
- [entorno global] el modelo de marco es devuelto por
lm
, con un costo de 2 GB.
Por lo tanto, se requiere un total de 46 GB de RAM, mucho mayor que la RAM de 22 GB disponible.
En realidad, si lm.fit
puede ser "incluido" en lm
, podríamos ahorrar 20 GB de costos. Pero no hay forma de alinear una función R en otra función R.
Tal vez podemos tomar un pequeño ejemplo para ver lo que sucede a su alrededor lm.fit
:
X <- matrix(rnorm(30), 10, 3) # a `10 * 3` model matrix
y <- rnorm(10) ## response vector
tracemem(X)
# [1] "<0xa5e5ed0>"
qrfit <- lm.fit(X, y)
# tracemem[0xa5e5ed0 -> 0xa1fba88]: lm.fit
Así que de hecho, X
se copia cuando pasó a lm.fit
. Vamos a echar un vistazo a lo que tiene qrfit
str(qrfit)
#List of 8
# $ coefficients : Named num [1:3] 0.164 0.716 -0.912
# ..- attr(*, "names")= chr [1:3] "x1" "x2" "x3"
# $ residuals : num [1:10] 0.4 -0.251 0.8 -0.966 -0.186 ...
# $ effects : Named num [1:10] -1.172 0.169 1.421 -1.307 -0.432 ...
# ..- attr(*, "names")= chr [1:10] "x1" "x2" "x3" "" ...
# $ rank : int 3
# $ fitted.values: num [1:10] -0.466 -0.449 -0.262 -1.236 0.578 ...
# $ assign : NULL
# $ qr :List of 5
# ..$ qr : num [1:10, 1:3] -1.838 -0.23 0.204 -0.199 0.647 ...
# ..$ qraux: num [1:3] 1.13 1.12 1.4
# ..$ pivot: int [1:3] 1 2 3
# ..$ tol : num 1e-07
# ..$ rank : int 3
# ..- attr(*, "class")= chr "qr"
# $ df.residual : int 7
Tenga en cuenta que la matriz compacta QR qrfit$qr$qr
es tan grande como la matriz del modelo X
. Se crea dentro de lm.fit
, pero al salir de lm.fit
, se copia. Entonces, en total, tendremos 3 "copias" de X
:
- la original en el entorno global;
- el copiado en
lm.fit
, sobrescrito por factorización QR;
- la devuelta por
lm.fit
.
En su caso, X
es de 10 GB, por lo que los costes de memoria asociados con lm.fit
sola ya es de 30 GB. Menos aún otros costos asociados con lm
.
Por otra parte, vamos a echar un vistazo a
solve(crossprod(X), crossprod(X,y))
X
tiene 10 GB, pero crossprod(X)
sólo es una matriz 25 * 25
, y crossprod(X,y)
es sólo un vector talla 25. Son muy pequeños en comparación con X
, por lo que el uso de la memoria no aumenta en absoluto.
Tal vez le preocupa que se realice una copia local de X
cuando se llama crossprod
? ¡De ningún modo! A diferencia de lm.fit
que realiza tanto lectura como escritura en X
, crossprod
solo lee X
, por lo que no se realiza ninguna copia. Podemos verificar esto con nuestra matriz de juguete X
por:
tracemem(X)
crossprod(X)
Usted verá ningún mensaje de copia!
Si quieres un breve resumen de todo lo anterior, aquí está:
- costes de memoria para
lm.fit(X, y)
(o incluso .lm.fit(X, y)
) es tres veces más grande que el de solve(crossprod(X), crossprod(X,y))
;
- Según cuánto más grande es el modelo de matriz que el modelo de marco, los costos de memoria para
lm
son 3 ~ 6 veces más grandes que para solve(crossprod(X), crossprod(X,y))
. El límite inferior 3 nunca se alcanza, mientras que el límite superior 6 se alcanza cuando la matriz del modelo es igual que el marco del modelo. Este es el caso cuando no hay factores o variables de términos "factor de semejanza", como bs()
y poly()
, etc.
¿por qué no intenta 'lm.fit' en lugar de' lm' para reducir la ¿problema? '' lm.fit' 'solo hace más o menos ajuste de modelo lineal' 'crudo' 'a través de la descomposición QR, ninguna de las cosas extrañas sobre la creación de matrices modelo, etc. Si también tienes problemas de memoria con 'lm.fit', entonces la respuesta de @Jake parece ser el problema (QR vs ecuaciones normales). –