使用最终产品而不是总和的矩阵产品的快速R方法

时间:2019-06-08 18:51:15

标签: r performance

在R中,可以通过在两个%*%M1: n x p之间使用M2: p x d来执行叉积,这两个矩阵的一维长度相同。

要对M1中的每一行1..n和M2中的第1..d列乘以相对乘积p_M1 x p_M2,然后求和向量相加。

但我希望得到的积不是prod(p_M1 x p_M2)

我可以使用R中的嵌套循环来执行此操作,但是它非常慢并且我的矩阵很大。有没有像%*%一样快的替代方案?

示例:

    set.seed(1)
    a <- matrix(sample((1:100) / 100, 15), ncol = 3)
    b <- matrix(sample((1:100) / 100, 15), ncol = 5)

    # This produces the usual cross-product...
    a %*% b

    # ...which can be done also using loops
    do.call('cbind', lapply(1:5, function(i) {
        sapply(1:5, function(j) {
            sum(a[i,] * b[,j])
        })
    }))

    # But I need to do the product of the paired vectors instead of the sum. I could use a nested loop but it takes hours.
    do.call('cbind', lapply(1:5, function(i) {
        sapply(1:5, function(j) {
            prod(a[i,] * b[,j])
        })
    }))

1 个答案:

答案 0 :(得分:6)

在我的评论之后,这是一个带有matrixStats软件包和outer的方法来执行计算。

# nested loop
mat1 <- 
    do.call('cbind', lapply(1:5, function(i) {
        sapply(1:5, function(j) {
            prod(a[i,] * b[,j])
        })
    }))

# vectorized-ish
library(matrixStats)

mat2 <- outer(colProds(b), rowProds(a))

现在,检查它们在数值上是否相等。

all.equal(mat1, mat2)
[1] TRUE

如果您想要%*%的外观,可以将其更改为

mat2 <- colProds(b) %o% rowProds(a)

如果要避免包装,可以坚持以R为底。这是一种方法。

mat3 <- outer(
               vapply(seq_len(ncol(b)), function(x) prod(b[, x]), numeric(1L)),
               vapply(seq_len(nrow(a)), function(x) prod(a[x, ]), numeric(1L))
              ))

测试这两个的速度,我得到以下结果

library(microbenchmark)

microbenchmark(nest=
                do.call('cbind', lapply(1:5, function(i) {
                        sapply(1:5, function(j) {
                                prod(a[i,] * b[,j])
                               })
                        })),
               vect=outer(colProds(b), rowProds(a)),
               baseVect=outer(
                  vapply(seq_len(ncol(b)), function(x) prod(b[, x]), numeric(1L)),
                  vapply(seq_len(nrow(a)), function(x) prod(a[x, ]), numeric(1L))
               ))

Unit: microseconds
  expr     min       lq      mean  median       uq      max neval
  nest    129.228 133.2225 172.43874 136.833 142.9640 3531.144   100
  vect     23.831  25.8690  28.38306  27.705  29.1815   94.546   100
 baseVect  27.223  29.8970  57.85946  31.471  32.8400 2647.373   100