2009-09-08 17 views
7

Frecuentemente creo estadísticas no paramétricas (densidades de loess, 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?Almacenamiento de objetos R 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.

Respuesta

9

Utilice 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 su recuperación: obtenga la cadena, luego unserialize() en un objeto R.

9

Un ejemplo de parámetros R., eso es bastante complejo:

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

El método mejor base de datos de almacenamiento para variables R depende de cómo desea utilizarlo.

tengo que hacer análisis dentro de la base de datos sobre los valores

En este caso, es necesario romper el objeto hacia abajo en valores que la base de datos puede 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 broom.

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

sólo quiero almacenamiento

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


Mis datos tiene que ser accesible por otros programas de R, y tiene que ser legible por humanos

Debe almacenar los 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 tiene que ser accesible por otros programas de R, y no necesita ser legible

Se puede escribir sus datos a una multiplataforma abierto formato binario 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. (Es probable que tenga que 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 feather paquete de guarda tramas de datos en un formato legible por ambos R y Python let.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 apartado anterior) a 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! 

Mis datos sólo tiene que ser accesible por R, y tiene que ser legible por humanos

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

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

serialize tiene que ser enviado a una conexión de texto, y en lugar de escribir en el archivo, se puede escribir en la consola y capturarlo.

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

Uso deparse con control = "all" para maximizar la reversibilidad cuando se vuelva a analizar más adelante.

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

Mis datos sólo tiene que ser accesible por R, y no tiene que ser legible por humanos

El mismo tipo de técnicas que se muestran en las secciones anteriores se pueden 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 
+0

Este último parece _muy_ ineficiente. 'saveRDS' escribe el objeto en un archivo, y luego' readBin' lo lee en la memoria. Hasta donde sé, 'serialize' escribe directamente en la memoria con' connection = NULL'. –

2

Usando textConnection/saveRDS/loadRDS es tal vez el nivel más versátil y de alta:

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

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 la envoltura list alrededor de some_object. La salida de serialize es un vector sin formato. Sin list, la sentencia INSERT se ejecutará para cada elemento vectorial. Envolverlo en una lista permite RSQLite::dbGetQuery verlo como un elemento.

para obtener el objeto de vuelta de la base de datos:

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

Lo que sucede es que toma el campo blob (que es una lista desde RSQLite no sabe cuántas filas será devuelto por la consulta) . Dado que LIMIT 1 asegura que solo se devuelve 1 fila, lo tomamos con [[1]], que es el vector bruto original. Entonces necesitas unserialize el vector sin procesar para obtener tu objeto.

Cuestiones relacionadas