在R save()函数之后,逻辑回归对象占用了大量磁盘空间

时间:2014-08-01 20:34:48

标签: r memory-management save persistence logistic-regression

我拒绝提供示例代码,因为到目前为止,我无法在较小的数据集上复制此示例。我正在使用不同的协变量选择训练几个逻辑回归(在此示例中为50)并将输出保存为列表。我的训练数据有+ 400K行。

认识到存在大量不必要的背景数据存储在glm对象中,我的训练脚本涉及以下几行代码,这些代码旨在尽可能多地删除额外数据并减少内存占用量。输出对象:

fit[c('residuals', 'fitted.values', 'effects', 'weights', 'prior.weights', 'y', 'linear.predictors', 'data')] <- NULL
fit$qr$qr <- NULL
 gc() 

起初,这似乎工作正常。 R / RStudio控制台告诉我执行我的代码后glms列表是9.6Mb:

enter image description here

但是,当我使用save(logitFire, file = 'logitFire.RData')保存此对象时,我发现它的内存占用空间非常庞大(磁盘上为1.32GB):

enter image description here

同样,我100%认识到不提供玩具示例是不好的形式。我尝试使用虹膜数据集,但无法重现问题。它似乎是大型数据集的一个特征,但我不确定。那里的任何专家都知道发生了什么?我的下一步,如果我不能使用基础包中的函数来解决这个问题,那就是为#14; leanLogit&#34;编写自己的包装器。和&#34; leanPredict&#34;只删除模型协变量并抛弃所有其余辅助数据的函数。

编辑:为了澄清,我在此问题中包含的示例脚本嵌入在模型训练例程中,该例程最终生成glms logitFire列表。这不是完整的代码,而是嵌入在更大的脚本中。我把它包括在内,以便读者可以看到我剥离的数据对象。

编辑#2:这里有一些额外的请求信息。为了尽可能清楚,logitFire是我使用glm在R中生成的50个逻辑回归模型的列表。我在此列表的一个元素上显示了str命令的输出,即一个逻辑回归模型:

> object.size(logitFire)
10113640 bytes
> str(logitFire[[1]])
List of 21
 $ coefficients : Named num [1:54] 18.361 -0.592 -1.043 -0.744 0.101 ...
  ..- attr(*, "names")= chr [1:54] "(Intercept)" "var32" "var33" "var34" ...
 $ R            : num [1:54, 1:54] -11.3 0 0 0 0 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:54] "(Intercept)" "var32" "var33" "var34" ...
  .. ..$ : chr [1:54] "(Intercept)" "var32" "var33" "var34" ...
 $ rank         : int 53
 $ qr           :List of 4
  ..$ rank : int 53
  ..$ qraux: num [1:54] 1 1 1 1 1 ...
  ..$ pivot: int [1:54] 1 2 3 4 5 6 7 8 9 10 ...
  ..$ tol  : num 1e-11
  ..- attr(*, "class")= chr "qr"
 $ family       :List of 12
  ..$ family    : chr "binomial"
  ..$ link      : chr "logit"
  ..$ linkfun   :function (mu)  
  ..$ linkinv   :function (eta)  
  ..$ variance  :function (mu)  
  ..$ dev.resids:function (y, mu, wt)  
  ..$ aic       :function (y, n, mu, wt, dev)  
  ..$ mu.eta    :function (eta)  
  ..$ initialize:  expression({     if (NCOL(y) == 1) {         if (is.factor(y))                 y <- y != levels(y)[1L]         n <- rep.int(1, nobs)         y[weights == 0] <- 0         if (any(y < 0 | y > 1))              stop("y values must be 0 <= y <= 1")         mustart <- (weights * y + 0.5)/(weights + 1)         m <- weights * y         if (any(abs(m - round(m)) > 0.001))              warning("non-integer #successes in a binomial glm!")     }     else if (NCOL(y) == 2) {         if (any(abs(y - round(y)) > 0.001))              warning("non-integer counts in a binomial glm!")         n <- y[, 1] + y[, 2]         y <- ifelse(n == 0, 0, y[, 1]/n)         weights <- weights * n         mustart <- (n * y + 0.5)/(n + 1)     }     else stop("for the 'binomial' family, y must be a vector of 0 and 1's\nor a 2 column matrix where col 1 is no. successes and col 2 is no. failures") })
  ..$ validmu   :function (mu)  
  ..$ valideta  :function (eta)  
  ..$ simulate  :function (object, nsim)  
  ..- attr(*, "class")= chr "family"
 $ deviance     : num 1648
 $ aic          : num 1754
 $ null.deviance: num 1783
 $ iter         : int 19
 $ df.residual  : int 49947
 $ df.null      : int 49999
 $ converged    : logi TRUE
 $ boundary     : logi FALSE
 $ call         : language glm(formula = fire ~ var3 + var1 + var12isNA + var4 + var11 + var13 + var6 + dummy + var9 + var16isNA + var10 + var17 + var8 + var7 + var15isNA +      var14isNA, family = binomial(), data = inData, model = FALSE)
 $ formula      :Class 'formula' length 3 fire ~ var3 + var1 + var12isNA + var4 + var11 + var13 + var6 + dummy + var9 + var16isNA + var10 + var17 + var8 + var7 + var15isNA + var14isNA
  .. ..- attr(*, ".Environment")=<environment: 0x7f98f5685ce8> 
 $ terms        :Classes 'terms', 'formula' length 3 fire ~ var3 + var1 + var12isNA + var4 + var11 + var13 + var6 + dummy + var9 + var16isNA + var10 + var17 + var8 + var7 + var15isNA + var14isNA
  .. ..- attr(*, "variables")= language list(fire, var3, var1, var12isNA, var4, var11, var13, var6, dummy, var9, var16isNA, var10, var17, var8, var7, var15isNA, var14isNA)
  .. ..- attr(*, "factors")= int [1:17, 1:16] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. ..$ : chr [1:17] "fire" "var3" "var1" "var12isNA" ...
  .. .. .. ..$ : chr [1:16] "var3" "var1" "var12isNA" "var4" ...
  .. ..- attr(*, "term.labels")= chr [1:16] "var3" "var1" "var12isNA" "var4" ...
  .. ..- attr(*, "order")= int [1:16] 1 1 1 1 1 1 1 1 1 1 ...
  .. ..- attr(*, "intercept")= int 1
  .. ..- attr(*, "response")= int 1
  .. ..- attr(*, ".Environment")=<environment: 0x7f98f5685ce8> 
  .. ..- attr(*, "predvars")= language list(fire, var3, var1, var12isNA, var4, var11, var13, var6, dummy, var9, var16isNA, var10, var17, var8, var7, var15isNA, var14isNA)
  .. ..- attr(*, "dataClasses")= Named chr [1:17] "numeric" "factor" "factor" "logical" ...
  .. .. ..- attr(*, "names")= chr [1:17] "fire" "var3" "var1" "var12isNA" ...
 $ offset       : NULL
 $ control      :List of 3
  ..$ epsilon: num 1e-08
  ..$ maxit  : num 25
  ..$ trace  : logi FALSE
 $ method       : chr "glm.fit"
 $ contrasts    :List of 12
  ..$ var3     : chr "contr.treatment"
  ..$ var1     : chr "contr.treatment"
  ..$ var12isNA: chr "contr.treatment"
  ..$ var4     : chr "contr.treatment"
  ..$ var6     : chr "contr.treatment"
  ..$ dummy    : chr "contr.treatment"
  ..$ var9     : chr "contr.treatment"
  ..$ var16isNA: chr "contr.treatment"
  ..$ var8     : chr "contr.treatment"
  ..$ var7     : chr "contr.treatment"
  ..$ var15isNA: chr "contr.treatment"
  ..$ var14isNA: chr "contr.treatment"
 $ xlevels      :List of 8
  ..$ var3 : chr [1:7] "1" "2" "3" "4" ...
  ..$ var1 : chr [1:6] "1" "2" "3" "4" ...
  ..$ var4 : chr [1:15] "99" "A1" "C1" "D1" ...
  ..$ var6 : chr [1:4] "A" "B" "C" "Z"
  ..$ dummy: chr [1:2] "A" "B"
  ..$ var9 : chr [1:3] "A" "B" "Z"
  ..$ var8 : chr [1:7] "1" "2" "3" "4" ...
  ..$ var7 : chr [1:9] "1" "2" "3" "4" ...
 - attr(*, "class")= chr [1:2] "glm" "lm"

