List 挑战:优化未上市[简单]

List 挑战:优化未上市[简单],list,optimization,r,vector,List,Optimization,R,Vector,因为SO最近有点慢,所以我发布了一个简单的问题。如果大鱼们能在这场比赛中坐在板凳上,给新秀一个回应的机会,我将不胜感激 有时,我们的对象有大量的大型列表元素(向量)。如何将此对象“取消列表”到单个向量中。证明您的方法比unlist()更快非unlist()解决方案必须非常快才能击败unlist(),不是吗?在这里,不到两秒钟就可以取消列出每个长度为100000的2000个数字向量的列表 > bigList2 <- as.list(data.frame(matrix(rep(rnorm

因为SO最近有点慢,所以我发布了一个简单的问题。如果大鱼们能在这场比赛中坐在板凳上,给新秀一个回应的机会,我将不胜感激

有时,我们的对象有大量的大型列表元素(向量)。如何将此对象“取消列表”到单个向量中。证明您的方法比
unlist()
更快非
unlist()
解决方案必须非常快才能击败
unlist()
,不是吗?在这里,不到两秒钟就可以取消列出每个长度为100000的2000个数字向量的列表

> bigList2 <- as.list(data.frame(matrix(rep(rnorm(1000000), times = 200), 
+                                       ncol = 2000)))
> print(object.size(bigList2), units = "Gb")
1.5 Gb
> system.time(foo <- unlist(bigList2, use.names = FALSE))
   user  system elapsed 
  1.897   0.000   2.019
。。。最后,
use.names=TRUE
版本完成了…:

> system.time(foo <- unlist(bigList2, use = TRUE))
    user   system  elapsed 
2307.839   10.978 2335.815

>system.time(foo如果你不需要名字,而且你的列表只有一级深,那么如果你能击败

.Internal(unlist(your_list, FALSE, FALSE))
在接下来的一年里,我会投票支持你所做的一切

[更新:如果需要非唯一的名称,并且列表不是递归的,那么这里有一个版本,它比未列出的名称改进了100倍

 myunlist <- function(l){
    names <- names(l)
    vec <- unlist(l, F, F)
    reps <- unlist(lapply(l, length), F, F)
    names(vec) <- rep(names, reps)
    vec
    }

 myunlist(list(a=1:3, b=2))
 a a a b 
 1 2 3 2 

 > tl <- list(a = 1:20000, b = 1:5000, c = 2:30)
 > system.time(for(i in 1:200) unlist(tl))
 user  system elapsed 
 22.97    0.00   23.00 

 > system.time(for(i in 1:200) myunlist(tl))
 user  system elapsed 
 0.2     0.0     0.2 

 > system.time(for(i in 1:200) unlist(tl, F, F))
 user  system elapsed 
 0.02    0.00    0.02 

myunlist作为一条中等大小的鱼,我首先尝试了一种解决方案,它为小鱼提供了一个基准。它比unlist慢大约3倍

我使用的是
ucfagls
测试列表的较小版本(因为它更适合内存)

bigList3
c()
具有逻辑参数
recursive
,当设置为
TRUE
(默认值显然是
FALSE
)时,该参数将递归取消列出向量


l这里的每个人都是一条“大鱼”;)。你正在冒着得不到任何答案的风险。有多大?我们说的是鲑鱼、马林鱼还是鲸鲨?什么是“数量荒谬的大列表元素”的意思?长度1000000或更长的向量?有多少列表元素是“荒谬”的数量?必须保留向量的名称?如果是,则必须是唯一的?列表是递归的?默认的非列表可以实现所有这些。假设有几个10000个列表元素,但我会让想象力尽情发挥。一般来说,元素的数量应该足够大,以显示速度性能的任何差异,但在内存限制内。名称可以转储d、 让我们假设list有+1,这可能不重要,但在我的测试中,您的版本比@ucfagls快一点。然而,最大的加速是从use.names=F中获得的。我从Roman的问题中了解到,他的愿望是替换内置的“unlist”就我而言,这是不可能的,当名字不需要的时候。这是一个不能拒绝的提议!如果我一天写6个项目,我可能会有机会抓住德克。FWWW,我认为大的鱼有1000个点。在我的系统中没有选择。(bigList2,recursive=FALSE,use.names=FALSE)
.Internal(unlist(bigList2,FALSE,FALSE)
unlist()中的开销
在调用
.Internal
之前,调用可以忽略不计。除非我真的非常确定我有正确的对象,否则我会尽量远离
.Internal
,以防万一,因为如果出现错误或提供了函数不期望的内容,您可能会使R崩溃。@ucfagis,这对于大向量和小迭代来说是正确的。但是,如果您的列表只包含小向量,并且您运行了长时间的模拟,则.Internal的改进可能会达到两倍!!!中等大小?据您介绍,在过去30天内,您是第10位回答者,并且一直是第7位;)哇。我还没意识到。耶。无论如何,我的提议仍然有效。改进/击败我的答案->获得升级投票。在我的机器上,你的东西大约慢了5倍。完全重启后,它只慢了3.5倍。我更新了你挑战的答案nr3。等待升级投票:)
 myunlist <- function(l){
    names <- names(l)
    vec <- unlist(l, F, F)
    reps <- unlist(lapply(l, length), F, F)
    names(vec) <- rep(names, reps)
    vec
    }

 myunlist(list(a=1:3, b=2))
 a a a b 
 1 2 3 2 

 > tl <- list(a = 1:20000, b = 1:5000, c = 2:30)
 > system.time(for(i in 1:200) unlist(tl))
 user  system elapsed 
 22.97    0.00   23.00 

 > system.time(for(i in 1:200) myunlist(tl))
 user  system elapsed 
 0.2     0.0     0.2 

 > system.time(for(i in 1:200) unlist(tl, F, F))
 user  system elapsed 
 0.02    0.00    0.02 
bigList3 <- replicate(500, rnorm(1e3), simplify = F)

unlist_vit <- function(l){
    names(l) <- NULL
    do.call(c, l)
    }

library(rbenchmark)

benchmark(unlist = unlist(bigList3, FALSE, FALSE),
          rjc    = unlist_rjc(bigList3),
          vit    = unlist_vit(bigList3),
          order  = "elapsed",
          replications = 100,
          columns = c("test", "relative", "elapsed")
          )

    test  relative elapsed
1 unlist   1.0000    2.06
3    vit   1.4369    2.96
2    rjc   3.5146    7.24
bigList3 <- as.list(data.frame(matrix(rep(rnorm(1e5), times = 200), ncol = 2000)))
unlist_rjc <- function(l)
{
  lengths <- vapply(l, length, FUN.VALUE = numeric(1), USE.NAMES = FALSE)
  total_len <- sum(lengths)
  end_index <- cumsum(lengths)
  start_index <- 1 + c(0, end_index)
  v <- numeric(total_len)
  for(i in seq_along(l))
  {
    v[start_index[i]:end_index[i]] <- l[[i]]
  }
  v
}

t1 <- system.time(for(i in 1:10) unlist(bigList2, FALSE, FALSE))
t2 <- system.time(for(i in 1:10) unlist_rjc(bigList2))
t2["user.self"] / t1["user.self"]  # 3.08
l <- replicate(500, rnorm(1e3), simplify = F)

microbenchmark::microbenchmark(
  unlist = unlist(l, FALSE, FALSE),
  c = c(l, recursive = TRUE, use.names = FALSE)
)

# Unit: milliseconds
# expr      min       lq     mean   median       uq      max neval
# unlist 3.083424 3.121067 4.662491 3.172401 3.985668 27.35040   100
#      c 3.084890 3.133779 4.090520 3.201246 3.920646 33.22832   100