Иногда возникает необходимость сохранять объект R в базе данных, что называется, "цельным куском", без отражения его внутренней структуры через атрибуты таблиц.

Подход к решению этой задачи достаточно очевиден: нужно выполнить сериализацию объекта, а затем сохранить его в базе. Позже, когда объект понадобится, его можно извлечь и выполнить десериализацию.

Рассмотрим, как это делается в R на примере типичного "составного" объекта — списка. В виде списков, в частности, сохраняются модели машинного обучения, построенные в пакете caret.

Составим тестовый список

l <- list("super", "important", "stuff")
print(l)

[+](1]]
[1] "super"

[[2]]
[1] "important"

[[3]]
[1] "stuff"

Сериализация объекта с помощью функции serialize позволяет превратить любой объект R в строку типа raw. После этого rawToChar преобразует бинарные данные raw в символы character.

l_char <- rawToChar(serialize(l, NULL, TRUE))
nchar(l_char) # сколько всего символов? (пригодится при создании таблицы)

Перейдём к базе данных: создадим её саму и таблицу для хранения списка. Покажем это делается на примере SQLite:

library(RSQLite) # интерфейс к SQLite

# Создаём базу данных.

db <- dbConnect(SQLite(), dbname="test.sqlite")

# Создаём таблицу с 2-мя атрибутами
# * 'id'   - первичный ключ,
# * 'list' - собственно список, сохраняемый как 'VARCHAR(100)'.
dbGetQuery(db, 'CREATE TABLE IF NOT EXISTS test
                (id INTEGER PRIMARY KEY AUTOINCREMENT,
                 list VARCHAR(100))'
           )

Приятно, что объект, который может иметь весьма сложную структуру, сохраняется в обычном символьном типе данных. В данном случае, в VARCHAR(n).

Поместим сериализованный список в таблицу test

# Создаём data.frame для вставки в таблицу БД.

df <- data.frame(lst = l_char)

# Вставляем данные в таблицу БД.

dbGetPreparedQuery(db, 'INSERT INTO test (list) values (:lst)',
                   bind.data = df)

и удалим из памяти исходный список, а также связанные с ним данные

rm(l, l_char, df)

Прошло некоторое время и нам снова понадобился сохранённый список. Извлекаем его из таблицы:

df2 <- dbGetQuery(db, "SELECT * FROM test")
dbDisconnect(db) # не забываем разорвать соединение с БД.

Восстанавливаем представление списка в R

l2 <- unserialize(charToRaw(df2$list))

и работаем с ним:

print(l2)

[[1]]
[1] "super"

[[2]]
[1] "important"

[[3]]
[1] "stuff"

Читайте также...

  • Множество способов сохранения объектов R, в зависимости от поставленной задачи, описано здесь.


Комментарии

comments powered by Disqus