R

时间:2018-11-13 16:54:18

标签: r loops matrix multiplication markov-chains

我想将相同大小的几个矩阵与初始矢量相乘。在下面的示例中,p.statem元素的向量,而tran.mat是列表,其中每个成员都是m x m矩阵。

for (i in 1:length(tran.mat)){
  p.state <- p.state %*% tran.mat[[i]]
} 

上面的代码给出了正确的答案,但是当length(tran.mat)很大时可能会变慢。我想知道是否有更有效的方法?

下面是一个m=3length(mat)=10可以生成此示例的示例:

p.state <- c(1,0,0)
tran.mat<-lapply(1:10,function(y){apply(matrix(runif(9),3,3),1,function(x){x/sum(x)})})

for (i in 1:length(tran.mat)){
  p.state <- p.state %*% tran.mat[[i]]
}

print(p.state) 

注意:tran.mat不必是当前仅写为一个的列表。

在评论后编辑:

Reduce较小时,

m很有用。但是,当m=6时,循环执行上述两种解决方案。     库(rbenchmark)

p.state1 <- p.state <- c(1,0,0,0,0,0)
tran.mat<-lapply(1:10000,function(y){t(apply(matrix(runif(36),6,6),1,function(x){x/sum(x)}))})

tst<-do.call(c, list(list(p.state), tran.mat))

benchmark(
  'loop' = {
    for (i in 1:length(tran.mat)){
      p.state <- p.state %*% tran.mat[[i]]
    }
  },
  'reduce' = {
    p.state1 %*% Reduce('%*%', tran.mat)
   },
  'reorder' = {
    Reduce(`%*%`,tran.mat,p.state1)
  }

这导致

        test replications elapsed relative user.self sys.self user.child     sys.child
   1    loop          100    0.87    1.000      0.87        0         NA        NA
   2  reduce          100    1.41    1.621      1.39        0         NA        NA
   3 reorder          100    1.00    1.149      1.00        0         NA        NA

3 个答案:

答案 0 :(得分:2)

一种更快的方法是使用Reduce()对矩阵列表进行顺序矩阵乘法。

那样,您可以获得大约4倍的加速。下面是一个经过测试的代码示例,列表中有1000个元素,而不是10个,可以更轻松地看到性能提高。

代码

library(rbenchmark)

p.state <- c(1,0,0)
tran.mat<-lapply(1:1000,function(y){apply(matrix(runif(9),3,3),1,function(x){x/sum(x)})})

benchmark(
  'loop' = {
    for (i in 1:length(tran.mat)){
      p.state <- p.state %*% tran.mat[[i]]
    }
  },
  'reduce' = {
    p.state %*% Reduce('%*%', tran.mat)
  }
)

输出

    test replications elapsed relative user.self sys.self user.child sys.child
1   loop          100    0.23    3.833      0.23        0         NA        NA
2 reduce          100    0.06    1.000      0.07        0         NA        NA

您可以看到reduce方法快约3.8倍。

答案 1 :(得分:1)

我不确定这会更快,但会更短:

prod <- Reduce("%*%", L)

all.equal(prod, L[[1]] %*% L[[2]] %*% L[[3]] %*% L[[4]])
## [1] TRUE

注意

我们使用了以下测试输入:

m <- matrix(1:9, 3)
L <- list(m^0, m, m^2, m^3)

答案 2 :(得分:1)

我将使用 Rfast 中的函数来减少乘法的执行时间。不幸的是,for loop的时间无法减少。

名为Rfast::eachcol.apply的函数对于您的目的是一个很好的解决方案。您的乘法也是函数crossprod,但对于我们的目的而言它很慢。

以下是一些辅助功能:

mult.list<-function(x,y){
    for (xm in x){
        y <- y %*% xm
    }
    y
}

mult.list2<-function(x,y){
    for (xm in x){
        y <- Rfast::eachcol.apply(xm,y,oper="*",apply="sum")
    }
    y
}

这里是一个例子:

x<-list()
y<-rnomr(1000)
for(i in 1:100){
    x[[i]]<-Rfast::matrnorm(1000,1000)
}


microbenchmark::microbenchmark(R=a<-mult.list(x,y),Rfast=b<-mult.list2(x,y),times = 10)
 Unit: milliseconds
     expr        min         lq        mean     median         uq        max neval
        R 410.067525 532.176979 633.3700627 649.155826 699.721086 916.542414    10
    Rfast 239.987159 251.266488 352.1951486 276.382339 458.089342 741.340268    10

all.equal(as.numeric(a),as.numeric(b))
[1] TRUE

参数 oper 用于每个元素的操作,而 apply 用于每个列的操作。在大矩阵中应快速。我无法在笔记本电脑中测试更大的矩阵。