从列表的列表中提取元素的快速方法

3
大家好, 我正在处理一个包含列表的大型列表。每个子列表都包含n个元素,我想要获取第三个元素,例如:
l = list()
l[[1]] = list(A=runif(1), B=runif(1), C=runif(1))
l[[2]] = list(A=runif(1), B=runif(1), C=runif(1))
l[[3]] = list(A=runif(1), B=runif(1), C=runif(1))

res = sapply(l, function(x) x$C)
res = sapply(l, function(x) x[[3]]) #alternative

但是我的列表包含数千个元素,我需要执行这个操作很多次。那么,有没有更快的方法来执行上面的操作呢?

最好的问候,

Mario

1个回答

7

如果您需要多次执行此操作,那么最好将列表转换为更简单的结构,例如data.table

library(data.table)
DT=rbindlist(l);
res = DT$C
# or if you prefer the 3rd element, not necessarily called 'C' then:
res = DT[[3]] # or DT[,C] which might be faster. Please check @richard-scriven comment

或者,如果您想保留基本的R语言,可以使用rbind函数。

res = do.call(rbind.data.frame, l)$C # or [[3]]

这样做能让事情变得更容易吗?

更新

以下是展示不同解决方案的基准测试结果:

准备工作:

library(data.table)
library(microbenchmark)

# creating a list and filling it with items 
nbr   = 1e5;
l     = vector("list",nbr)
for (i in 1:nbr) {
  l[[i]] = list(A=runif(1), B=runif(1), C=runif(1))
}

# creating data.frame and data.table versions
DT <- rbindlist(l)
DF <- data.frame(rbindlist(l))

基准测试:


# doing the benchmarking
op <- 
  microbenchmark(
    LAPPLY.1 = lapply(l, function(x) x$C),
    LAPPLY.2 = lapply(l, `[`, "C"),
    LAPPLY.3 = lapply(l, `[[`, "C"),

    SAPPLY.1 = sapply(l, function(x) x$C),
    SAPPLY.2 = sapply(l, function(x) x[[3]]),
    SAPPLY.3 = sapply(l, `[[`, 3),
    DT.1     = rbindlist(l)$C,

    DT.2     = DT$C,
    DF.2     = DF$C,
    times    = 100
  )

结果:

op 

## Unit: microseconds
## expr        min     lq   mean median     uq   max neval
## LAPPLY.1 124088 142390 161672 154415 163240 396761  100
## LAPPLY.2 111397 134745 156012 150062 165229 364539  100
## LAPPLY.3  66965  71608  82975  77329  84949 323041  100
## SAPPLY.1 133220 149093 166653 159222 172495 311857  100
## SAPPLY.2 105917 119533 137990 133364 139216 346759  100
## SAPPLY.3  70391  74726  81910  80520  85792 110062  100
## DT.1      46895  48943  49113  49178  49391  51377  100
## DT.2          8     18     37     47     49     58  100
## DF.2          7     13     33     40     42     82  100

(1) 一般而言,最好一开始就使用类似于data.frame或者data.table的表格结构——从中选择列所花费的时间最少。
(2) 如果不可能使用这种结构,最好将列表先转换为data.frame或者data.table,然后进行单次操作提取值。
(3) 有趣的是,在基本的R语言中使用sapply或lapply与优化的[[函数相结合,其处理时间只比使用rbind然后提取列的值多两倍。

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Nikos
1
也许,microbenchmark 应该包括对 rbindlist 的调用吗?这样做是为了考虑到首先 OP 需要改变格式的情况。 - alexis_laz
DT[,C] 可能比 DT$C 更快。不建议在数据表中使用 $ 运算符。或者您可以使用 rbindlist(l)[,C] 来使其更短。 - Rich Scriven
谢谢@richard-scriven。 - Nikos
所以,我进行了基准测试,包括 rbindlist,仍然加速了5-6倍。但是我打算用c/c++编写这些内容,因为我不想使用外部软件包。 - user1309940
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接