我想将相同大小的几个矩阵与初始矢量相乘。在下面的示例中,p.state
是m
元素的向量,而tran.mat
是列表,其中每个成员都是m x m
矩阵。
for (i in 1:length(tran.mat)){
p.state <- p.state %*% tran.mat[[i]]
}
上面的代码给出了正确的答案,但是当length(tran.mat)
很大时可能会变慢。我想知道是否有更有效的方法?
下面是一个m=3
和length(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
答案 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 用于每个列的操作。在大矩阵中应快速。我无法在笔记本电脑中测试更大的矩阵。