首页 > 解决方案 > 如何为嵌套矩阵匹配和 colSums 加速 R 中的 for 循环

问题描述

我有一个明显简单的问题,我需要比我开发的更快的 R 实现

我为此示例初始化随机种子和维度:

set.seed(1)
d1<-400
d2<-20000
d3<-50

我有一个矩阵 X,尺寸为d1 x d2

X<-as.data.frame(matrix(rnorm(d1*d2),nrow=d1,ncol=d2))
rownames(X)<-paste0("row",1:nrow(X))
colnames(X)<-paste0("col",1:ncol(X))

以及具有d1行索引的向量 u:

u<-sample(rownames(X),nrow(X),replace=TRUE)

我还有一个矩阵 C 与命名行和维度d3 x d2

C<-matrix(rnorm(d3*d2),nrow=d3,ncol=d2)
rownames(C)<-sample(rownames(X),nrow(C),replace=FALSE)

现在,通过以下非常慢的循环,我用匹配的 X 行的总和填充矩阵 C:

system.time(
    for(i in 1:nrow(C)){
        indexes<-which(u==rownames(C)[i])
        C[i,] <- colSums(X[indexes,])
    }
)

此操作在我的 PC 上大约需要 11.5 秒,但我确信可以通过避免 for 循环来加快速度。有任何想法吗?非常感谢!

标签: rperformancefor-loop

解决方案


您可以尝试使用sapplyfor 循环。

system.time(
  C2 <- `dimnames<-`(t(sapply(match(rownames(C), u), function(x) 
    colSums(X[x, ]))), list(rownames(C), NULL))
)
#  user  system elapsed 
# 20.06    0.03   20.14 

stopifnot(all.equal(C, C2))

相比

system.time(
  for(i in 1:nrow(C)){
    indexes <- which(u == rownames(C)[i])
    C[i, ] <- colSums(X[indexes, ])
  }
)
#  user  system elapsed 
# 20.76    0.69   28.30  

然而,目前它只是一个单一的测量值。

更新

好像跑的了点……

Unit: seconds
    expr      min       lq     mean   median       uq      max neval cld
 forloop 20.44852 20.57730 21.67771 20.74106 21.01723 29.63220    10   a
  sapply 19.86707 20.17126 21.34529 20.50283 20.81254 29.73764    10   a

更新 2

但是你可以用parallel::parSapply.

system.time({
  library(parallel)
  cl <- makeCluster(detectCores() - 1)
  clusterExport(cl, c("C", "u", "X"))
  C3 <- parSapply(cl, match(rownames(C), u), function(x) colSums(X[x, ]))
  stopCluster(cl)
  C3 <- `dimnames<-`(t(C3), list(rownames(C), NULL))
})
# user  system elapsed 
# 0.81    3.16    9.82

stopifnot(all.equal(C, C3))

现在,我的机器和你的机器一样快,有了for-loop :)


推荐阅读