team software questions org how frequently data citation asked database r object r-faq

database - software - Almacenamiento de objetos R en una base de datos relacional



r software (4)

Use la función de serialización para convertir cualquier objeto R en una cadena (en bruto o de caracteres), luego almacene esa cadena. Ver help(serialize) .

Invierta esto para recuperarlo: obtenga la secuencia y luego unserialize() en un objeto R.

Frecuentemente creo estadísticas no paramétricas (loess, densidades de kernel, etc.) en datos que saco de una base de datos relacional. Para facilitar la administración de datos, me gustaría almacenar la salida R dentro de mi base de datos. Esto es fácil con marcos de datos simples de números o texto, pero no he descubierto cómo almacenar objetos R en mi base de datos relacional. Entonces, ¿hay alguna manera de almacenar un vector de densidades de kernel, por ejemplo, de nuevo en una base de datos relacional?

En este momento, soluciono esto guardando los objetos R en un espacio de disco de red para que otros puedan cargar los objetos según sea necesario.


Un ejemplo de variable R, eso es bastante complejo:

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

El mejor método de base de datos de almacenamiento para las variables R depende de cómo quiera usarlo.

Necesito hacer análisis en la base de datos sobre los valores

En este caso, debe dividir el objeto en valores que la base de datos pueda manejar de forma nativa. Esto generalmente significa convertirlo en uno o más marcos de datos. La forma más fácil de hacerlo es usar el paquete de broom .

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

Solo quiero almacenamiento

En este caso, quiere serializar sus variables R. Es decir, convertirlos en una cadena o un blob binario. Hay varios métodos para esto.

Mis datos deben ser accesibles por programas que no sean R, y deben ser legibles por el ser humano

Debe almacenar sus datos en un formato de texto multiplataforma; probablemente JSON o YAML. JSON no admite algunos conceptos importantes como Inf ; YAML es más general, pero el soporte en R no es tan maduro. XML también es posible, pero es demasiado detallado para ser útil para almacenar matrices grandes.

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

Mis datos tienen que ser accesibles por programas que no sean R, y no necesitan ser legibles por humanos

Puede escribir sus datos en un formato binario abierto y multiplataforma como HFD5. Actualmente, la compatibilidad con los archivos HFD5 (a través de rhdf5 ) es limitada, por lo que los objetos complejos no son compatibles. (Probablemente necesites unclass todo).

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

El paquete de feather permite guardar marcos de datos en un formato legible por R y Python. Para usar esto, primero debe convertir el objeto modelo en marcos de datos, como se describe en la sección de escoba al principio de la respuesta.

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

Otra alternativa es guardar una versión de texto de la variable (ver sección anterior) en un archivo comprimido y almacenar sus bytes en la base de datos.

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!

Solo R necesita acceder a mis datos y debe ser legible por el ser humano

Hay dos opciones para convertir una variable en una cadena: serialize y deparse .

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

serialize necesita ser enviado a una conexión de texto, y en lugar de escribir en un archivo, puede escribir en la consola y capturarlo.

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

Use deparse con control = "all" para maximizar la reversibilidad al volver a analizar más tarde.

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

Solo R necesita acceder a mis datos y no es necesario que sean legibles por el ser humano

El mismo tipo de técnicas que se muestran en las secciones anteriores se puede aplicar aquí. Puede comprimir una variable serializada o deparsed y volver a leerla como un vector sin formato.

serialize también puede escribir variables en un formato binario. En este caso, es más fácil de usar con su envoltorio saveRDS .

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


Usar textConnection / saveRDS / loadRDS es quizás el nivel más versátil y alto:

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))


Para sqlite (y posiblemente otros):

CREATE TABLE data (blob BLOB);

Ahora en R :

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

Tenga en cuenta el contenedor de list alrededor de some_object . El resultado de serialize es un vector sin formato. Sin list , la instrucción INSERT se ejecutará para cada elemento vectorial. Envolverlo en una lista permite que RSQLite::dbGetQuery vea como un elemento.

Para recuperar el objeto de la base de datos:

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

Lo que sucede aquí es que tomes el blob campo (que es una lista ya que RSQLite no sabe cuántas filas serán devueltas por la consulta). Como LIMIT 1 asegura que solo se devuelve 1 fila, la tomamos con [[1]] , que es el vector bruto original. Luego necesita unserialize el vector sin procesar para obtener su objeto.