计算矩阵元素的最快方法

时间:2013-07-04 09:59:28

标签: r optimization matrix

我正在研究一些需要我反复计算大方阵的元素的东西。该过程涉及读取存储在另一个矩阵中的数据,然后计算矩阵元素。目前我正在使用双 for 循环来执行此操作。

library(matrixcalc)

data <- matrix(nrow=3,ncol=1000)

for(x in 1:ncol(data)){
   for(y in 1:ncol(data)){
       matrix[x,y]=exp(-entrywise.norm(data[,x]-data[,y],2))
   }
}

问题在于,由于我的矩阵非常大,因此非常慢。这个程序最快的替代方法是什么?

4 个答案:

答案 0 :(得分:3)

短而快:

mat <- exp(-as.matrix(dist(t(data))))

我还建议使用fields::rdist函数作为计算欧氏距离矩阵的dist的更快替代方法,因此如果加载包不是问题,请考虑:

library(fields)
mat <- exp(-rdist(t(data)))

为了让您了解提速:

data <- matrix(runif(3000), nrow=3, ncol=1000)

OP <- function(data) {
  require(matrixcalc)
  mat <- matrix(0, ncol(data), ncol(data))
  for(x in 1:ncol(data)){
    for(y in 1:ncol(data)){
      mat[x,y]=exp(-entrywise.norm(data[,x]-data[,y],2))
    }
  }
  mat
}

flodel1 <- function(data) exp(-as.matrix(dist(t(data))))
flodel2 <- function(data) {
  require(fields)
  exp(-rdist(t(data)))
}

system.time(res1 <- OP(data))
#   user  system elapsed 
# 22.708   2.080  24.602 
system.time(res2 <- flodel1(data))
#   user  system elapsed 
#  0.112   0.025   0.136 
system.time(res3 <- flodel2(data))
#   user  system elapsed 
#  0.048   0.000   0.049 

(请注意,在OPflodel2的情况下,这些运行时不包括在测试之前加载的软件包的加载。)

答案 1 :(得分:2)

这应该快得多:

nc <- ncol(data)

mat <- diag(nc)

for(x in 2:nc){
   for(y in 1:x){
       mat[x, y] <- exp(-(sum((data[ , x] - data[ , y])^2) ^ .5))
   }
}

mat[upper.tri(mat)] <- t(mat)[upper.tri(mat)]

答案 2 :(得分:1)

R语言使用 column-major-order 数组。更改for循环顺序可以提高性能。因为这样,您可以以更连续的形状访问内存,从而实现cpu-cache优势。

 for(y in 1:dim) //outer is y now
 {
    for(x in 1:dim) //now x is count inside
    {
        matrix[x,y]=exp(-entrywise.norm(data[,x]-data[,y],2))
    }
 }

你的&#34;矩阵&#34;是2D阵列吗?

如果你需要更高的速度,你可以展开一些内部循环,以减少cpu的分支负载和更好的缓存/预取。

 for(y in 1:dim) 
 {
    for(x in 1:(dim/8)) //lets imagine dimension is a multiple of 8
    {
        matrix[x,y]=exp(-entrywise.norm(data[,x]-data[,y],2))
        matrix[x+1,y]=exp(-entrywise.norm(data[,x+1]-data[,y],2))
        matrix[x+2,y]=exp(-entrywise.norm(data[,x+2]-data[,y],2))
        matrix[x+3,y]=exp(-entrywise.norm(data[,x+3]-data[,y],2))
        matrix[x+4,y]=exp(-entrywise.norm(data[,x+4]-data[,y],2))
        matrix[x+5,y]=exp(-entrywise.norm(data[,x+5]-data[,y],2))
        matrix[x+6,y]=exp(-entrywise.norm(data[,x+6]-data[,y],2))
        matrix[x+7,y]=exp(-entrywise.norm(data[,x+7]-data[,y],2))
    }
 }

答案 3 :(得分:1)

您可以使用colSums代替内循环。根据@Sven Hohenstein的回答:

nc <- ncol(data)

mat <- diag(nc)

for(x in 2:nc){
  mat[x, 1:x] <- exp(-(colSums((data[ , 1:x] - data[ ,x])^2) ^ .5))
}

mat[upper.tri(mat)] <- t(mat)[upper.tri(mat)]