2017-02-17 3 views
0

Ich möchte eine Struktur erstellen, die für jeden Datensatz eine Zeichenfolge, einen Index und einen numerischen Wert speichert. Ich möchte auf den numerischen Wert zugreifen können, indem ich die Datenstruktur entweder mit dem Index oder dem String abfrage. Außerdem ist die Datenstruktur klein (in der Größenordnung von 30 Datensätzen), aber sie muss viele Male (möglicherweise sogar eine Million Mal) aufgerufen und modifiziert werden. Normalerweise würde ich nur einen Datenrahmen verwenden, aber angesichts der Effizienzanforderungen, denken Sie, dass es einen besseren (schnelleren) Weg geben würde? Nach der Syntax zu urteilen, habe ich den Eindruck, dass auf my_struct zugegriffen werden muss zweimal für jede Operation (lesen oder schreiben): vielleicht ist es keine große Sache, aber ich frage mich, ob Experte R Programmierer, wenn Effizienz eine Einschränkung ist, würde dies verwenden Code oder etwas anderes.Effiziente Datenstruktur zum Speichern einer Zeichenfolge, einer ganzen Zahl und einer reellen Zahl für jeden Datensatz

# define data structure 
my_struct <- data.frame(index = c(3:14,24), variable = c("Pin", "Pout", "Tout", "D", "L", "mu", "R","K","c","omega","alpha","beta","gamma"), value = runif(13), stringsAsFactors = FALSE) 

# examples of read/write statements 
my_struct$value[my_struct$variable == "Pin"] 
my_struct$value[my_struct$index %in% c(3:14)] 
my_struct$value[my_struct$index %in% c(3,5)] <- rnorm(2) 
+2

Wahrscheinlich wollen Sie 'data.frame (..., stringsAsFactors = FALSE)' da, wenn Sie wirklich eine Zeichenfolge wollen. – Frank

+0

Wie auch immer, data.table unterstützt eine effiziente Indizierung auf mehreren Indizes mit binärer Suche und netter Syntax. Siehe http://r-datatable.com Eine Sache jedoch zu beachten: Es unterstützt nicht das Einfügen oder Löschen von Zeilen/Datensätzen. – Frank

+0

@Frank hab es geschafft, danke für den Tipp. Ich möchte definitiv eine echte Saite, also korrigiere ich meinen Code entsprechend. – DeltaIV

Antwort

2

Das data.table Paket unterstützt Indizes und hat nette Syntax für Lese- und Schreib:

library(data.table) 
dat <- data.table(index = c(3:14,24), variable = c("Pin", "Pout", "Tout", "D", "L", "mu", "R","K","c","omega","alpha","beta","gamma"), value = runif(13)) 

setindex(dat, index) 
setindex(dat, variable) 

# read 
dat[ index %in% 3:4, value ] 

# write 
dat[ index %in% 3:4, value := 2:3 ] 

zu sehen, wie die Index-Werke, fügen verbose = TRUE, wie dat[ index %in% 3:4, value := 2:3, verbose = TRUE ] und die vignettes lesen. (Indizes in der vierten abgedeckt sind.)

Benchmark für OPs Beispiel

library(microbenchmark) 
datDF = data.frame(dat) 

n_idx = 2L 
idxcol = "variable" 
idx = sample(dat[[idxcol]], n_idx) 
v  = rnorm(length(idx)) 
e  = substitute(idxcol %in% idx, list(idxcol = as.name(idxcol))) 
microbenchmark(
    DT = dat[eval(e), value := v ], 
    DF = datDF$value[ datDF[[idxcol]] %in% idx ] <- v 
) 

# Unit: microseconds 
# expr  min  lq  mean median  uq  max neval 
# DT 449.694 473.136 487.17583 481.042 487.0065 1049.193 100 
# DF 27.742 30.239 44.21525 36.065 38.4225 854.723 100 

So ist es tatsächlich langsamer. Ich würde immer noch für die (meiner Meinung nach) schönere Syntax mitgehen. Beachten Sie, dass dplyr keine Syntax zum Aktualisieren einer Teilmenge von Zeilen hat.

mit einem großen Tisch, dann würden Sie die Benchmark umgekehrt sehen:

dat = data.table(variable = do.call(paste0, CJ(LETTERS, LETTERS, LETTERS, LETTERS))) 
dat[, index := .I ] 
dat[, value := rnorm(.N) ] 
setindex(dat, index) 
setindex(dat, variable) 

datDF = data.frame(dat) 

n_idx = 2L 
idxcol = "variable" 
idx = sample(dat[[idxcol]], n_idx) 
v  = rnorm(length(idx)) 
e  = substitute(idxcol %in% idx, list(idxcol = as.name(idxcol))) 
microbenchmark(
    DT = dat[eval(e), value := v ], 
    DF = datDF$value[ datDF[[idxcol]] %in% idx ] <- v 
) 

# Unit: microseconds 
# expr  min   lq  mean median  uq  max neval 
# DT 471.887 492.5545 701.7914 757.766 817.827 1647.582 100 
# DF 17387.134 17729.3280 23750.6721 22629.490 25912.309 83057.928 100 

Hinweis: Die DF Art und Weise auch datDF$value[ match(idx, datDF[[idxcol]]) ] <- v geschrieben werden kann, aber ich bin über das gleiche Timing zu sehen.

Verwandte Themen