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..
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..
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
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.
For a matrix of n x m
for i to n
for j to m
if i != j
matrix[i][j] = 0;
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
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.
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.