これまでのところ、正しい方向を示した答えはありません。
@idrによって受け入れられた回答は、 と の間lm
で混乱を招いていsummary.lm
ます。lm
診断統計をまったく計算しません。代わりに、summary.lm
そうします。だから彼は話しているsummary.lm
.
@Jakeの答えは、QR 分解と LU/Choleksy 分解の数値安定性に関する事実です。Arvindakshanの回答は、両方の操作の背後にある浮動小数点操作の量を指摘することで、これを拡張します (ただし、彼が言ったように、行列の外積を計算するためのコストは考慮していません)。ただし、FLOP カウントとメモリ コストを混同しないでください。実際、どちらの方法も LINPACK / LAPACK でのメモリ使用量は同じです。具体的には、QR メソッドQ
は因子を格納するためにより多くの RAM を必要とするという彼の主張は、偽物です。lm()で説明されている圧縮されたストレージ: LINPACK / LAPACK の QR 分解によって返される qraux とは、 QR 因数分解がどのように計算され、格納されるかを明確にします。QR vs Chol の速度の問題については、私の回答で詳しく説明しています。Rで組み込みのlm関数が非常に遅いのはなぜですか? 、高速化lm
に関する私の回答では、Choleksy 法を使用した小さなルーチンが提供されていますlm.chol
。これは、QR 法よりも 3 倍高速です。
@Gregの回答/提案biglm
は良いですが、質問には回答しません。が言及されているので、 QR 分解が と で異なることbiglm
を指摘しておきます。結果の因子が正の対角線を持つように世帯主反射を計算します。詳細については、QR 分解によるコレスキー ファクターを参照してください。これを行う理由は、結果がコレスキー因子と同じになるためです。詳細については、QR 分解と Rのコレスキー分解を参照してください。また、 以外にも を使用できます。私の答えを読んでください:サイズ xx.x MB のベクトルをさらに割り当てることができないと予測してください。lm
biglm
biglm
R
biglm
R
biglm
mgcv
biglm
要約の後、私の答えを投稿する時が来ました。
lm
線形モデルを適合させるために、
- モデル フレームを生成します。
- モデル行列を生成します。
lm.fit
QR 因数分解の呼び出し。
- は、QR 分解の結果と のモデル フレームを返します
lmObject
。
5 列の入力データ フレームの保存には 2 GB のコストがかかるとおっしゃいました。因子レベルが 20 の場合、結果のモデル マトリックスには約 25 列があり、10 GB のストレージを使用します。を呼び出したときにメモリ使用量がどのように増加するかを見てみましょうlm
。
- [グローバル環境]最初は、データ フレーム用に 2 GB のストレージがあります。
- [
lm
環境]次に、モデル フレームにコピーされ、2 GB のコストがかかります。
- [
lm
環境]次に、モデル マトリックスが生成され、10 GB のコストがかかります。
- [
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
実際、X
に渡されるとコピーされlm.fit
ます。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
。
あなたの場合は 10 GB であるため、単独でX
関連するメモリ コストはすでに 30 GB です。lm.fit
に関連するその他のコストは言うまでもありませんlm
。
一方、見てみましょう
solve(crossprod(X), crossprod(X,y))
X
10 GB かかりますが、これcrossprod(X)
は単なる25 * 25
行列でありcrossprod(X,y)
、長さ 25 のベクトルです。に比べて非常に小さいためX
、メモリ使用量はまったく増加しません。
が呼び出さX
れたときにのローカル コピーが作成されるのではないかと心配しているかもしれません。crossprod
全くない!lm.fit
に対して読み取りと書き込みの両方を実行するとは異なりX
、crossprod
読み取りのみを実行X
するため、コピーは作成されません。おもちゃの行列でこれを確認するには、次のようにしますX
。
tracemem(X)
crossprod(X)
コピーのメッセージは表示されません。
上記のすべての短い要約が必要な場合は、次のとおりです。
lm.fit(X, y)
(または)のメモリ コスト.lm.fit(X, y)
は、 の 3 倍ですsolve(crossprod(X), crossprod(X,y))
。
- モデル マトリックスがモデル フレームよりどれだけ大きいかに応じて、 のメモリ コスト
lm
は の 3 ~ 6 倍になりsolve(crossprod(X), crossprod(X,y))
ます。下限 3 には到達しませんが、モデル マトリックスがモデル フレームと同じ場合、上限 6 に到達します。bs()
これは、やなどの因子変数や「因子に類似した」項がない場合に当てはまりますpoly()
。