2011-06-06 65 views
5

R教科書繼續推廣使用lapply而不是循環。這甚至對於參數的功能,如使用lapply改變參數

lapply(somelist, f, a=1, b=2) 

,但很容易,如果參數根據列表元素上改變什麼? 假設我somelist包括:

somelist$USA 
somelist$Europe 
somelist$Switzerland 

加有anotherlist與同一地區,我想用這些不斷變化的參數lapply使用?例如,當f是比率計算時,這可能很有用。

lapply(somelist, f, a= somelist$USA, b=anotherlist$USA) 

除了循環有效地貫穿這些區域嗎?

編輯: 我的問題似乎是,我試着用以前編寫的函數沒有索引...

ratio <-function(a,b){ 
z<-(b-a)/a 
return(z) 
} 

導致

lapply(data,ratio,names(data)) 

不工作。也許別人也可以從這個錯誤中學習。

回答

14

應用於列表名稱而不是列表元素。例如: -

somelist <- list('USA'=rnorm(10), 'Europe'=rnorm(10), 'Switzerland'=rnorm(10)) 
anotherlist <- list('USA'=5, 'Europe'=10, 'Switzerland'=4) 
lapply(names(somelist), function(i) somelist[[i]]/anotherlist[[i]]) 

編輯:

你也問,如果有一種方法,「只有一個循環」做這個「有效」。你應該注意到,應用不一定更有效率。效率可能取決於你的內在功能有多快。如果您想對列表中的每個元素進行操作,您將需要一個循環,無論它是否隱藏在apply()調用中。檢查這個問題:Is R's apply family more than syntactic sugar?

我上面給了可以重新寫成一個for循環的例子,你可以做一些幼稚的基準:

fun1 <- function(){ 
    lapply(names(somelist), function(i) somelist[[i]]/anotherlist[[i]]) 
} 
fun2 <- function(){ 
    for (i in names(somelist)){ 
     somelist[[i]] <- somelist[[i]]/anotherlist[[i]] 
    } 
    return(somelist) 
} 
library(rbenchmark) 

benchmark(fun1(), fun2(), 
      columns=c("test", "replications", 
      "elapsed", "relative"), 
      order="relative", replications=10000) 

我的機器上基準的輸出是這樣的:

test replications elapsed relative 
1 fun1()  10000 0.145 1.000000 
2 fun2()  10000 0.148 1.020690 

雖然這不是一個真正的工作應用程序和功能是不切合實際的任務,你可以看到,在計算時間的差異完全可以忽略。

+0

+1我看你打我到名字的想法 – 2011-06-06 14:32:40

+0

是啊,這似乎像是一個最直接的方法來解決這個問題。我加了一些關於vs申請的討論,因爲他也是這麼要求的... – Vincent 2011-06-06 14:36:15

7

你只需要制定出什麼lapply()結束。這裏列出的names()就足夠了,我們重寫f()後採取不同的參數:

somelist <- list(USA = 1:10, Europe = 21:30, 
       Switzerland = seq(1, 5, length = 10)) 
anotherlist <- list(USA = list(a = 1, b = 2), Europe = list(a = 2, b = 4), 
        Switzerland = list(a = 0.5, b = 1)) 

f <- function(x, some, other) { 
    (some[[x]] + other[[x]][["a"]]) * other[[x]][["b"]] 
} 

lapply(names(somelist), f, some = somelist, other = anotherlist) 

,並提供:

R> lapply(names(somelist), f, some = somelist, other = anotherlist) 
[[1]] 
[1] 4 6 8 10 12 14 16 18 20 22 

[[2]] 
[1] 92 96 100 104 108 112 116 120 124 128 

[[3]] 
[1] 1.500000 1.944444 2.388889 2.833333 3.277778 3.722222 4.166667 4.611111 
[9] 5.055556 5.500000 
+0

太糟糕了,我不能在這裏發佈另一個+1。有另外一個問題,試着問這個但沒有引起我的建議。你的答案再次幫助!大。 – 2011-09-22 16:37:50