【问题标题】:Efficient row wise matrix operation in RR中的高效逐行矩阵运算
【发布时间】:2017-10-29 02:22:53
【问题描述】:

我有 2 个矩阵 M1、M2。对于 M1 中的每一行,我想找到 M1 中该行和 M2 中每一行的乘积的最大值。

我已经尝试了以下实现,它产生了我想要的结果。

set.seed(1)
st_time = Sys.time()
M1 = matrix(runif(1000*10), nrow=1000, ncol=10)
M2 = matrix(runif(10000*10), nrow=10000, ncol=10)

score = apply(M1, 1, function(x){
  w = M2 %*% diag(x)
  row_max = apply(w, 1, max)
  return(row_max)
})
required_output = t(score)
Sys.time() - st_time

这在我的机器上需要 16 秒。有更快的实现吗? 谢谢!

【问题讨论】:

    标签: r performance matrix linear-algebra


    【解决方案1】:

    并行运行提供了更轻松的速度。在我的机器上,串行版本是 15 秒,并行版本是不到 4 秒。

    加载包

    # Comes with R
    library(parallel)
    
    # Make the cluster 
    # 8 cores, see detectCores() 
    cl = makeCluster(8)
    

    那么我们需要显式导出M2

    clusterExport(cl, "M2")
    

    正常运行

    score_par = function() {
      parApply(cl, M1, 1, function(x){
        w = M2 %*% diag(x)
        row_max = apply(w, 1, max)
        return(row_max)
      })
    }
    system.time(score_par())
    

    【讨论】:

    • 谢谢!这有帮助。不幸的是,执行此脚本的系统是双核机器。使用 2 个集群只有边际改进。反正有没有“改变数学”来提高速度?我知道 R 中的循环很慢。有没有办法避免使用 2 个嵌套的应用函数?
    【解决方案2】:

    使用for 循环对我来说可以加快速度

    set.seed(1)
    M1 = matrix(runif(1000*10), nrow=1000, ncol=10)
    M2 = matrix(runif(10000*10), nrow=10000, ncol=10)
    
    st_time = Sys.time()
    
    tm = t(M2)
    out = matrix(0, nr=nrow(M1), nc=nrow(M2))
    
    for(i in 1:nrow(M1)){
      out[i, ] = matrixStats::colMaxs(M1[i, ]* tm)
    }
    
    Sys.time() - st_time
    #Time difference of 1.835793 secs # was ~28secs with yours on my laptop
    
    
    all.equal(required_output, out)
    

    【讨论】:

    • 这是要走的路。只需注意几点:您不仅使用了 for 循环,还删除了 diag 瓶颈,并且额外的 apply 调用被矢量化的 matrixStats::colMaxs 调用取代。最后,不用tm = t(M2)matrixStats::colMaxs(M1[i, ]* tm),直接matrixStats::rowMaxs(M1[i, ]* M2)就可以了(直接在M2上)
    • 感谢 cmets @DavidArenburg。但是,我认为(可能是错误的!)M1[i, ]* M2 不会将正确的元素相乘 - 它现在不会将行相乘。例如,M1 = matrix(1:4, nc=2) ; M2 = matrix(1:6, nc=2) ; M1[1, ] * M2 ; M1[1, ] * t(M2)
    • 不确定你的意思out2 = matrix(0, nr=nrow(M1), nc=nrow(M2)) ; for(i in 1:nrow(M1)) out2[i, ] = matrixStats::rowMaxs(M1[i, ]* M2) ; identical(out, out2) 给我TRUE。请注意我使用的是rowMaxs 而不是colMaxs
    • 是的,你可能是对的,我只在一个小的对称矩阵上进行了测试。
    • 哇.. 谢谢!这正是我正在寻找的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    • 2017-12-16
    • 1970-01-01
    • 2011-07-22
    相关资源
    最近更新 更多