向量化和并行化列表的分解

vectorizing & parallelizing the disagregation of a list

下面是一些生成 data.frame 列表的代码,然后将该原始列表转换为新列表,其中每个列表元素都是每个数据框的行列表。

例如。
- l1 的长度为 10,每个元素都是一个包含 1000 行的 data.frame
- l2 是长度为 1000 (nrow(l1[[k]])) 的列表,每个元素都是长度为 10 (length(l1)) 的 list,包含来自 [=13] 元素的行向量=]

l1 <- vector("list", length= 10)
set.seed(65L)
for (i in 1:10) {
  l1[[i]] <- data.frame(matrix(rnorm(10000),ncol=10))
}

l2 <- vector(mode="list", length= nrow(l1[[1]]))
for (i in 1:nrow(l1[[1]])) {
  l2[[i]] <- lapply(l1, function(l) return(unlist(l[i,])))
}

Edit 为了阐明 l1l2 的关系,这里是语言无关代码。

for (j in 1:length(l1) {
  for (i in 1:nrow(l1[[1]]) { # where nrow(l1[[1]]) == nrow(l1[[k]]) k= 2,...,10
    l2[[i]][[j]] <- l1[[j]][i,]
  }
}

如何通过矢量化或并行化加快 l2 的创建速度? 我遇到的问题是 parallel::parLapplyLB 拆分列表;但是,我不想拆分列表 l1,我想做的是拆分 l1 的每个元素内的行。一个中间解决方案将通过使用一些 *apply 函数来替换 for 循环来矢量化我当前的方法。这显然也可以扩展到并行解决方案。

如果在可接受的解决方案之前我自己解决了这个问题,我会post在这里回答。

我会完全破坏结构并通过 split 重建第二个列表。这种方法比原来的方法需要更多的内存,但至少对于给定的例子,它要快 10 倍以上:

sgibb <- function(x) {
  ## get the lengths of all data.frames (equal to `sapply(x, ncol)`)
  n <- lengths(x)
  ## destroy the list structure
  y <- unlist(x, use.names = FALSE)
  ## generate row indices (stores the information which row the element in y
  ## belongs to)
  rowIndices <- unlist(lapply(n, rep.int, x=1L:nrow(x[[1L]])))
  ## split y first by rows
  ## and subsequently loop over these lists to split by columns
  lapply(split(y, rowIndices), split, f=rep.int(seq_along(n), n))
}

alex <- function(x) {
  l2 <- vector(mode="list", length= nrow(x[[1]]))
  for (i in 1:nrow(x[[1]])) {
    l2[[i]] <- lapply(x, function(l) return(unlist(l[i,])))
  }
  l2
}

## check.attributes is need because the names differ
all.equal(alex(l1), sgibb(l1), check.attributes=FALSE)

library(rbenchmark)
benchmark(alex(l1), sgibb(l1), order = "relative", replications = 10)
#       test replications elapsed relative user.self sys.self user.child sys.child
#2 sgibb(l1)           10   0.808    1.000     0.808        0          0         0
#1  alex(l1)           10  11.970   14.814    11.972        0          0         0