如何在R中向量化2个循环

时间:2016-02-04 13:09:51

标签: r performance vectorization

我有两个矩阵:

setContentView(R.layout.splash2);

和向量matr1 = [k ; n] matr2 = [n ; m] x 向量length(x) = k包含值x

1 : m

我必须执行以下操作,我使用n = 5 m = 3 k = m * n matr1 <- matrix(sample(seq(0,1, by = 0.1), size = k * n, replace = T), nrow = k, ncol = n ) matr2 <- matrix(sample(seq(0,1, by = 0.1), size = m * n, replace = T), nrow = n, ncol = m) x <- sample(1:m, size = k, replace = T) 循环解决了这个问题。

for

有没有办法以某种方式进行矢量化?

或者可能会使用一些技巧来加快计算速度?

P.S。我考虑过使用基本的并行化,但我想找到更聪明的方法

2 个答案:

答案 0 :(得分:2)

我想了一会儿,但是:

foo <- apply(matr2,2,function(x) rev(cumprod(x+1)))
matr3 <- matr1*t(foo[,x])

- 证明 -

set.seed(100)
n = 5
m = 3
k = m * n

matr1 <- matrix(sample(seq(0,1, by = 0.1), size = k * n, replace = T), nrow = k, ncol = n )
matr2 <- matrix(sample(seq(0,1, by = 0.1), size = m * n, replace = T), nrow = n, ncol = m)
x <- sample(1:m, size = k, replace = T)

foo <- apply(matr2,2,function(x) rev(cumprod(x+1)))
matr3 <- matr1*t(foo[,x])

for( i in 1:k){
  for( j in 1:n){
    matr1[i, 1:(n-j+1)] <- matr1[i, 1:(n-j+1)] + 
      matr1[i, 1:(n-j+1)] * matr2[j , x[i]]
  }
}

all.equal(matr3,matr1)
# TRUE

- 说明 -

所以我花了一段时间才弄清楚这一点,但是这里......假设你的代码并假设i = 1,我们基本上可以写j=1

matr1[1,1:5] <- matr1[1,1:5] + matr1[1,1:5] * matr2[1,3]

所以你把第1行,第1列到第5列,然后用原始数字加上这些数字加上那些数字乘以其他数字(在这种情况下为0.8)。然后,当j=2

matr1[1,1:4] <- matr1[1,1:4] + matr1[1,1:4] * matr2[2,3]

所以现在你只接受n本身的所有列,并以与步骤1相同的方式更新值。最后,应该明确的模式是更新matr1[1,1] { {1}}次,n时间更新matr[1,n]次(仅1次。

我们通过一次性预先计算所有步骤来利用此模式。我们这样做:

matr2[1,3]

这基本上是一个新表,对于每列foo <- apply(matr2,2,function(x) rev(cumprod(x+1))) ,包含一个数字。此数字是您之前的代码遇到单个数字的所有循环的组合。因此,我们现在只需执行1次,而不是matr1[i,]需要5次乘法。

现在我们有:

matr1[1,1]

我们可以将其减少到:

for (i in 1:k) for (j in 1:n) matr1[i,j] <- matr1[i,j] * foo[j,x[i]]

由于for (i in 1:k) matr1[i,] <- matr1[i,] * foo[,x[i]] 每次都为i索引,因此我们只能对其进行矢量化:

1:k

我们已经完成了。

- 基准 -

我重新考虑了我作为证据提供的代码块,但使用了matr <- matr*t(foo[,x]) n=100

您的代码:

m=100

我的代码:

# user  system elapsed 
# 6.85    0.00    6.86 

答案 1 :(得分:0)

而不是双循环,你可以在k-n-grid上apply

suppressOutput <- apply(expand.grid(1:k, 1:n), 1, function(y){
    matr1[y[1], 1:(n-y[2]+1)] <<- matr1[y[1], 1:(n-y[2]+1)] + matr1[y[1], 1:(n-y[2]+1)] * matr2[y[2] , x[y[1]]]
})

在我的机器上节省超过50%的计算时间。虽然它不是很漂亮。