saveRDS膨胀对象的大小

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了saveRDS膨胀对象的大小相关的知识,希望对你有一定的参考价值。

这是一个棘手的问题,因为我不能提供一个可重复的例子,但我希望其他人可能有过处理这个问题的经验。

基本上我有一个函数可以从DB中提取大量数据,清理并减小大小并循环一些参数,以生成一系列lm模型对象,参数值和其他参考值。这被编译成一个总计大约10mb的复杂列表结构。

然后它应该在AWS s3上保存为RDS文件,在生产环境中检索它以构建预测。

EG

db.connection <- db.connection.object


build_model_list <- function(db.connection) {   


clean_and_build_models <- function(db.connection, other.parameters) {


get_db_data <- function(db.connection, some.parameters) {# Retrieve db data} ## Externally defined

db.data <- get_db_data() 


build_models <- function(db.data, some.parameters) ## Externally defined

clean_data <- function(db.data, some.parameters) {# Cleans and filters data based on parameters} ## Externally defined


clean.data <- clean_data() 


lm_model <- function(clean.data) {# Builds lm model based on clean.data} ## Externally defined

lm.model <- lm_model()


return(list(lm.model, other.parameters))} ## Externally defined


looped.model.object <- llply(some.parameters, clean_and_build_models)

return(looped.model.object)}


model.list <- build_model_list()

saveRDS(model.list, "~/a_place/model_list.RDS")

我得到的问题是,当我在本地保存为RDS或尝试上传到AWS s3时,内存仅10MB的'model.list'对象将膨胀到多GB。

我应该注意,虽然该函数处理非常大量的数据(约500万行),但输出中使用的数据不会超过几百行。

在Stack Exchange上读取有限的信息,我发现在main函数中移动一些外部定义的函数(作为包的一部分)(例如clean_data和lm_model)有助于减少RDS保存大小。

然而,这有一些很大的缺点。

首先是它的试验和错误,没有明确的逻辑顺序,经常崩溃和建立列表对象需要几个小时,这是一个非常长的调试周期。

其次,这意味着我的主要功能将是数百行,这将使未来的更改和调试变得更加棘手。

我的问题是:

有没有人遇到过这个问题?

关于是什么导致它的任何假设?

有人找到了合乎逻辑的非试错法吗?

谢谢你的帮助。

答案

它需要一些挖掘,但我确实找到了最终的解决方案。

事实证明,这是lm模型对象是有罪的一方。基于这篇非常有用的文章:

https://blogs.oracle.com/R/entry/is_the_size_of_your

事实证明,lm.object $ terms组件包含一个环境组件,该组件在构建模型时引用全局环境中存在的对象。在某些情况下,当你保存RDS R时会尝试将环境对象绘制到保存对象中。

由于我在全局环境中有大约0.5GB的空间和大约200 lm模型对象的列表数组,这导致RDS对象在实际尝试压缩~100GB数据时显着膨胀。

测试这是否是导致问题的原因。执行以下代码:

as.matrix(lapply(lm.object, function(x) length(serialize(x,NULL)))) 

这将告诉您$ terms组件是否正在膨胀。

以下代码将从$ terms组件中删除环境引用:

rm(list=ls(envir = attr(lm.object$terms, ".Environment")), envir = attr(lm.object$terms, ".Environment")) 

请注意,虽然它也会删除它引用的所有全球环境对象。

另一答案

对于模型对象,您还可以简单地删除对环境的引用。

像这样的例子

ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14)
trt <- c(4.81,4.17,4.41,3.59,5.87,3.83,6.03,4.89,4.32,4.69)
group <- gl(2, 10, 20, labels = c("Ctl","Trt"))
weight <- c(ctl, trt)
lm.D9 <- lm(weight ~ group) 

attr(lm.D9$terms, ".Environment") <- NULL
saveRDS(lm.D9, file = "path_to_save.RDS")

不幸的是,这打破了模型 - 但您可以在再次加载后手动添加环境。

readRDS("path_to_save.RDS")
attr(lm.D9$terms, ".Environment") <- globalenv()

这对我的具体用例有所帮助,对我来说看起来有点安全......

以上是关于saveRDS膨胀对象的大小的主要内容,如果未能解决你的问题,请参考以下文章

Android片段布局完成膨胀

创建片段的新实例时菜单未膨胀

片段上的 Mapbox 膨胀视图

Android TabLayout ViewPager 不会在 backstack 上膨胀标签片段

在我的“设置”片段中膨胀类 PreferenceScreen 时出错

Android:在drawerlayout中使用地图膨胀片段时出错