1 个答案:

答案 0 :(得分:1)

您在save()到磁盘之后说135x膨胀。以下是一些没有看到您的数据的提示:

  1. object.size只是衡量内存使用量的一个很小的指标,它不会跟随指针,因此字符串和因素不会被计算在内。因此,在某些情况下,它可能会严重不足。相反,使用优秀的lsos() memory-reporting function 并告诉我们报告的内容。
  2. 您的环境是否包含大量字符串(例如文本或基因组),或带有标签的高基数因子转换为字符串?或不必要的字符串行标签?检查您在options('stringsAsFactors'=F)中设置 read.csv() 。另外,请确保您从未明确使用dataframe(..., stringsAsFactors=T)。 (但是从str()
  3. 转储的情况似乎都不是这样的
  4. 不仅仅告诉我们object.size()lsos()个数字,还要告诉我们在创建这些lr对象之前和之后R会话的总内存大小,之前和在运行垃圾收集(gc()gc(reset=T))之后。然后在save(),rm()logitFire的内容之后,然后logitFire本身,报告R的总内存使用量,进行垃圾收集,报告总内存使用量以及缩小的大小。
  5. 检查环境中的其他变量/数据框/数据表/文件对象/模型:执行ls()并使用lsos()查看其大小(如@BenBolker提示)
  6. 在普通R下测试它,而不是RStudio!,RStudio偶尔会导致内存爆炸或与gc混淆(例如,如果您不小心在View()窗口中保留对数据的引用)。
  7. 检查您的./.Rprofile~/.Rprofile是否有可能已经悄悄进入的wack设置,即使是无关紧要的内容,例如加载不必要的软件包或加载不同的加载顺序(可以影子内置函数)。 你是否从另一个干净的环境/ VM /同事的登录中重复了这种行为?如果没有,请执行。
  8. 确保您从一个干净的环境开始,不要导入.RData,特别是那些散布着大量临时环境的人。。使用R --no-restore --no-save,同样在RStudio中禁用常规设置&#39;恢复RData&#39;并且&#39;保存RData`。删除你不小心留下的任何.RData。
  9. 要检查save(..., ascii = FALSE, envir = parent.frame(), compress = isTRUE(!ascii), compression_level "integer: the level of compression to be used. Defaults to 6 for gzip compression and to 9 for bzip2 or xz compression")的默认行为的一些显而易见的愚蠢事项检查没有任何内容弄乱您的默认值,同时@BenBolker说检查您环境中的内容(执行{{1}并查看他们的尺寸)。
  10. 尽管如此,总是可以在.RData上尝试手动gzip,看看它有多臃肿。
  11. 除上述所有内容外,请尝试将命令和参数减少到可重现问题的最小值。使用随机种子数据。理想情况下,我们可以进入测试用例:)或解决方案。