迄今沒有任何答案指出了正確的方向。
@idr接受的答案正在混淆lm
和summary.lm
。 lm
根本不計算診斷統計量;相反,summary.lm
呢。所以他在談論summary.lm
。
@Jake的答案是關於QR因子分解和LU/Choleksy因子分解的數值穩定性的一個事實。 Aravindakshan的答案通過指出兩個操作背後浮點操作的數量來擴展這個問題(儘管如他所說,他沒有計算計算矩陣交叉乘積的成本)。但是,不要混淆FLOP計數和內存成本。實際上這兩種方法在LINPACK/LAPACK中具有相同的內存使用情況。具體來說,他認爲QR方法花費更多內存來存儲Q
因子是一個虛假的因素。如lm(): What is qraux returned by QR decomposition in LINPACK/LAPACK中所解釋的壓縮存儲器闡明瞭如何計算和存儲QR分解。 QR v.s.的速度問題Chol在我的回答中有詳細說明:Why the built-in lm function is so slow in R?,而我在faster lm
上的回答提供了一個使用Choleksy方法的小例程lm.chol
,它比QR方法快3倍。
@Greg對biglm
的回答/建議很好,但它沒有回答這個問題。由於提到了biglm
,我會指出QR decomposition differs in lm
and biglm
。 biglm
計算householder反射,以便生成的R
因子具有正對角線。詳情請參閱Cholesky factor via QR factorization。 biglm
這樣做的原因是由此產生的R
將與Cholesky因子相同,請參閱QR decomposition and Choleski decomposition in R以獲取信息。此外,除了biglm
,您可以使用mgcv
。閱讀我的答案:biglm
predict unable to allocate a vector of size xx.x MB瞭解更多信息。
經過總結,是時候發佈我的回答。
爲了適合的線性模型,lm
將
- 生成模型框架;
- 生成模型矩陣;
- 致電
lm.fit
QR分解;
- 返回QR分解的結果以及
lmObject
中的模型框架。
你說你的5列輸入數據幀需要2 GB的存儲空間。在20個因子水平下,最終的模型矩陣大約有25列,存儲容量爲10 GB。現在讓我們看看當我們調用lm
時內存使用情況如何增長。
- [全球環境]最初,您有2 GB的數據存儲空間;
- [
lm
envrionment]然後它被複制到模型框架,花費2 GB;
- [
lm
環境]然後生成模型矩陣,成本爲10GB;
- [
lm.fit
環境]複製模型矩陣,然後用QR分解重寫,成本10 GB;
- [
lm
環境]返回結果lm.fit
,成本10 GB;
- [全球環境]
lm.fit
的結果進一步由lm
返回,花費另外10 GB;
- [全球環境]模型框架由
lm
返回,成本爲2 GB。
因此,總共需要46 GB RAM,遠遠大於可用的22 GB RAM。
其實如果lm.fit
可以「內聯」爲lm
,我們可以節省20 GB的成本。但是無法在另一個R函數中內聯R函數。
也許我們可以舉一個小例子,看看周圍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
所以事實上,當傳遞到lm.fit
X
被複制。讓我們來看看什麼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
注意,緊湊QR矩陣qrfit$qr$qr
是模型矩陣X
一樣大。它在lm.fit
內部創建,但在lm.fit
的退出時被複制。所以總共我們將有3個「副本」X
:
- 原來在全球環境中的一個;
- 一個複製到
lm.fit
,被QR分解覆蓋;
- 由
lm.fit
返回的那一個。
在你的情況下,X
是10 GB,所以與lm.fit
單獨相關的內存成本已經是30 GB。更Let論與lm
相關的其他費用。
在另一方面,讓我們來看看
solve(crossprod(X), crossprod(X,y))
X
需要10 GB,但crossprod(X)
只是25 * 25
矩陣,crossprod(X,y)
只是一個長度爲25載體。與X
相比,它們非常小,因此內存使用量根本不增加。
也許你擔心當crossprod
被調用時會產生本地副本X
?一點也不!與執行X
的讀取和寫入的lm.fit
不同,crossprod
僅讀取X
,因此不進行復制。我們可以通過我們的玩具矩陣X
驗證這一點:
tracemem(X)
crossprod(X)
你會看到沒有複製的消息!
如果你想上面所有的簡短總結,那就是:爲lm.fit(X, y)
(甚至.lm.fit(X, y)
)
- 內存成本是對於
solve(crossprod(X), crossprod(X,y))
三倍大;
- 根據模型矩陣比模型框架大多少,
lm
的存儲器成本是solve(crossprod(X), crossprod(X,y))
的3〜6倍。下限3永遠不會達到,而當模型矩陣與模型框架相同時達到上限6。出現這種情況時,有沒有因子變量或「因子都」而言,像bs()
和poly()
等
你爲什麼不試着去'lm.fit',而不是'lm'來縮小問題? 'lm.fit'只是通過QR分解進行或多或少的「原始」線性模型擬合 - 沒有關於模型矩陣創建的無關內容等。如果您還遇到'lm.fit'的內存問題,那麼@傑克的答案似乎是問題(QR與正常方程)。 – 2012-04-26 15:54:09