How to replace non-diagonal elements in a matrix?

2019-03-05 09:43发布

问题:

More specifically, I want all elements other than the diagonal ones (X_11, X_22, X_33,...,X_jj) to be zero.

E.g. I want:

 [1 4 5
  2 3 5
  3 9 8]

to be:

 [1 0 0
  0 3 0
  0 0 8]

Is this possible? Sorry I'm a complete noob at this..

回答1:

The simplest way to do this, is to create a new matrix filled with 0s, then replace its diagonal with the diagonal of the old matrix.

So if you have:

m <- cbind(c(1,2,3), c(4,3,9), c(5, 5, 8))  # The original matrix

diagonal <- diag(m)
m <- matrix(0, nrow(m), ncol(m))  # Overwrite the old matrix
diag(m) <- diagonal


回答2:

It's a simple one liner. First, get the data in:

> (a <- matrix(scan(),nr=3,byrow=TRUE))
1: 1 4 5 2 3 5 3 9 8
10: 
Read 9 items
     [,1] [,2] [,3]
[1,]    1    4    5
[2,]    2    3    5
[3,]    3    9    8

Method 1:

> diag(diag(a))
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    3    0
[3,]    0    0    8

The thing is, if its argument is a matrix, diag extracts the diagonal... but if the argument is a vector, it's a function that creates a diagonal matrix. So just use it twice. (In fact diag has four different uses, depending on what you give it, though two of the cases are quite similar.) See ?diag

If your matrices are huge this isn't likely to be the most efficient way, but for moderate size cases that's the way I do it.

---

Method 2:

A completely different one-liner that also works -

ifelse(row(a)==col(a),a,0)

The two work the same on square matrices. But they have a different result on non-square matrices - the first one returns a square matrix (of dimension the smaller of the two original dimensions), while the second one returns an object of the same shape as its argument; this can be useful depending on the situation.



回答3:

For a matrix of n x m

for i to n
    for j to m
        if i != j
            matrix[i][j] = 0;


回答4:

If m is your matrix try:

m = matrix(c(1,4,5,2,3,5,3,9,8),3,3)
m[upper.tri(m) | lower.tri(m)] = 0

m

##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    3    0
## [3,]    0    0    8


回答5:

It simply dependes on the size of the matrix you're dealing with, let's say you have a nxn matrix then the diagonals are gonna be at these places 0, n+1 , 2(n+1), 3(n+1),... if your matrix as you mentioned is not multi dimensional and is linear! so by simply writing a for loop it is possible.



回答6:

I'm transferring my answer from your second post on this topic.

You can use the following to compute a logical matrix which describes the non-diagonal entries of a n×n matrix:

outer(1:n, 1:n, function(i,j) i!=j)

Applied to your example:

> m <- matrix(c(1,2,3,4,3,9,5,5,8),ncol=3)
> m
     [,1] [,2] [,3]
[1,]    1    4    5
[2,]    2    3    5
[3,]    3    9    8
> m[outer(1:3, 1:3, function(i,j) i!=j)] <- 0
> m
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    0    3    0
[3,]    0    0    8

I also like the triangle approach by @e4e5f4. That might be a bit faster than this code here, but this code here might be easier to adapt to different situations. So it's good to know this one, even if that one might be preferrable for your current application.