R 为什么lm会耗尽内存,而矩阵乘法可以很好地处理系数?

R 为什么lm会耗尽内存,而矩阵乘法可以很好地处理系数?,r,memory,regression,linear-regression,lm,R,Memory,Regression,Linear Regression,Lm,我正在尝试用R做固定效应线性回归 dte yr id v1 v2 . . . . . . . . . . . . . . . 然后,我决定简单地将yr作为一个因子,并使用lm: lm(v1 ~ factor(yr) + v2 - 1, data = df) 然而,这似乎耗尽了内存。我的因子中有20个级别,df是1400万行,存储大约需要2GB,我在一台22 GB的机器上运行这个过程 然后我决定

我正在尝试用R做固定效应线性回归

dte   yr   id   v1   v2
  .    .    .    .    .
  .    .    .    .    .
  .    .    .    .    .
然后,我决定简单地将
yr
作为一个因子,并使用
lm

lm(v1 ~ factor(yr) + v2 - 1, data = df)
然而,这似乎耗尽了内存。我的因子中有20个级别,
df
是1400万行,存储大约需要2GB,我在一台22 GB的机器上运行这个过程

然后我决定用老式的方法来尝试:为我的每一年
t1
t20
创建虚拟变量,方法是:

df$t1 <- 1*(df$yr==1)
df$t2 <- 1*(df$yr==2)
df$t3 <- 1*(df$yr==3)
...
这运行起来没有问题,并且几乎可以立即得到答案


我特别好奇的是,当我可以很好地计算系数时,lm是什么导致它的内存不足?谢谢。

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       
>数据(mtcars)
>lm_车辆摘要(lm_车辆)
电话:
lm(公式=mpg~,数据=mtcars)
残差:
最小1季度中值3季度最大值
-3.4506 -1.6044 -0.1196  1.2193  4.6271                       
系数:
估计标准误差t值Pr(>t)
(截距)12.30337 18.71788 0.657 0.5181
气缸-0.11144 1.04502-0.107 0.9161
显示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
对0.31776 2.10451 0.151 0.8814
am 2.52023 2.05665 1.225 0.2340
档位0.65541 1.49326 0.439 0.6652
碳水化合物-0.19942 0.82875-0.241 0.8122
---                                                           
签名。代码:0'***'0.001'***'0.01'*'0.05'.'0.1''1
剩余标准误差:21个自由度上的2.65
倍数R平方:0.869,调整后的R平方:0.8066
F-统计量:10和21 DF上的13.93,p-值:3.793e-07

除了idris所说的之外,还值得指出的是,lm()并不像您在问题中所说明的那样,使用正规方程求解参数,而是使用QR分解,它的效率较低,但往往会产生更精确的数值解。

< P>你可能想考虑使用这个包。它通过使用较小的数据块来适应lm模型

详细阐述杰克的观点。假设您的回归正试图解决:
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
调用内存不足。

到目前为止,没有一个答案指向正确的方向

被接受的答案是混淆了
lm
summary.lm
lm
根本不计算诊断统计数据
;相反,
summary.lm
。所以他说的是
summary.lm

他的答案是关于QR分解和LU/Choleksy分解的数值稳定性的事实s的回答对此进行了扩展,指出了这两种操作背后的浮点运算量(尽管正如他所说,他没有计算矩阵叉积的成本)。但是,不要混淆触发器计数和内存成本。实际上,这两种方法在LINPACK/LAPACK中具有相同的内存使用率。具体来说,他认为QR方法存储
Q
因子需要更多RAM的观点是错误的。中解释的压缩存储澄清了如何计算和存储QR因子分解。QR v.s.Chol的速度问题在我的回答中有详细说明:,我在上的回答提供了一个使用Choleksy方法的小程序
lm.Chol
,比QR方法快3倍

对于
biglm
的回答/建议是好的,但它没有回答这个问题。既然提到了
biglm
,我想指出这一点
biglm
计算householder反射,从而得到的
R
因子具有正对角线。有关详细信息,请参阅。
biglm
这样做的原因是得到的
R
wil
>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       
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 
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
solve(crossprod(X), crossprod(X,y))
tracemem(X)
crossprod(X)