遍历矩阵对角线加1的循环

3
我需要循环遍历对角线+1(即对角线右侧的一列),并将该值写入数据框中的一列:
write.csv(data.frame(matrix[1,2], matrix[2,3], matrix[3,4])

如何使用函数来完成这个操作,而不是仅列出值的所有位置?
3个回答

9
一个快速的方法,无需编写程序计算索引,而是使用经常被忽视的row()col()函数。它们分别返回矩阵中每个元素所属的行或列。
对角线是指行索引等于列索引的元素。第一条次对角线是指行索引等于列索引加1的元素,而第一条超对角线则是指行索引等于列索引减1的元素。
以下是一些示例:
m <- matrix(1:25, ncol = 5)
m

> m
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    6   11   16   21
[2,]    2    7   12   17   22
[3,]    3    8   13   18   23
[4,]    4    9   14   19   24
[5,]    5   10   15   20   25

对角线

m[row(m) == col(m)]
diag(m)

> m[row(m) == col(m)]
[1]  1  7 13 19 25
> diag(m) ## just to show this is correct
[1]  1  7 13 19 25

第一条副对角线

m[row(m) == col(m) + 1

> m[row(m) == col(m) + 1]
[1]  2  8 14 20

第一超对角线

m[row(m) == col(m) -1]

> m[row(m) == col(m) -1]
[1]  6 12 18 24

通过增加添加到列索引的值,可以提取高阶超级和次对角线。

创建数据框并写出

本质上您已经拥有了这个,但是

write.csv(data.frame(m[row(m) == col(m) + 1), file = "subdiag.csv")

一个处理次对角线或超对角线的通用函数

diags <- function(m, type = c("sub", "super"), offset = 1) {
  type <- match.arg(type)
  FUN <-
  if(isTRUE(all.equal(type, "sub")))
    `+`
  else
    `-`
  m[row(m) == FUN(col(m), offset)] 
}

我们正在使用以下内容:

> diags(m)
[1]  2  8 14 20
> diags(m, type = "super")
[1]  6 12 18 24
> diags(m, offset = 2)
[1]  3  9 15

点赞了,因为这是我会做的方式,而且它有那个酷炫的match.arg调用,但实际上我认为@mnel的解决方案更好。 - IRTFM
谢谢,您能详细说明一下为什么您认为@mnels的解决方案更好吗? - Gavin Simpson
使用 rowcol 需要构建两个与输入矩阵相同大小的完整逻辑矩阵。而这种方法只需构建两个向量并提取即可。 - IRTFM
好的,我明白你的意思了——两个长度为nrow(m)的向量与两个长度为prod(nrow(m), ncol(m))的向量。因此,就内存效率而言,@mnel的解决方案毫无疑问是更胜一筹的。 - Gavin Simpson
这种方法在灵活性方面胜出。同一个函数可以通过改变参数的符号来选择子对角线或超对角线。 - Matthew Lundberg

7
您可以使用矩阵进行索引。
例如:
m <- matrix(1:25, ncol = 5)

可以使用以下方式访问偏对角线:

offd <- cbind(1:4,2:5)


m[offd]

## [1]  6 12 18 24

您可以创建一个函数来实现这一操作。
offdiag <- function(m, offset){
  i <- seq_len(nrow(m)-offset)
  j <- i + offset
  m[cbind(i,j)]

}


offdiag(m, 1)
## [1]  6 12 18 24
offdiag(m, 2)
[1] 11 17 23
offdiag(m, 3)
## [1] 16 22
offdiag(m, 4)
## [1] 21

1
这可能更快,并且在处理稀疏矩阵时应该效果良好。我认为你的代码更清晰,但这是针对第一个参数为矩阵的情况下 diag 中的代码:y <- c(x)[1 + 0L:(m - 1L) * (dim(x)[1L] + 1)] - IRTFM

6

取子矩阵,然后取其对角线。

使用 mnel 的 m

diag(m[, -1])
[1]  6 12 18 24

作为一个带有可变偏移量的函数(但在这种形式下,它并不比mnel的解决方案更简洁):
offdiag <- function(m, offset) {
  s <- seq(offset)
  diag(m[,-s, drop=FALSE])
}

offdiag(m, 1)
## [1]  6 12 18 24
offdiag(m, 2)
## [1] 11 17 23
offdiag(m, 3)
## [1] 16 22
offdiag(m, 4)
## [1] 21

+1 好主意,不过对于非方阵来说,diag(m[,-1]) 可能更好。 - Josh O'Brien
@JoshO'Brien 是的,那样更好。 - Matthew Lundberg
1
真的很优雅。不知道diag有这样的功能。 - IRTFM

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