9

R 教科书继续提倡使用 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))

这是行不通的。也许其他人也可以从这个错误中吸取教训。

4

2 回答 2

16

应用于列表名称而不是列表元素。例如:

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() 调用中。检查这个问题:R 的应用系列不仅仅是语法糖吗?

我上面给出的例子可以重写为一个 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

虽然这不是一个真正的工作应用程序并且功能不是现实的任务,但您可以看到计算时间的差异可以忽略不计。

于 2011-06-06T14:22:48.947 回答
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
于 2011-06-06T14:28:15.370 回答