问题
I need to loop through the diagonal+1 (i.e. the values 1 column to the right of the diagonal) and write the value to a column in a dataframe:
write.csv(data.frame(matrix[1,2], matrix[2,3], matrix[3,4])
How can I do this using a function, rather than just listing all the positions of the values?
回答1:
You can index using a matrix.
eg
m <- matrix(1:25, ncol = 5)
The off diagonals can be accessed using
offd <- cbind(1:4,2:5)
m[offd]
## [1] 6 12 18 24
You could create a function that does this
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
回答2:
A fast way of doing this without the head-scratching of working out the indices programatically is to use the oft-overlooked row()
and col()
functions. These return for each element of a matrix the row or column that element belongs to respectively.
The diagonal is where the row index of an element equals the column index. The first subdiagonal is where the row index equals the column index plus 1 whilst the first superdiagonal is where the row index equals the column index minus 1.
Here are some examples:
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
The diagonal
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
First subdiagonal
m[row(m) == col(m) + 1
> m[row(m) == col(m) + 1]
[1] 2 8 14 20
First superdiagonal
m[row(m) == col(m) -1]
> m[row(m) == col(m) -1]
[1] 6 12 18 24
Higher-order super- and subdiagonals can be extracted by increasing the value added to the column index.
Creating the data frame and writing out
Essentially you already have this, but
write.csv(data.frame(m[row(m) == col(m) + 1), file = "subdiag.csv")
A general function for sub- or superdiagonals
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)]
}
In use we have:
> diags(m)
[1] 2 8 14 20
> diags(m, type = "super")
[1] 6 12 18 24
> diags(m, offset = 2)
[1] 3 9 15
回答3:
Take the submatrix, then the diagonal of that.
Using mnel's m
:
diag(m[, -1])
[1] 6 12 18 24
As a function with variable offset (but in this form, it is not any cleaner than mnel's solution):
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
来源:https://stackoverflow.com/questions/15672585/looping-through-diagonal1-of-a-matrix