将矩阵子对角转换为列r的高效算法

时间:2017-03-22 12:07:13

标签: r algorithm matrix transformation

我有一个非方矩阵,需要对它的子对角线进行一些计算。我发现最好的方法是将subdiagonals转换为列/行并使用像cumprod这样的函数。现在我使用for循环和exdiag定义如下:

select
exe2.arr[1] as a,
exe2.arr[2] as b,
exe2.arr[3] as c,
exe2.arr[4] as d
from
(
    select
    exe.x,
    string_to_array(exe.x,';') as arr
    from
    (
        select
        '150;itema;section;shelf' as x
        union select
        '120;itemb;shelf;box' as x
        union select
        '151;itemf;section;shelf' as x
    ) exe
) exe2

然而,它并不是真正有效率。你知道其他任何算法来实现这种结果。

一个小例子来展示我在做什么:

exdiag <- function(mat, off=0) {mat[row(mat) == col(mat)+off]}

祝你好运, 阿图尔

2 个答案:

答案 0 :(得分:1)

您可以修改diag()函数。

exdiag <- function(mat, off=0) {mat[row(mat) == col(mat)+off]}

exdiag2 <- function(matrix, off){diag(matrix[-1:-off,])}

速度测试:

mat = diag(10, 10000,10000)

off = 4

> system.time(exdiag(mat,4))

  user  system elapsed 
  7.083   2.973  10.054 

> system.time(exdiag2(mat,4))

   user  system elapsed 
  5.370   0.155   5.524 

> system.time(diag(mat))

   user  system elapsed 
  0.002   0.000   0.002

看起来矩阵的子集需要花费大量时间,但它仍然比您的实现表现更好。可能还有很多其他的子集方法,这些方法优于我的解决方案。 :)

答案 1 :(得分:1)

从非正方形矩阵中获取所有可能对角线的最快但迄今为止最神秘的解决方案是将矩阵视为向量,并简单地构造id向量以供选择。最后,如果需要,您可以将其转换回矩阵。

以下功能可以做到:

exdiag <- function(mat){

  NR <- nrow(mat)
  NC <- ncol(mat)
  smalldim <- min(NC,NR)
  if(NC > NR){
    id <- seq_len(NR) + 
      seq.int(0,NR-1)*NR +
      rep(seq.int(1,NC - 1), each = NR)*NR


  } else if(NC < NR){
    id <- seq_len(NC) + 
      seq.int(0,NC-1)*NR +
      rep(seq.int(1,NR - 1), each = NC)

  } else {
    return(diag(mat))
  }
  out <- matrix(mat[id],nrow = smalldim)
  id <- (ncol(out) + 1 - row(out)) - col(out) < 0
  out[id] <- NA
  return(out)
}

请记住,您必须考虑矩阵的形成方式。

在这两种情况下,我都遵循相同的逻辑:

  • 首先构建一个表示沿最小维度的位置的序列
  • 按此顺序添加行长度的0,1,2 ......倍。

这会创建第一个对角线。完成此操作后,您只需添加一个序列,将整个前一个序列移动1(向下或向右),直到到达矩阵的末尾。要向右移动,我需要将此序列乘以行数。

最后,您可以使用这些索引从mat中选择正确的位置,并将所有这些作为矩阵返回。由于此代码的矢量化特性,您必须检查最后的子对角线是否正确。它们包含的元素少于第一个元素,因此您必须用NA替换不属于该子对角线的值。在这里你可以简单地使用索引技巧。

您可以按如下方式使用它:

> diag1 <- exdiag(amatrix)
> diag2 <- exdiag(t(amatrix))
> identical(diag1, diag2)
[1] TRUE

为了得出你的结果

amatrix <- matrix(1:72, ncol = 6)
diag1 <- exdiag(amatrix)
res <- apply(diag1,2,cumprod)
res[is.na(res)] <- 0
t(res)