R 创建向量列表';s元素:循环与应用

R 创建向量列表';s元素:循环与应用,r,function,R,Function,我最近开始用R编码,我读到apply函数比for循环快 假设我想从向量中提取数字并将其插入到列表中。使用for循环不是问题。然而,我很好奇,应用函数是否也能做到这一点,以及这是否有任何意义。我有这样的想法(这是行不通的): some.list创建包含向量元素的列表有各种不同的方法(我经常使用的方法是as.list)。您可以使用R基准测试包为自己进行测试,速度更快: fun1 <- function(v) as.list(v) fun2 <- function(v) { l <

我最近开始用R编码,我读到apply函数比for循环快

假设我想从向量中提取数字并将其插入到列表中。使用for循环不是问题。然而,我很好奇,应用函数是否也能做到这一点,以及这是否有任何意义。我有这样的想法(这是行不通的):


some.list创建包含向量元素的列表有各种不同的方法(我经常使用的方法是
as.list
)。您可以使用R基准测试包为自己进行测试,速度更快:

fun1 <- function(v) as.list(v)
fun2 <- function(v) {
  l <- vector("list", length(v))  # Thanks to @MrFlick for pre-allocation tip
  for (i in seq_along(v)) {
    l[[i]] <- v[i]
  }
  l
}
fun2a <- function(v) {
  l <- vector("list", length(v))  # Thanks to @MrFlick for pre-allocation tip
  sapply(seq_along(v), function(i) l[[i]] <<- v[i])
  l
}
fun3 <- function(v) lapply(v, identity)
fun3a <- function(v) sapply(v, identity, simplify=FALSE)
fun4 <- function(v) unname(split(v, seq_along(v)))

v <- 1:10000
# Check if all return same thing (see http://stackoverflow.com/a/30850654/3093387)
all(sapply(list(fun2(v), fun2a(v), fun3(v), fun3a(v), fun4(v)), identical, fun1(v)))
# [1] TRUE

library(microbenchmark)
microbenchmark(fun1(v), fun2(v), fun2a(v), fun3(v), fun3a(v), fun4(v))
# Unit: microseconds
#      expr       min         lq       mean    median         uq       max neval
#   fun1(v)   139.543   178.5015   283.7498   218.720   288.1555  3730.439   100
#   fun2(v)  6809.344  7465.1110  9326.7799  7912.763 10881.0305 16963.567   100
#  fun2a(v) 10790.471 13786.2335 15912.5338 15089.547 15787.3085 71504.328   100
#   fun3(v)  4132.854  4545.2085  6612.3504  4768.798  7947.0820 63608.519   100
#  fun3a(v)  4147.731  4537.0010  5887.4457  4805.952  7604.4250 13613.517   100
#   fun4(v)  3341.360  3508.2995  3798.4246  3599.220  3797.1200  7565.591   100

fun1可能吗?对你可以使用
,如果你想让人们回答得更快,你应该做一个最小的可重复的例子。要了解更多信息,请查看您到底在哪里阅读?这真是个糟糕的神话。如果可用,您应该使用矢量化函数,但通常编写良好的for循环比apply()快(最重要的是预分配)。当然,
as.list(some.vector)
在这里可以正常工作。也许一个更准确/更具描述性的例子会对你有所帮助。你可以在循环中添加预分配来帮助:
l@MrFlick谢谢——我已经更新为预分配,并在评论中感谢你@理查德斯克林比什么慢?对于非预分配版本?是的,我猜非预分配似乎是OP正在使用的,但是对于
sapply
@RichardScriven进行预分配是一个更公平的比较。您是否在同一个微基准调用中进行了比较(否则单位可能会不同)?它应该慢几个数量级:
funA
fun1 <- function(v) as.list(v)
fun2 <- function(v) {
  l <- vector("list", length(v))  # Thanks to @MrFlick for pre-allocation tip
  for (i in seq_along(v)) {
    l[[i]] <- v[i]
  }
  l
}
fun2a <- function(v) {
  l <- vector("list", length(v))  # Thanks to @MrFlick for pre-allocation tip
  sapply(seq_along(v), function(i) l[[i]] <<- v[i])
  l
}
fun3 <- function(v) lapply(v, identity)
fun3a <- function(v) sapply(v, identity, simplify=FALSE)
fun4 <- function(v) unname(split(v, seq_along(v)))

v <- 1:10000
# Check if all return same thing (see http://stackoverflow.com/a/30850654/3093387)
all(sapply(list(fun2(v), fun2a(v), fun3(v), fun3a(v), fun4(v)), identical, fun1(v)))
# [1] TRUE

library(microbenchmark)
microbenchmark(fun1(v), fun2(v), fun2a(v), fun3(v), fun3a(v), fun4(v))
# Unit: microseconds
#      expr       min         lq       mean    median         uq       max neval
#   fun1(v)   139.543   178.5015   283.7498   218.720   288.1555  3730.439   100
#   fun2(v)  6809.344  7465.1110  9326.7799  7912.763 10881.0305 16963.567   100
#  fun2a(v) 10790.471 13786.2335 15912.5338 15089.547 15787.3085 71504.328   100
#   fun3(v)  4132.854  4545.2085  6612.3504  4768.798  7947.0820 63608.519   100
#  fun3a(v)  4147.731  4537.0010  5887.4457  4805.952  7604.4250 13613.517   100
#   fun4(v)  3341.360  3508.2995  3798.4246  3599.220  3797.1200  7565.591   100