Как использовать параметр saveRDS (..., refhook =)? - PullRequest
0 голосов
/ 11 января 2019

У меня сложный объект списка, вывод функции моделирования (asreml). Объект содержит все виды типов данных, включая функции и формулы, к которым присоединены среды. Я не хочу сохранять среды в RDS, потому что они довольно большие, и я сохраняю много моделей.

Я наткнулся на параметр refhook= в функциях serialize и saveRDS. В документации написано:

Функции refhook можно использовать для настройки обработки несистемных ссылочных объектов (всех внешних указателей и слабых ссылок, а также всех сред, кроме сред пространства имен и пакетов и .GlobalEnv). Функция ловушки для serialize должна возвращать символьный вектор для ссылок, которые она хочет обработать; в противном случае он должен возвращать NULL.

Данный пример модели

e <- new.env()
e$a = rnorm(10)
l <- list(a = e, b = 42)

Функция refhook действительно показывает некоторый эффект. Вывод становится меньше, когда я определяю функцию, которая возвращает символ, указывая, что среда не сохраняется:

length(serialize(l, connection = NULL))
[1] 338

s <- serialize(l, 
  connection = NULL, 
  refhook = function(x) "")
length(s)
[1] 109

Однако я не могу прочитать полученный объект:

unserialize(s)

Error in unserialize(s) : 
  no restore method available

Я также пробовал вывод необработанных векторов, подозревая, что, возможно, refhook предоставит альтернативный сериализованный вывод, но это не сработает:

s2 <- serialize(l,
  connection = NULL, 
  refhook = function(x) 
    serialize("env", connection = NULL)))

Error in serialize(l, con = NULL, refhook = function(x) serialize("env",  : 
  assertion 'TYPEOF(t) == STRSXP && LENGTH(t) > 0' failed: file 'serialize.c', line 982

Как мне использовать refhook=? Какой вывод символов ожидается от этой функции?

1 Ответ

0 голосов
/ 14 января 2019

Ах, я сам это выяснил. Ошибка «метод восстановления недоступен» означает, что вы забыли включить refhook для функции unserialize. Вам нужны оба, рефук для serialize и unserialize.

Refhook из serialize полностью свободен в возвращаемой строке. Единственный, кому нужно понять результат, это рефук unserialize.

Пример: сериализация и восстановление списков, которые содержат среды, хранящиеся централизованно

Создание хранилища сред. Давайте представим, что это внешний источник и его содержимое не нужно сериализовать. Восстановить их, внешний источник данных просто необходимо перечитать.

repo <- list()
for(i in 1:10){
  repo[[i]] <- new.env()
  repo[[i]]$a <- rnorm(1e6)
}

Одна среда имеет размер 8 МБ. Мы не хотим, чтобы все эти данные были в нашем сериализованном выводе, потому что они уже постоянно сохранены в repo.

object.size(repo[[1]]$a)

Это список, который мы хотим сериализовать. Содержит вторую среду из хранилища. Мы просто хотим сохранить числовое значение b. Для среда, мы просто хотим сохранить, что это среда 2 из репозиторий. Мы не хотим сериализовать содержимое, потому что хранилище уже есть.

l <- list(a = repo[[2]], b = 42)

Это рефук для сериализации. Это смотрит на окружающую среду в индексе и просто хранит индекс.

ser <- function(e){
  for(i in seq_along(repo)){
    if(identical(e, repo[[i]])){
      message("Identified environment #",i)
      return(as.character(i)) # Just save the 
    }
  }
  message("Environment not found in the repository")
  return(NULL)
}

Соответствующий refhook для unserialize берет индекс и загружает соответствующая среда от repo:

unser <- function(s){
  i <- as.numeric(s)
  return(repo[[i]])
}

Это экономит много места в сериализованном выводе

  • Без пользовательского refhook: также содержит среду

    object.size(serialize(l, con = NULL))
    ## 8000040 bytes
    
  • С пользовательским рефуоком: сохраняются только l$b и индекс среды

    s <- serialize(l, con = NULL, refhook = ser)
    object.size(s)
    ## 168 bytes
    

Среда загружается из базы данных при десериализации

u <- unserialize(s, refhook = unser)
## $a
## <environment: 0x000000001c91a118>
## 
## $b
## [1] 42
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...