Using lapply with changing arguments

风格不统一 提交于 2019-11-27 20:18:55
Vincent

Apply over list names rather than list elements. E.g.:

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]])

EDIT:

You also ask if there is a way "except for a loop" to do this "efficiently". You should note that the apply will not necessarily be more efficient. Efficiency will probably be determined by how quick your inner function is. If you want to operate on each elements of a list, you will need a loop, whether it is hidden in an apply() call or not. Check this question: Is R's apply family more than syntactic sugar?

The example I gave above can be re-written as a for loop, and you can make some naive benchmarks:

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)

The output of the benchmark on my machine was this:

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

Although this is not a real work application and the functions are not realistic tasks, you can see that the difference in computation time is quite negligible.

You just need to work out what to lapply() over. Here the names() of the lists suffices, after we rewrite f() to take different arguments:

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)

Giving:

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
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!