performance - R 中的向量化矩阵运算

标签 performance r matrix vectorization

我有一个 R x C 矩阵,填充到第 k 行,并在该行下方为空。我需要做的是填充剩余的行。为了做到这一点,我有一个函数,它接受 2 个完整行作为参数,处理这些行并输出 2 个新行(这些输出将填充矩阵的空行,批量为 2)。我有一个固定矩阵,其中包含要处理的所有“对”行,但我的 for 循环对性能没有帮助:

# the processRows function:
processRows = function(r1, r2)
{
  # just change a little bit the two rows and return it in a compact way    
  nr1 = r1 * 0.1
  nr2 = -r2 * 0.1

  matrix (c(nr1, nr2), ncol = 2)
 }

# M is the matrix
# nrow(M) and k are even, so nLeft is even

M = matrix(1:48, ncol = 3)
# half to fill (can be more or less, but k is always even)
k = nrow(M)/2

# simulate empty rows to be filled
M[-(1:k), ] = 0

cat('before fill')
print(M)

# number of empty rows to fill
nLeft  = nrow(M) - k
nextRow = k + 1

# each row in idxList represents a 'pair' of rows to be processed 
# any pairwise combination of non-empty rows could happen
# make it reproducible

set.seed(1)
idxList = matrix (sample(1:k, k), ncol = 2, byrow = TRUE)

for ( i in 1 : (nLeft / 2))
{
   row1 = M[idxList[i, 1],]
   row2 = M[idxList[i, 2],]

   # the two columns in 'results' will become 2 rows in M
   results = processRows(row1, row2)

   # fill the matrix
   M[nextRow, ] = results[, 1]
   nextRow = nextRow + 1
   M[nextRow, ] = results[, 2]
   nextRow = nextRow + 1
 }

 cat('after fill')
 print(M)

最佳答案

好的,首先这是您的代码。我们运行这个,以便我们拥有“真实”矩阵的副本,我们希望更快地重现。

#### Original Code (aka Gold Standard) ####
M = matrix(1:48, ncol = 3)
k = nrow(M)/2
M[-(1:k), ] = 0
nLeft  = nrow(M) - k
nextRow = k + 1
idxList = matrix(1:k, ncol = 2)
for ( i in 1 : (nLeft / 2))
{
    row1 = M[idxList[i, 1],]
    row2 = M[idxList[i, 2],]
    results = matrix(c(2*row1, 3*row2), ncol = 2)
    M[nextRow, ] = results[, 1]
    nextRow = nextRow + 1
    M[nextRow, ] = results[, 2]
    nextRow = nextRow + 1
}

现在这是矢量化代码。基本思想是,如果您正在处理 4 行。不要一次将它们作为向量传递一个,而是一次传递。即:

(1:3) * 2
(1:3) * 2
(1:3) * 2
(1:3) * 2

与以下内容相同(但速度较慢):

c(1:3, 1:3, 1:3, 1:3) * 2

因此,首先,我们将使用相同的设置代码,然后创建要作为两个长向量处理的行(其中所有 4 个原始行都串在一起,如上面的简单示例所示)。然后,我们获取这些结果,并将它们转换为具有适当维度的矩阵。最后一个技巧是只需两步即可将结果分配回来。您可以一次分配给矩阵的多行,因此我们使用 seq() 来获取奇数和偶数,从而分别分配结果的第一列和第二列。

#### Vectorized Code (testing) ####
M2 = matrix(1:48, ncol = 3)
k2 = nrow(M2)/2
M2[-(1:k2), ] = 0
nLeft2  = nrow(M2) - k2
nextRow2 = k2 + 1
idxList2 = matrix(1:k2, ncol = 2)

## create two long vectors of all rows to be processed
row12 <- as.vector(t(M2[idxList2[, 1],]))
row22 <- as.vector(t(M2[idxList2[, 2],]))

## get all results
results2 = matrix(c(2*row12, 3*row22), ncol = 2)

## add results back
M2[seq(nextRow2, nextRow2 + nLeft2-1, by = 2), ] <- matrix(results2[,1], nLeft2/2, byrow=TRUE)
M2[seq(nextRow2+1, nextRow2 + nLeft2, by = 2), ] <- matrix(results2[,2], nLeft2/2, byrow=TRUE)

## check that vectorized code matches your examples
all.equal(M, M2)

在我的机器上给出:

> all.equal(M, M2)
[1] TRUE

关于performance - R 中的向量化矩阵运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11388201/

相关文章:

c - 相关变量和操作的分组?

MySQL - 查询以查找连续范围的未使用值

r - 从具有样条和滞后预测变量的 GAM 模型中提取预测

R rollapply 从下到上?

java - 可以从一个文件创建两个不同大小的数组/矩阵吗?

r - 循环遍历矩阵的对角线+1

c++ - 将 C++ 变量声明为 const 是有助于还是损害性能?

c# - 在 sqlConnections 上使用 'Using' 对性能有何影响

windows - 从 R 写入 UTF-8 文件

Java Chess,如何更新棋盘?