Как избежать разрыва выходного размера, если я сохраню список со скопированными элементами? - PullRequest
0 голосов
/ 25 октября 2018

У меня есть несколько долгосрочных сценариев и для дальнейшей разработки или анализа после смерти в случае ошибки я сохраняю результаты в конце с saveRDS и save.image.Однако при сохранении списков, содержащих реплицированные элементы списка, возникают проблемы.Сохраняемые изображения намного больше оперативной памяти, используемой R, и иногда сохранение занимает больше времени, чем вычисления (8-часовой расчет, 1-дневное сохранение).Я чувствую, что это неэффективно, и мне нужен лучший метод.

При разработке я извлекаю выгоду из семантики R при копировании при модификации для достижения функционального стиля манипулирования данными.Я храню данные и параметры в одном столбце со столбцами списка и использую mapply, purrr::map2 и аналогичные для выполнения моделирования для каждой строки.Поэтому я копирую много данных, но хочу их эффективно сохранить.Например:

library(lobstr) # devtools::install_github("hadley/lobstr")
library(tidyr)
# Some sample data: A random matrix
x <- matrix(runif(100^2), ncol = 100)

Если я реплицирую объект, используя tidyr::crossing(), создается фрейм данных, который можно повторять по строкам.Например, я могу выполнить итерацию при начальной загрузке путем репликации строк, а затем итерации по строкам.Обычно я использую purrr::map и аналогичные для этого.

l <- crossing(tibble(mat = list(x)), i = 1:10)
str(l)
## Classes 'tbl_df', 'tbl' and 'data.frame':    10 obs. of  2 variables:
##  $ mat:List of 10
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##   ..$ : num [1:100, 1:100] 0.922 0.355 0.869 0.596 0.784 ...
##  $ i  : int  1 2 3 4 5 6 7 8 9 10

Объект не занимает много памяти, поскольку он просто содержит ссылки на одну и ту же матрицу

obj_addrs(l$mat)
## [1] "0x210390a0" "0x210390a0" "0x210390a0" "0x210390a0" "0x210390a0" "0x210390a0"
## [7] "0x210390a0" "0x210390a0" "0x210390a0" "0x210390a0"
obj_addr(x)
## [1] "0x210390a0"

Об этом небольшом размере правильно сообщает lobstr::obj_size().Однако, если я сериализую объект, я получу увеличение в 10 раз.Так как saveRDS и save.image используют serialize, это приводит к нестандартно большому файлу.

object.size(x) # The size of one list element
## 80200 bytes
lobstr::obj_size(l) # lobstr knows about the shared references
## 81,272 B
object.size(l) # base R doesn't
## 803072 bytes
object.size(serialize(l, con = NULL)) # serialize also has the big size
## 800656 bytes

Кроме того, общая ссылка не сохраняется serialize, поэтому после загрузки объекта издиск, все элементы списка дублируются в памяти:

u <- unserialize(serialize(l, con = NULL))
lobstr::obj_addrs(u$mat) 
## [1] "0x3a83dc30" "0x2104c950" "0x42254540" "0x42267df0" "0x1d0d5ac0" "0x1d0e9370"
## [7] "0x3a876070" "0x3a889920" "0x20fd18b0" "0x20fe5160"

Это приводит к абсурдной ситуации, когда вы можете записывать переменные на диск, которые занимают больше места на диске, чем у вас есть RAM на вашем компьютере!Я считаю очень полезным, что я могу использовать поведение R при копировании при изменении для функционального рабочего процесса. Как я могу сохранить это при сохранении объектов на диск и избежать дублирования идентичных данных?

...