2009-09-08 2 views
7

Я часто создаю непараметрическую статистику (лёсс, плотность ядра и т. Д.) Для данных, которые я выхожу из реляционной базы данных. Чтобы упростить управление данными, я хотел бы сохранить вывод R в моей БД. Это легко с простыми кадрами данных чисел или текста, но я не понял, как хранить объекты R в моей реляционной базе данных. Так есть способ хранения вектора плотности ядра, например, обратно в реляционную базу данных?Сохранение объектов R в реляционной базе данных

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

ответ

9

Используйте функцию сериализации, чтобы превратить любой объект R в строку (raw или character), а затем сохранить эту строку. См. help(serialize).

Обратный это для извлечения: получите строку, затем unserialize() в объект R.

9

Переменная пример R, это довольно сложный:

library(nlme) 
model <- lme(uptake ~ conc + Treatment, CO2, random = ~ 1 | Plant/Type) 

Лучший способ базы данных для хранения переменных R зависит от того, как вы хотите использовать его.

мне нужно сделать в базе данных-аналитики от значений

В этом случае вам нужно разбить объект вниз в значения, что база данных может обрабатывать изначально. Обычно это означает преобразование его в один или несколько кадров данных. Самый простой способ сделать это - использовать пакет broom.

library(broom) 
coefficients_etc <- tidy(model) 
model_level_stats <- glance(model) 
row_level_stats <- augment(model) 

Я просто хочу, хранение

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


Мои данных должны быть доступны, кроме R программ, а также должны быть читаемым человек

Вы должны хранить свои данные в текстовом формате кросс-платформенного; вероятно, JSON или YAML. JSON не поддерживает некоторые важные концепции, такие как Inf; YAML является более общим, но поддержка в R не столь зрелой. XML также возможен, но слишком подробен, чтобы быть полезным для хранения больших массивов.

library(RJSONIO) 
model_as_json <- toJSON(model) 
nchar(model_as_json) # 17916 

library(yaml) 
# yaml package doesn't yet support conversion of language objects, 
# so preprocessing is needed 
model2 <- within(
    model, 
    { 
    call <- as.character(call) 
    terms <- as.character(terms) 
    } 
) 
model_as_yaml <- as.yaml(model2) 
nchar(model_as_yaml) # 14493 

Мои данные должны быть доступны, кроме R программ, и не нужно быть человеком-читаемый

Вы можете написать свои данные в открытом, кросс-платформенный двоичный формат, такой как HFD5. В настоящее время поддержка файлов HFD5 (через rhdf5) ограничена, поэтому сложные объекты не поддерживаются. (Вы, вероятно, нужно unclass все.)

library(rhdf5) 
h5save(rapply(model2, unclass, how = "replace"), file = "model.h5") 
bin_h5 <- readBin("model.h5", "raw", 1e6) 
length(bin_h5) # 88291 not very efficient in this case 

feather пакет позволяет вам сохранить кадры данных в формате читаться как R и Python.Чтобы использовать это, вам сначала нужно преобразовать объект модели в кадры данных, как описано в разделе метлы ранее в ответе.

library(feather) 
library(broom) 
write_feather(augment(model), "co2_row.feather") # 5474 bytes 
write_feather(tidy(model), "co2_coeff.feather") # 2093 bytes 
write_feather(glance(model), "co2_model.feather") # 562 bytes 

Другой альтернативой является, чтобы сохранить текстовую версию переменной (смотрите предыдущий раздел) в архивный файл и сохранить его байты в базе данных.

writeLines(model_as_json) 
tar("model.tar.bz", "model.txt", compression = "bzip2") 
bin_bzip <- readBin("model.tar.bz", "raw", 1e6) 
length(bin_bzip) # only 42 bytes! 

Мои данные должны только быть доступны R, и должен быть читаемый человеком

Есть два варианта для превращения переменной в строку: serialize и deparse.

p <- function(x) 
{ 
    paste0(x, collapse = "\n") 
} 

serialize должно быть отправлено текстовое сообщение, и вместо того, чтобы писать в файл, вы можете написать в консоль и захватить его.

model_serialized <- p(capture.output(serialize(model, stdout()))) 
nchar(model_serialized) # 23830 

Использование deparse с control = "all", чтобы максимизировать обратимость при повторном разборе позже.

model_deparsed <- p(deparse(model, control = "all")) 
nchar(model_deparsed) # 22036 

Мои данные нужно только быть доступными R, и не нужно быть человеком-читаемый

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

serialize также может записывать переменные в двоичном формате. В этом случае его наиболее легко использовать с его оберткой saveRDS.

saveRDS(model, "model.rds") 
bin_rds <- readBin("model.rds", "raw", 1e6) 
length(bin_rds) # 6350 
+0

Этот последний кажется _very_ неэффективным. 'saveRDS' записывает объект в файл, а затем' readBin' считывает его в память. Насколько мне известно, 'serialize' записывает непосредственно в память с помощью' connection = NULL'. –

2

Использование textConnection/saveRDS/loadRDS, пожалуй, самый универсальный и высокий уровень:

zz<-textConnection('tempConnection', 'wb') 
saveRDS(myData, zz, ascii = T) 
TEXT<-paste(textConnectionValue(zz), collapse='\n') 

#write TEXT into SQL 
... 
closeAllConnections() #if the connection persists, new data will be appended 

#reading back: 
#1. pull from SQL into queryResult 
... 
#2. recover the object 
recoveredData <- readRDS(textConnection(queryResult$TEXT)) 
2

Для sqlite (и, возможно, другие):

CREATE TABLE data (blob BLOB); 

Сейчас в R:

RSQLite::dbGetQuery(db.conn, 'INSERT INTO data VALUES (:blob)', params = list(blob = list(serialize(some_object))) 

Обратите внимание на обертку list вокруг some_object. Выходной сигнал serialize является необработанным вектором. Без list оператор INSERT будет выполняться для каждого векторного элемента. Обертка в списке позволяет RSQLite::dbGetQuery видеть его как один элемент.

Чтобы получить объект обратно из базы данных:

some_object <- unserialize(RSQLite::dbGetQuery(db.conn, 'SELECT blob FROM data LIMIT 1')$blob[[1]]) 

Что происходит здесь вы берете поле blob (который является списком, поскольку RSQLite не знает, сколько строк будет возвращено запросом) , Начиная с LIMIT 1, возвращается только 1 строка, мы берем ее с [[1]], который является исходным сырым вектором. Затем вам понадобится unserialize необработанный вектор, чтобы получить ваш объект.