从矩阵中获取所有对角线向量

25

我正在尝试找出如何获取矩阵的所有对角线。例如,假设我有以下矩阵:

A <- matrix(1:16,4)

使用diag(A)函数将返回:

[1]  1  6 11 16
除了主对角线,我希望得到所有在它上面和下面的对角线的列表。

除了主对角线,我希望得到所有在它上面和下面的对角线的列表。

5 10 15
2  7 12
9 14
3  8
4
13

我找到了以下链接https://dev59.com/NGcs5IYBdhLWcg3wMxJF#13049722,它给出了主对角线上方和下方的直接对角线,但是我似乎无法想出如何扩展代码以获取任意大小矩阵的其余对角线。我尝试了两个嵌套的for循环,因为看起来某种矩阵下标的递增会产生我要寻找的结果。我在for循环中尝试使用ncol(A),nrow(A),但是似乎无法找到正确的组合。此外,我知道在R中,for循环通常不被认可。

给出的代码是:

diag(A[-4,-1])
diag(A[-1,-4])

返回了两个对角线,上下对角线都返回。

当然,这是一个方阵,并不是我想要执行此操作的所有矩阵都是方阵。如果必要的话,在非方形区域填充NA将是可接受的。我需要的答案可能在页面上的其他答案中,但原始问题涉及平均数、总和等,这增加了一层超出我所尝试做的事情的复杂性。我感觉解决这个问题会非常简单,但它没有发生在我脑海中。我也很惊讶我找不到任何关于这个问题的问答,它似乎是一个足够常见的问题。也许我不知道这个问题的正确术语。


1
你为什么不看看@GavinSimpson的答案呢? - A5C1D2H2I1M1N2O1R2T1
我也读了那个答案,所以我理解解决方案涉及基于行和列数量的递增,但如何将其打包成一个函数,以返回一个矩阵中的所有对角线,这正是我在这里遇到的难题。我一遍又一遍地阅读了所有的答案。 - Beaker
5
旁注:for循环并不被视为不好的东西。我认为这是一个谬论。在源代码中到处都有它们。只需要像其他函数一样适当地使用它们即可 :-) - Rich Scriven
3
“@RichardScriven - for循环受到不赞成并非无中生有。但是,所有这些负面看法对代码速度产生影响纯属传说。” - thelatemail
3个回答

64
A <- matrix(1:16, 4)

# create an indicator for all diagonals in the matrix
d <- row(A) - col(A)

# use split to group on these values
split(A, d)

# 
# $`-3`
# [1] 13
# 
# $`-2`
# [1]  9 14
# 
# $`-1`
# [1]  5 10 15
# 
# $`0`
# [1]  1  6 11 16
# 
# $`1`
# [1]  2  7 12
# 
# $`2`
# [1] 3 8
# 
# $`3`
# [1] 4

9
可以对角线反转转成 row(A) + col(A) - user20650

6

由于你正在处理方阵,因此将Gavin的答案转换为一个小函数应该非常容易,该函数首先计算应使用作为偏移值的范围。下面是这样的一个函数:

AllDiags <- function(inmat, sorted = TRUE) {
  Range <- ncol(inmat) - 1
  Range <- -Range:Range
  if (isTRUE(sorted)) Range <- Range[order(abs(Range))]
  lapply(Range, function(x) {
    inmat[row(inmat) == (col(inmat) - x)]
  })
}

以下是您样本矩阵"A"的输出结果。

AllDiags(A)
# [[1]]
# [1]  1  6 11 16
# 
# [[2]]
# [1]  2  7 12
# 
# [[3]]
# [1]  5 10 15
# 
# [[4]]
# [1] 3 8
# 
# [[5]]
# [1]  9 14
# 
# [[6]]
# [1] 4
# 
# [[7]]
# [1] 13

3

基于一个观察,你可以通过缩小和扩大矩阵来获得所有的对角线。首先考虑第N行第1列(获取该对角线),然后考虑第(N-1)行: 第(1:2)列。获取该对角线,以此类推。

N <- ncol(A)
rows <- cbind(c(N:1, rep(1,N-1)), c(rep(N,N), (N-1):1)) # row indeces
cols <- apply(rows, 2, rev)                             # col indeces

diagMatSubset <- function(mat, i1, i2, j1, j2) diag(mat[i1:i2, j1:j2, drop=FALSE])

Map(diagMatSubset, list(A), rows[,1], rows[,2], cols[,1], cols[,2])

[[1]]
[1] 4

[[2]]
[1] 3 8

[[3]]
[1]  2  7 12

[[4]]
[1]  1  6 11 16

[[5]]
[1]  5 10 15

[[6]]
[1]  9 14

[[7]]
[1] 13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接