我正在尝试使用R进行固定效果线性回归。我的数据看起来像
dte yr id v1 v2
. . . . .
. . . . .
. . . . .
然后我决定通过将yr
作为一个因素并使用lm
来执行此操作:
lm(v1 ~ factor(yr) + v2 - 1, data = df)
然而,这似乎耗尽了内存。我的因子中有20个级别,而df
是1400万行,大约需要2GB才能存储,我在一台专用于此过程的22 GB机器上运行它。
然后我决定以老式的方式尝试:通过执行以下操作,为{JER} t1
创建虚拟变量:{/ p>
t20
并简单地计算:
df$t1 <- 1*(df$yr==1)
df$t2 <- 1*(df$yr==2)
df$t3 <- 1*(df$yr==3)
...
这没有问题,几乎立即产生了答案。
我特别好奇当我能够很好地计算系数时,lm会使内存耗尽吗?感谢。
答案 0 :(得分:10)
除了idris所说的,还值得指出的是lm()并没有像你在问题中所说明的那样使用正规方程求解参数,而是使用QR分解,效率较低但往往会产生更准确的解决方案。
答案 1 :(得分:9)
您可能需要考虑使用biglm包。它通过使用较小的数据块来适应lm模型。
答案 2 :(得分:8)
到目前为止,答案中没有一个指向正确的方向。
@idr接受的答案正在lm
和summary.lm
之间产生混淆。 lm
根本不计算诊断统计信息;相反,summary.lm
会这样做。所以他在谈论summary.lm
。
@Jake的答案是关于QR分解和LU / Choleksy分解的数值稳定性的事实。 Aravindakshan的答案扩展了这一点,指出了两个操作背后的浮点运算量(尽管如他所说,他没有计算计算矩阵交叉产品的成本)。但是,不要将FLOP计数与内存成本混淆。实际上,这两种方法在LINPACK / LAPACK中具有相同的内存使用量。具体来说,他认为QR方法需要花费更多RAM来存储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
计算住户反映,以便生成的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分解; lmObject
中的模型框架。您说您的5列输入数据帧需要2 GB才能存储。使用20个因子级别,得到的模型矩阵有大约25列,占用10 GB存储空间。现在让我们看看当我们调用lm
时内存使用情况如何增长。
lm
envrionment] 然后将其复制到模型框架,耗资2 GB; lm
environment] 然后生成一个模型矩阵,耗资10 GB; lm.fit
environment] 制作模型矩阵的副本,然后通过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
返回的那个。在您的情况下,X
为10 GB,因此仅与lm.fit
相关联的内存成本已为30 GB。更不用说与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)
)的内存成本是solve(crossprod(X), crossprod(X,y))
的内存成本的三倍; lm
的内存成本是solve(crossprod(X), crossprod(X,y))
的3到6倍。从未达到下限3,而当模型矩阵与模型框架相同时,达到上限6。如果没有因子变量或“因子相似”术语,例如bs()
和poly()
等,就会出现这种情况。答案 3 :(得分:7)
lm
不仅可以找到输入要素的系数。例如,它提供诊断统计信息,告诉您有关自变量系数的更多信息,包括每个自变量的标准误差和t值。
我认为,在运行回归分析以了解回归的有效性时,了解这些诊断统计信息非常重要。
这些额外的计算导致lm
比简单地解决回归的矩阵方程慢。
例如,使用mtcars
数据集:
>data(mtcars)
>lm_cars <- lm(mpg~., data=mtcars)
>summary(lm_cars)
Call:
lm(formula = mpg ~ ., data = mtcars)
Residuals:
Min 1Q Median 3Q Max
-3.4506 -1.6044 -0.1196 1.2193 4.6271
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 12.30337 18.71788 0.657 0.5181
cyl -0.11144 1.04502 -0.107 0.9161
disp 0.01334 0.01786 0.747 0.4635
hp -0.02148 0.02177 -0.987 0.3350
drat 0.78711 1.63537 0.481 0.6353
wt -3.71530 1.89441 -1.961 0.0633 .
qsec 0.82104 0.73084 1.123 0.2739
vs 0.31776 2.10451 0.151 0.8814
am 2.52023 2.05665 1.225 0.2340
gear 0.65541 1.49326 0.439 0.6652
carb -0.19942 0.82875 -0.241 0.8122
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.65 on 21 degrees of freedom
Multiple R-squared: 0.869, Adjusted R-squared: 0.8066
F-statistic: 13.93 on 10 and 21 DF, p-value: 3.793e-07
答案 4 :(得分:5)
详细阐述杰克的观点。假设您的回归试图解决:y = Ax
(A是设计矩阵)。 m个观测值和n个独立变量A是mxn矩阵。那么QR的成本是〜m*n^2
。在你的情况下,它看起来像m = 14x10 ^ 6和n = 20。因此m*n^2 = 14*10^6*400
是一项重大成本。
然而,使用正规方程式,您试图反转A'A
('表示转置),它是方形且大小为nxn
。解决方案通常使用LU进行,费用为n^3 = 8000
。这远小于QR的计算成本。 当然这不包括矩阵乘法的成本。
此外,如果QR例程尝试存储大小为mxm=14^2*10^12
(!)的Q矩阵,那么您的记忆力将不足。可以将QR写入没有这个问题。了解实际使用的QR版本会很有趣。为什么lm
调用会耗尽内存。