2017-02-17 1 views
0

Я хотел бы построить структуру, которая для каждой записи хранит строку, индекс и числовое значение. Я хотел бы иметь доступ к числовому значению, запрашивая структуру данных либо с индексом, либо с строкой. Кроме того, структура данных небольшая (порядка 30 записей), но она должна быть доступна и изменена много раз (возможно, даже миллион раз). Обычно я просто использовал бы фрейм данных, но с учетом требований к эффективности, как вы думаете, будет лучше (быстрее)? Судя по синтаксису, у меня создалось впечатление, что для каждой операции (чтение или запись) необходимо получить доступ к my_struct два раза: возможно, это не очень важно, но мне интересно, будут ли экспертные R-кодеры, когда эффективность является ограничением, будут использовать это код или что-то другое.Эффективная структура данных для хранения строки, целого и действительного числа для каждой записи

# 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

Вы, вероятно, хотите 'data.frame (..., strAsAsFactors = FALSE)' там, если вам действительно нужна строка. – Frank

+0

В любом случае, data.table поддерживает эффективную индексацию по нескольким индексам с бинарным поиском и красивым синтаксисом. См. Http://r-datatable.com. Одно замечание: оно не поддерживает вставку или удаление строк/записей. – Frank

+0

@Frank получил его, спасибо за подсказку. Я определенно хочу настоящую строку, поэтому я исправил свой код соответственно. – DeltaIV

ответ

2

data.table пакет поддерживает индексы и имеет хороший синтаксис для чтения и записи:

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 ] 

Чтобы увидеть, как индекс работ, добавить verbose = TRUE, как dat[ index %in% 3:4, value := 2:3, verbose = TRUE ] и читать vignettes. (Индексы рассматриваются в четвертой.)

Benchmark, например ФП в

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 

Так что это на самом деле медленнее. Я все равно поеду с ним для (по-моему) лучшего синтаксиса. Обратите внимание, что dplyr не имеет синтаксиса для обновления подмножества строк.

С большим столом, вы бы увидели ориентир обращенную:

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 

Примечание: Путь DF также может быть написано datDF$value[ match(idx, datDF[[idxcol]]) ] <- v, но я вижу, о том же времени.

Смежные вопросы