2017-02-17 56 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(...,stringsAsFactors = 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。 (指數在第四個覆蓋。)

基準爲OP的例子

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,但我看到大約相同的時間。