列表列表中元素替换的慢循环

时间:2015-09-10 04:18:56

标签: r list for-loop

我写了一个循环来有条件地替换列表列表中的元素。虽然对R来说还是比较新的,但我确信我并没有尽可能有效地解决这个问题。以下循环对我的实际数据运行非常缓慢(一小时左右)。我在下面列出了一个最小的工作示例,它完全复制了我的数据结构。

A <- matrix(c(0, 1, 1, 2, 0, 0, 1, 0, 1, 2, 0, 0), nrow = 2, ncol = 6, byrow = TRUE)
B <- matrix(c(1, 1, 1, 2, 0, 1, 1, 0, 1, 2, 0, 0), nrow = 2, ncol = 6, byrow = TRUE)
C <- matrix(c(1, 0, 0, 1, 0, 1), nrow = 1, ncol = 6, byrow = TRUE)
D <- matrix(c(0, 0, 0, 1, 1, 1), nrow = 1, ncol = 6, byrow = TRUE)
mList <-list(list(A, B))
dList <- list(list(C, D))

如果mList2的第n项的元素j等于{{1},则循环的目标是将0的第n项的第j列中的所有单元格替换为dList }。

0

这是使用mList # [[1]] # [[1]][[1]] # [,1] [,2] [,3] [,4] [,5] [,6] # [1,] 0 1 1 2 0 0 # [2,] 1 0 1 2 0 0 # # [[1]][[2]] # [,1] [,2] [,3] [,4] [,5] [,6] # [1,] 1 1 1 2 0 1 # [2,] 1 0 1 2 0 0 dList # [[1]] # [[1]][[1]] # [,1] [,2] [,3] [,4] [,5] [,6] # [1,] 1 0 0 1 0 1 # # [[1]][[2]] # [,1] [,2] [,3] [,4] [,5] [,6] # [1,] 0 0 0 1 1 1 函数集的另一个未实现收益的实例吗?有没有更好的方法来做这个不涉及使用四个指数?

apply

导致:

for(i in 1:length(dList)) {
    for(j in 1:length(dList[[i]])) {
        for(k in 1:length(dList[[i]][[j]])) {
            for(m in 1:nrow(mList[[i]][[j]])) {
                mList[[i]][[j]][m, k] <- 
                    ifelse(
                        dList[[i]][[j]][k] == 1, 
                        mList[[i]][[j]][m, k], 
                        0
                    )
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我会使用嵌套的lapply循环输入列表的嵌套结构,使用单个向量化操作重新计算mList中的相关条目,而不是通过列和行循环:< / p>

lapply(seq_along(dList), function(i) {
  lapply(seq_along(dList[[i]]), function(j) {
    t(t(mList[[i]][[j]]) * as.vector(dList[[i]][[j]] != 0))
  })
})
# [[1]]
# [[1]][[1]]
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    0    0    0    2    0    0
# [2,]    1    0    0    2    0    0
# 
# [[1]][[2]]
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    0    0    0    2    0    1
# [2,]    0    0    0    2    0    0

这里是相同结构列表的基准,在mList中有10 x 10000个矩阵。我已经对您提供的解决方案,@ thelatemail的解决方案以及我的解决方案进行了基准测试:

set.seed(144)
A <- matrix(sample(0:2, 100000, replace=TRUE), nrow=10)
B <- matrix(sample(0:2, 100000, replace=TRUE), nrow=10)
C <- matrix(sample(0:1, 10000, replace=TRUE), nrow=1)
D <- matrix(sample(0:1, 10000, replace=TRUE), nrow=1)
mList <-list(list(A, B))
dList <- list(list(C, D))

OP <- function(mList, dList) {
  for(i in 1:length(dList)) {
    for(j in 1:length(dList[[i]])) {
        for(k in 1:ncol(dList[[i]][[j]])) {
            for(m in 1:nrow(mList[[i]][[j]])) {
                mList[[i]][[j]][m, k] <- 
                    ifelse(
                        dList[[i]][[j]][k] == 1, 
                        mList[[i]][[j]][m, k], 
                        0
                    )
            }
        }
    }
  }
  mList
}
josilber <- function(mList, dList) {
  lapply(seq_along(dList), function(i) {
    lapply(seq_along(dList[[i]]), function(j) {
      t(t(mList[[i]][[j]]) * as.vector(dList[[i]][[j]] != 0))
    })
  })
}
thelatemail <- function(mList, dList) {
  Map(
    function(L,s) Map(function(sL,ss) {sL[,ss] <- 0; sL}, L, s),
    mList,
    lapply(dList, function(x) lapply(x, function(y) y==0) )
  )
}

library(microbenchmark)
microbenchmark(OP(mList, dList), josilber(mList, dList), thelatemail(mList, dList), times=10)
# Unit: milliseconds
#                       expr          min           lq         mean       median           uq          max neval
#           OP(mList, dList) 12252.468288 13318.745019 13478.116388 13486.732412 13840.106332 14259.053497    10
#     josilber(mList, dList)     2.299442     2.401806     2.561809     2.480822     2.552620     3.511609    10
#  thelatemail(mList, dList)     4.259594     4.438562     4.683855     4.612297     5.002605     5.122605    10

两种解决方案的运行速度都要快1000倍,这主要是因为它们没有紧密地循环通过矩阵,而是以矢量化的方式执行操作。