内部创建的ggplot2对象与外部函数之间的RDS文件大小差异

时间:2018-06-15 23:42:43

标签: r ggplot2

我正在尝试构建一个使用函数生成多个ggplot2对象的R项目。但是,我注意到,将这些对象保存为RDS文件时,文件大小比我预期的要大得多。我意识到,保存使用函数生成的RDS对象以及全局环境中的相同图,尽管在R会话中占用了相同的内存,但仍会提供两种截然不同的文件大小。例如:

library(ggplot2)
data <- data.frame(x = rnorm(1e6))

p1 <- ggplot(data) + 
  geom_histogram(aes(x = x))

plot_fun <- function(y) {
  p <- ggplot(y) +
    geom_histogram(aes(x = x))
  return(p)
}

p2 <- plot_fun(data)

object.size(p1) # 8 Mb
object.size(p2) # 8 Mb

saveRDS(p1, "plot1.rds")
saveRDS(p2, "plot2.rds")

file.info("plot1.rds", "plot2.rds")

有谁知道为什么会这样?我是否从函数中错误地返回了对象?

2 个答案:

答案 0 :(得分:6)

这个很棘手。我最初的建议是使用pryr::object_size(),它更全面地包含存储在对象环境中的对象的大小,但这只显示了两个ggplot对象之间的微小差异。

但是,ggplot个对象包含一个环境,$plot_env组件,其内容将与对象一起存储。

p2$plot_env的环境与您的函数内部对应:

ls(p2$plot_env)
# [1] "p" "y"

p1$plot_env的环境是全局环境,其中包含数据的副本以及其他绘图对象......

ls(p1$plot_env)
# [1] "data"     "p1"       "p2"       "plot_fun"

但这对我来说似乎仍然有些神秘。 p1(在其环境中包含更多对象)创建较小的文件大小(7.4M),而p2(包含较少的对象)创建较大的文件大小(22M),p1天真地似乎存储了更多东西:

sapply(p1$plot_env,object.size)
## plot_fun       p1       p2     data 
##     6568  8004632  8004632  8000728 
sapply(p2$plot_env,object.size)
##       p       y 
## 8004632 8000728 

这是某种递归的噩梦吗?环境引用其他环境,所有环境都必须存储?正如@Chris所说:

  

p2的环境具有全球环境的父环境,而p1的环境是全球环境......我想知道什么是发生的是,当R需要序列化从另一个env(即父env)继承的环境时,它会将父env与子节点一起保存。这可以解释为什么与p1

相比,保存p2会导致文件较小

如果我用全局环境替换p2的绘图环境,文件大小会变小......我认为我没有打破绘图对象。

p2$plot_env <- p1$plot_env
saveRDS(p2, "plot2.rds")
system("ls -lht plot?.rds")
## -rw-r--r--  1 bolker  staff   7.4M 15 Jun 20:15 plot2.rds
## -rw-r--r--  1 bolker  staff   7.4M 15 Jun 20:14 plot1.rds

如果你的工作流允许,你可以考虑存储这些图的渲染版本(如PDF / SVG /无论什么)而不是绘图对象本身......虽然绘图对象肯定更灵活。

答案 1 :(得分:1)

如果要获得对象的准确尺寸,请使用: length(serialize(p1,NULL))。 如上所述,这种差异来自环境。