我有一个非方矩阵,需要对它的子对角线进行一些计算。我发现最好的方法是将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]}
祝你好运, 阿图尔
答案 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)
}
请记住,您必须考虑矩阵的形成方式。
在这两种情况下,我都遵循相同的逻辑:
这会创建第一个对角线。完成此操作后,您只需添加一个序列,将整个前一个序列移动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)