Nessuna delle risposte finora ha indicato la giusta direzione.
La risposta accettata da @idr crea confusione tra lm
e summary.lm
. lm
non calcola statistiche diagnostiche su tutti; invece, lo fa summary.lm
. Quindi sta parlando di summary.lm
.
@Jake La risposta è un dato di fatto sulla stabilità numerica della fattorizzazione QR e della fattorizzazione LU/Choleksy. La risposta di Aravindakshan la espande, sottolineando la quantità di operazioni in virgola mobile dietro entrambe le operazioni (sebbene, come ha detto, non ha considerato i costi per il calcolo del prodotto a matrice incrociata). Ma non confondere i conteggi FLOP con i costi di memoria. In realtà entrambi i metodi hanno lo stesso utilizzo della memoria in LINPACK/LAPACK. In particolare, il suo argomento secondo cui il metodo QR costa più RAM per memorizzare il fattore Q
è falso. La memoria compattata come spiegato in lm(): What is qraux returned by QR decomposition in LINPACK/LAPACK chiarisce in che modo la fattorizzazione QR viene calcolata e archiviata. Problema di velocità di QR v.s. Chol è dettagliato nella mia risposta: Why the built-in lm function is so slow in R?, e la mia risposta su faster lm
fornisce una piccola routine lm.chol
utilizzando il metodo Choleksy, che è 3 volte più veloce del metodo QR.
@Greg La risposta/suggerimento per biglm
è buona, ma non risponde alla domanda. Dal momento che si parla di biglm
, vorrei sottolineare che QR decomposition differs in lm
and biglm
. biglm
calcola la riflessione della famiglia in modo che il risultante fattore R
abbia diagonali positive. Vedi Cholesky factor via QR factorization per i dettagli. Il motivo per cui biglm
esegue questa operazione, è che il risultante R
sarà uguale al fattore Cholesky, vedere QR decomposition and Choleski decomposition in R per informazioni. Inoltre, a parte biglm
, è possibile utilizzare mgcv
. Leggi la mia risposta: biglm
predict unable to allocate a vector of size xx.x MB per ulteriori informazioni.
Dopo una sintesi, è il momento di inviare la mia risposta.
Per montare un modello lineare, lm
sarà
- genera un modello di telaio;
- genera una matrice modello;
- chiamata
lm.fit
per fattorizzazione QR;
- restituisce il risultato della fattorizzazione QR nonché il frame del modello in
lmObject
.
Hai detto che il frame dati di input con 5 colonne costa 2 GB per l'archiviazione. Con 20 livelli di fattore la matrice del modello risultante ha circa 25 colonne che occupano 10 GB di spazio. Ora vediamo come cresce l'utilizzo della memoria quando chiamiamo lm
.
- [ambiente globale] inizialmente avete 2 GB di storage per il frame di dati;
- [
lm
envrionment] quindi viene copiato in un frame del modello, che costa 2 GB;
- [
lm
ambiente] quindi viene generata una matrice modello, che costa 10 GB;
- [
lm.fit
ambiente] una copia della matrice del modello viene quindi sovrascritta dalla fattorizzazione QR, che costa 10 GB;
- [
lm
ambiente] viene restituito il risultato di lm.fit
, che costa 10 GB;
- [ambiente globale] il risultato di
lm.fit
è ulteriormente restituito da lm
, costano altri 10 GB;
- [ambiente globale] il frame del modello viene restituito da
lm
, che costa 2 GB.
Quindi, è richiesto un totale di 46 GB di RAM, molto più grande della RAM disponibile di 22 GB.
In realtà se può essere "in linea" in lm
, potremmo risparmiare 20 GB di costi. Ma non c'è modo di allineare una funzione R in un'altra funzione R.
Forse possiamo fare un piccolo esempio per vedere cosa succede intorno 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
così effettivamente, X
viene copiato quando passò in lm.fit
. Diamo un'occhiata a ciò che ha 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
nota che la compatta a matrice QR qrfit$qr$qr
è grande come matrice modello X
. Viene creato all'interno di lm.fit
, ma all'uscita di lm.fit
, viene copiato. Quindi, in totale, avremo 3 "copie" di X
:
- quello originale in ambiente globale;
- quello copiato in
lm.fit
, sovrascritto dalla fattorizzazione QR;
- quello restituito da
lm.fit
.
Nel suo caso, X
è 10 GB, quindi i costi di memoria associati lm.fit
sola è già 30 GB. Per non parlare degli altri costi associati a lm
.
D'altra parte, diamo un'occhiata a
solve(crossprod(X), crossprod(X,y))
X
prende 10 GB, ma crossprod(X)
è solo una matrice 25 * 25
e crossprod(X,y)
è solo un vettore lunghezza-25. Sono così piccoli rispetto a X
, quindi l'utilizzo della memoria non aumenta affatto.
Forse si è preoccupati che venga eseguita una copia locale di X
quando viene chiamato crossprod
? Affatto! A differenza di lm.fit
che esegue sia la lettura che la scrittura su X
, crossprod
legge solo X
, quindi non viene eseguita alcuna copia. Siamo in grado di verificare questo con la nostra matrice giocattolo X
da:
tracemem(X)
crossprod(X)
Si vedrà alcun messaggio copia!
Se si desidera un breve riassunto per tutti sopra, qui è:
- costi di memoria per
lm.fit(X, y)
(o anche .lm.fit(X, y)
) è tre volte più grande di quella per solve(crossprod(X), crossprod(X,y))
;
- A seconda di quanto più grande è la matrice del modello rispetto al frame del modello, i costi di memoria per
lm
sono 3 ~ 6 volte più grandi di quello per solve(crossprod(X), crossprod(X,y))
. Il limite inferiore 3 non viene mai raggiunto, mentre il limite superiore 6 viene raggiunto quando la matrice del modello è uguale a quella del modello. Questo è il caso in cui non ci sono variabili fattore o termini "fattore-alike", come bs()
e poly()
, ecc
perché non si tenta 'lm.fit' invece di' lm' per restringere il campo problema? 'lm.fit' fa solo il più o meno" lineare "fitting del modello lineare tramite la decomposizione QR - nessuna delle cose estranee sulla creazione della matrice del modello, ecc. Se si riscontrano anche problemi di memoria con' lm.fit', allora @ la risposta di Jake sembrerebbe essere il problema (QR rispetto alle equazioni normali). –