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

У меня есть несколько долгосрочных сценариев и для дальнейшей разработки или анализа после смерти в случае ошибки я сохраняю результаты в конце 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"

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

0 ответов

Другие вопросы по тегам