2009-09-08 13 views
7

Ich erstelle häufig nichtparametrische Statistiken (Löss, Kerneldichten usw.) auf Daten, die ich aus einer relationalen Datenbank heraushole. Um die Datenverwaltung zu vereinfachen, möchte ich die R-Ausgabe in meiner Datenbank speichern. Dies ist mit einfachen Datenrahmen von Zahlen oder Text einfach, aber ich habe nicht herausgefunden, wie man R Objekte in meiner relationalen Datenbank speichert. Gibt es also eine Möglichkeit, einen Vektor von Kerndichten beispielsweise in eine relationale Datenbank zu speichern?Speichern von R-Objekten in einer relationalen Datenbank

Momentan arbeite ich darum herum, indem ich die R-Objekte auf einem Netzwerklaufwerkplatz speichere, damit andere die Objekte nach Bedarf laden können.

Antwort

9

Verwenden Sie die Serialisierungsfunktion, um ein beliebiges R-Objekt in eine (Raw- oder Zeichen-) Zeichenkette umzuwandeln, und speichern Sie dann diese Zeichenkette. Siehe help(serialize).

Umkehren Sie dies für den Abruf: Holen Sie sich die Zeichenfolge, dann unserialize() in ein R-Objekt.

9

Ein Beispiel R Variable, das ist ziemlich komplex:

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

Die beste Speicherdatenbankmethode für R Variablen hängt davon ab, wie Sie es verwenden möchten.

Ich brauche in-Database Analytics auf den Werten zu tun

In diesem Fall müssen Sie das Objekt nach unten in Werte brechen, die die Datenbank nativ verarbeiten kann. Dies bedeutet normalerweise, dass es in einen oder mehrere Datenrahmen umgewandelt wird. Der einfachste Weg dazu ist das broom Paket.

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

Ich will nur Speicher

In diesem Fall können Sie Ihre R Variablen serialisiert werden soll. Das heißt, sie in eine Zeichenfolge oder einen binären Blob umzuwandeln. Dafür gibt es mehrere Methoden.


Meine Daten hat von anderen Programmen als R zugänglich sein muss und für Menschen lesbare

Sie sein sollten Ihre Daten in einem plattformübergreifenden Textformat speichern; wahrscheinlich JSON oder YAML. JSON unterstützt einige wichtige Konzepte wie Inf; YAML ist allgemeiner, aber die Unterstützung in R ist nicht so ausgereift. XML ist ebenfalls möglich, aber zu ausführlich, um große Arrays zu speichern.

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 

Meine Daten hat von anderen Programmen als R zugänglich sein, und muss nicht vom Menschen lesbar sein

Sie können Ihre Daten in eine offene, plattformübergreif schreiben Binärformat wie HFD5. Derzeit ist die Unterstützung für HFD5-Dateien (über rhdf5) begrenzt, so dass komplexe Objekte nicht unterstützt werden. (Sie werden wahrscheinlich zu unclass alles brauchen.)

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 

Das feather Paket Lassen Sie uns sparen Sie Datenrahmen in einem Format sowohl lesbar R und Python.Um dies zu verwenden, müssten Sie zuerst das Modellobjekt in Datenrahmen konvertieren, wie im Abschnitt "Besen" in der Antwort zuvor beschrieben.

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 

Eine weitere Alternative ist eine Textversion der Variablen zu speichern (siehe vorheriger Abschnitt) in eine komprimierte Datei und speichern ihre Bytes in der Datenbank.

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! 

braucht Meine Daten nur durch R zugänglich sein muss und zum Drehen einer Variable in einen String Menschen lesbaren

Es gibt zwei Möglichkeiten zu: serialize und deparse.

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

serialize muss eine Textverbindung gesendet werden, und anstatt in Datei schreiben, können Sie auf die Konsole schreiben und aufzunehmen.

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

Verwenden deparse mit control = "all" die Reversibilität zu maximieren, wenn später wieder Parsen.

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

Meine Daten braucht nur mit dem R zu sein, und muss nicht für Menschen lesbare

Die gleiche Art von Techniken, die in den vorhergehenden Abschnitten gezeigt werden, können hier angewendet werden . Sie können eine serialisierte oder deklarierte Variable komprimieren und als Rohvektor erneut lesen.

serialize kann auch Variablen in einem binären Format schreiben. In diesem Fall wird es am einfachsten mit seiner Hülle saveRDS verwendet.

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

Dieser letzte scheint _sehr_ ineffizient. 'saveRDS' schreibt das Objekt in eine Datei, und' readBin' liest es in den Speicher. Soweit ich weiß, schreibt 'serialize' direkt in den Speicher mit' connection = NULL'. –

2

Mit textConnection/saveRDS/loadRDS ist vielleicht der vielseitigste und hohe Niveau:

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

Für sqlite (und möglicherweise andere):

CREATE TABLE data (blob BLOB); 

Jetzt in R:

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

Beachten Sie die list Verpackung um some_object. Die Ausgabe von serialize ist ein roher Vektor. Ohne list würde die INSERT-Anweisung für jedes Vektorelement ausgeführt werden. Wenn man es in eine Liste einpackt, kann man es als ein Element in RSQLite::dbGetQuery sehen.

Um das Objekt wieder aus der Datenbank zu erhalten:

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

Was hier passiert, nehmen Sie das Feld blob (die eine Liste ist seit RSQLite nicht weiß, wie viele Zeilen werden von der Abfrage zurückgegeben werden) . Da LIMIT 1 sicherstellt, dass nur 1 Zeile zurückgegeben wird, nehmen wir es mit [[1]], was der ursprüngliche rohe Vektor ist. Dann müssen Sie unserialize den rohen Vektor, um Ihr Objekt zu erhalten.

Verwandte Themen