因为最近SO有点慢,所以我发布了一个简单的问题。我很感激,如果大鱼留在板凳上为这一个,让新手有机会回应。
有时我们的对象具有大量的大型列表元素(向量)。您如何将此对象“取消”转换为单个向量。证明您的方法比unlist()
更快。
答案 0 :(得分:10)
如果你不需要名字而且你的名单有一个级别,那么如果你能打败
.Internal(unlist(your_list, FALSE, FALSE))
我将在接下来的1年内对您在SO上所做的一切进行投票!
[更新:如果需要非唯一名称并且列表不是递归的,那么这是一个比unlist提高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
[更新2:响应来自Richie Cotton的Nr3挑战。
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
PS:我认为“大鱼”是比你更有声望的人。所以我在这里很小:)。
答案 1 :(得分:2)
非unlist()
解决方案必须非常快才能击败unlist()
不是吗?在这里,使用长度为100,000的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
在我的工作区中使用bigList2
和foo
,R正在使用~9Gb的可用内存。关键是use.names = FALSE
。没有它unlist()
非常缓慢。究竟有多缓慢我还在等待......
我们可以通过设置recursive = FALSE
来加快速度,然后我们实际上与VitoshKa的回答(两个有代表性的时间)相同:
> system.time(foo <- unlist(bigList2, recursive = FALSE, use.names = FALSE))
user system elapsed
1.379 0.001 1.416
> system.time(foo <- .Internal(unlist(bigList2, FALSE, FALSE)))
user system elapsed
1.335 0.000 1.344
...最后use.names = TRUE
版本已完成......:
> system.time(foo <- unlist(bigList2, use = TRUE))
user system elapsed
2307.839 10.978 2335.815
它消耗了我所有系统的16Gb内存,所以我放弃了......
答案 2 :(得分:2)
c()
具有逻辑参数recursive
,当设置为TRUE
时,该参数将递归地取消列出向量(默认值为FALSE
)。
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
答案 3 :(得分:0)
作为一种中等大小的鱼,我正在尝试第一次尝试解决方案,为小鱼提供基准。它比unlist慢约3倍。
我正在使用较小版本的ucfagls
测试列表。 (因为它更适合记忆。)
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
小鱼的挑战:
你可以扩展它来处理除数字以外的其他类型吗?
你能用它来处理递归(嵌套列表)吗?
你能加快速度吗?
我会支持任何积分少于我的人,他的答案会遇到一个或多个这些小挑战。