2016-07-15 4 views
1

Любой общий способ сделать следующий R-код быстрее? Например, в понимании python dict (см. Эквивалент ниже) было бы более быстрой альтернативой.словарь и понимание списка в R

R:

l1 <- 1:3 
l2 <- c("a", "b", "c") 
foo <- function(x) {return(5*x)} 
bar <- list() 
for (i in 1:length(l1)) bar[l2[i]] <- foo(l1[i]) 

Python

l1 = range(1, 4) 
l2 = ["a", "b", "c"] 
def foo(x): 
    return 5*x 
{b: foo(a) for a, b in zip(l1, l2)} 
+4

'setNames (lapply (l1, foo), l2)'. – joran

+1

Если вам это не нужно как список (потому что это всего лишь одно число на элемент), вы можете использовать 'sapply' вместо' lapply'. – Frank

+1

Поскольку умножение (и, следовательно, 'foo') векторизовано, вы можете просто выполнить' as.list (setNames (l1 * 5, l2)) 'или' as.list (setNames (foo (l1), l2)) '; отмените 'as.list', чтобы сохранить его как именованный числовой вектор. – alistaire

ответ

3

Мы говорим о скорости, так что давайте делать некоторые бенчмаркинг:

library(microbenchmark) 
microbenchmark(op = {for (i in 1:length(l1)) bar[l2[i]] <- foo(l1[i])}, 
       lapply = setNames(lapply(l1,foo),l2), 
       vectorised = setNames(as.list(foo(l1)), l2)) 

Unit: microseconds 
     expr min lq  mean median  uq max neval 
     op 7.982 9.122 10.81052 9.693 10.548 36.206 100 
    lapply 5.987 6.557 7.73159 6.842 7.270 55.877 100 
vectorised 4.561 5.132 6.72526 5.417 5.987 80.964 100 

Но эти маленькие значения не значат , поэтому я накачал длину вектора до 10000, где вы действительно увидите разницу:

l <- 10000 
l1 <- seq_len(l) 
l2 <- sample(letters, l, replace = TRUE) 

microbenchmark(op = {bar <- list(); for (i in 1:length(l1)) bar[l2[i]] <- foo(l1[i])}, 
       lapply = setNames(lapply(l1,foo),l2), 
       vectorised = setNames(as.list(foo(l1)), l2), 
       times = 100) 

Unit: microseconds 
     expr  min  lq  mean  median  uq  max neval 
     op 30122.865 33325.788 34914.8339 34769.8825 36721.428 41515.405 100 
    lapply 13526.397 14446.078 15217.5309 14829.2320 15351.933 19241.767 100 
vectorised 199.559 259.997 349.0544 296.9155 368.614 3189.523 100 

Но, ссылаясь на то, что говорили все остальные, это не обязательно должен быть список. Если вы удалите требование из списка:

microbenchmark(setNames(foo(l1), l2)) 

Unit: microseconds 
        expr min  lq  mean median  uq  max neval 
setNames(foo(l1), l2) 22.522 23.8045 58.06888 25.0875 48.322 1427.417 100 
+0

/уважение и/спасибо @ sebastian-c –