【问题标题】:"Vectorized" matrix multiplication“向量化”矩阵乘法
【发布时间】:2016-02-10 05:55:48
【问题描述】:

假设我有两个矩阵 x 和 y,尺寸均为 100x2。我想创建一个列表,这样对于 x 和 y 的每一行,我都有矩阵 t(x) %*% y。例如,通过 for 循环:

x = matrix(rnorm(10), nrow = 5)
y = matrix(rnorm(10), nrow = 5)
myList = list()
for(i in 1:5){
    myList[[i]] = t(x[i, , drop = FALSE]) %*% y[i, ]
}

有没有更有效的方法来做这个计算?我试图弄清楚如何表达这个矩阵乘法但没有运气。我也考虑过 mapply,但似乎我需要将 x 和 y 转换为向量列表而不是矩阵才能使用 mapply,我怀疑这也是正确的方法。

【问题讨论】:

  • 我想应该是Map(function(x,y) matrix(x,ncol=1)%*%y , split(x, row(x)), split(y, row(y)))
  • 您应该预先分配 mylist 对象,这将使您的 for 循环方法明显更快。使用mylist = vector("list", 5)

标签: r matrix matrix-multiplication


【解决方案1】:

Map 的一种方式

Map(function(x,y) matrix(x,ncol=1)%*%y ,
               split(x, row(x)), split(y, row(y))) 

【讨论】:

  • 我无法想象这比循环更快,尽管它可能是更简洁的编码。
  • Map(tcrossprod, split(x, row(x)), split(y, row(y)))
【解决方案2】:

您可以缩短(并可能稍微加快)您的代码

NewList <- list()
for (i in 1:nrow(x)) NewList[[i]] <- outer(x[i,],y[i,])
#> all.equal(NewList,myList)
#[1] TRUE

或者,等价的,

for (i in 1:nrow(x)) NewList[[i]] <- x[i,] %o% y[i,]

【讨论】:

    【解决方案3】:

    似乎 Map 是最好的方法:

    library(rbenchmark)
    
    x = matrix(rnorm(10000), nrow = 5000)
    y = matrix(rnorm(10000), nrow = 5000)
    myList = list()
    
    loopTest = function(){
        for(i in 1:nrow(x)){
            myList[[i]] = t(x[i, , drop = FALSE]) %*% y[i, ]
        }
    }
    
    loopTest2 = function(){
        for(i in 1:nrow(x)){
            myList[[i]] = outer(x[i, ], y[i, ])
        }
    }
    
    mapTest = function(){
        Map(function(x,y) matrix(x,ncol=1)%*%y ,
                       split(x, row(x)), split(y, row(y))) 
    }
    
    mapplyTest = function(){
        mapply(function(x,y) matrix(x,ncol=1)%*%y,
               x = split(x, row(x)), y = split(y, row(y))) 
    }
    
    benchmark(loopTest(), mapTest(), mapplyTest(), replications = 100)
    

    这给了我:

    test        elapsed
    loopTest()   10.471
    loopTest2()  12.225
    mapplyTest()  3.100
    mapTest()     2.252
    

    但是,循环方法确实适用于较小的数据集,比如只有 5 行。

    【讨论】:

    • 感谢您的测试。因此,outer() 似乎并没有提高速度。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 2023-01-11
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多