2011-06-06 50 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