【问题标题】:Faster way of calculating off-diagonal averages in large matrices在大型矩阵中计算非对角线平均值的更快方法
【发布时间】:2012-12-17 13:10:31
【问题描述】:

我需要计算 n × n 矩阵中每个非对角线元素的平均值。下三角和上三角是多余的。这是我目前正在使用的代码:

A <- replicate(500, rnorm(500))
sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)]))

这似乎有效,但不适用于更大的矩阵。我拥有的并不大,大约 2-5000^2,但即使有 1000^2,它所花费的时间也比我想要的要长:

A <- replicate(1000, rnorm(1000)) 
system.time(sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)])))
>   user  system elapsed 
> 26.662   4.846  31.494  

有更聪明的方法吗?

edit 澄清一下,我想要每个对角线独立的平均值,例如为:

 1 2 3 4
 1 2 3 4
 1 2 3 4
 1 2 3 4

我想要:

 mean(c(1,2,3))
 mean(c(1,2))
 mean(1)

【问题讨论】:

    标签: r matrix average


    【解决方案1】:

    您可以通过使用线性寻址直接提取对角线来显着加快速度:superdiag 此处从 A 中提取第 i 个上对角线(i=1 是主对角线)

    superdiag <- function(A,i) {
      n<-nrow(A); 
      len<-n-i+1;
      r <- 1:len; 
      c <- i:n; 
      indices<-(c-1)*n+r; 
      A[indices]
    }
    
    superdiagmeans <- function(A) {
      sapply(2:nrow(A), function(i){mean(superdiag(A,i))})
    }
    

    在 1K 方阵上运行此程序可实现约 800 倍的加速:

    > A <- replicate(1000, rnorm(1000))
    
    > system.time(sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)])))
       user  system elapsed 
     26.464   3.345  29.793 
    
    > system.time(superdiagmeans(A))
       user  system elapsed 
      0.033   0.006   0.039 
    

    这会以与原始顺序相同的顺序为您提供结果。

    【讨论】:

    • 很好地使用索引。我投票支持这个作为公认的答案,因为它说明了索引的强大功能。
    • 谢谢,但你的更清楚,@JorisMeys ;仅当您必须做很多 很多 并且每隔十分之一秒投放广告时,这种方法才值得额外的复杂性。
    • 这很聪明——我必须通过索引生成来了解发生了什么。感谢您的回答
    • 我想说这两个答案都是“酷”并且说明了 R 的一个或另一个功能。为你们俩干杯。
    【解决方案2】:

    您可以使用以下功能:

    diagmean <- function(x){
      id <- row(x) - col(x)
      sol <- tapply(x,id,mean)
      sol[names(sol)!='0']
    }
    

    如果我们在您的矩阵上检查这一点,则速度增益非常可观:

    > system.time(diagmean(A))
       user  system elapsed 
       2.58    0.00    2.58 
    
    > system.time(sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)])))
       user  system elapsed 
      38.93    4.01   42.98 
    

    请注意,此函数同时计算上下三角形。您可以使用以下方法仅计算下三角形:

    diagmean <- function(A){
      id <- row(A) - col(A)
      id[id>=0] <- NA
      tapply(A,id,mean)
    }
    

    这会导致另一个速度增益。请注意,与您的解决方案相比,解决方案将相反:

    > A <- matrix(rep(c(1,2,3,4),4),ncol=4)
    
    > sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)]))
    [1] 2.0 1.5 1.0
    
    > diagmean(A)
     -3  -2  -1 
    1.0 1.5 2.0 
    

    【讨论】:

    • 非常好,我机器上的 1k^2 矩阵不到 1 秒。非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 2012-10-14
    • 2023-04-11
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    相关资源
    最近更新 更多