Removing diagonal elements from a matrix from R

How to remove diagonal elements (diagL) from my matrix L using R? I tried using the following:

subset(L, select=-diag(L)) or subset(L, select=-c(diag(L))) 

but I get 0 numbers ...

+9
matrix r diagonal
source share
4 answers

R programming language? I love C better, it's easier to spell.

One way is to create a matrix with numbers the way I like:

 a<-t(matrix(1:16,nrow=4,ncol=4)) 

which looks like:

  [,1] [,2] [,3] [,4] [1,] 1 2 3 4 [2,] 5 6 7 8 [3,] 9 10 11 12 [4,] 13 14 15 16 

Delete values ​​diagonally:

 diag(a)=NA 

that leads to:

  [,1] [,2] [,3] [,4] [1,] NA 2 3 4 [2,] 5 NA 7 8 [3,] 9 10 NA 12 [4,] 13 14 15 NA 

To actually DELETE the values, and not just remove them, we need to change:

 a<-t(matrix(t(a)[which(!is.na(a))],nrow=3,ncol=4)) 

That leads to:

  [,1] [,2] [,3] [1,] 2 3 4 [2,] 5 7 8 [3,] 9 10 12 [4,] 13 14 15 

which is the same as what we got in C above.

This is a bit complicated, but as a result I see the correct answer. I would be interested to see an improved solution by someone who knows R better than me.

A little explanation on purpose:

 a<-t(matrix(t(a)[which(!is.na(a))],nrow=3,ncol=4)) 
  1. !is.na(a) gives us a list of TRUE, FALSE values ​​for which the elements have been reset.
  2. which(!is.na(a)) gives us a list of indexes for each of the true elements.
  3. t(a) transposes the matrix, since we need to draw based on the indices in # 2.
  4. t(a)[which(!is.na(a))] gives us a list of numbers in which there are no diagonal values ​​of NA.
  5. matrix(t(a)[which(!is.na(a))],nrow=3,ncol=4) converts the list from # 4 into a matrix, which is a transposition of what we want.
  6. a<-t(matrix(1:16,nrow=4,ncol=4)) (all this) permutes # 5 in the form we want and assigns its a variable.

This works with cases like a<-t(matrix(11:26,nrow=4,ncol=4)) .

+15
source share

Here are some artificial data to illustrate:

 x <- matrix(1:16, 4, 4) n <- nrow(x) x [,1] [,2] [,3] [,4] [1,] 1 5 9 13 [2,] 2 6 10 14 [3,] 3 7 11 15 [4,] 4 8 12 16 

After vectorizing the matrix x diagonal elements correspond to the indices 1, n+2, 2*n+3, ... , that is, the sequences seq(1, n^2, n+1) . These indices can be removed using

 x[-seq(1,n^2,n+1)] [1] 2 3 4 5 7 8 9 10 12 13 14 15 

After “removing the diagonal” of the matrix, you can move the lower triangular matrix up to get a matrix with n-1 rows and columns n by

 matrix(x[-seq(1,n^2,n+1)], n-1, n) [,1] [,2] [,3] [,4] [1,] 2 5 9 13 [2,] 3 7 10 14 [3,] 4 8 12 15 

or, and this is probably what you want, you can move the lower triangular matrix to the right to get a matrix with columns n and columns n-1 , move x before deleting the diagonal indices and wrap them back after

 t(matrix(t(x)[-seq(1,n^2,n+1)], n-1, n)) [,1] [,2] [,3] [1,] 5 9 13 [2,] 2 10 14 [3,] 3 7 15 [4,] 4 8 12 
+7
source share

Keep in mind that the diagonal will have the same index X and Y. The following is a brief program to reset the diagonal to C:

 #include <stdio.h> static void printMat(char mat[4][4], char *comment) { printf("%s:\n", comment); for(int jj=0; jj<4; jj++) { for(int ii=0; ii<4; ii++) { printf("%2d ",mat[jj][ii]); } printf("\n"); } } main() { static char matrix[4][4]= { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9,10,11,12}, {13,14,15,16} }; printMat(matrix,"Before"); for(int ii=0; ii<4; ii++) { matrix[ii][ii]=0; } printMat(matrix,"After"); } 

This leads to:

 Before: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 After: 0 2 3 4 5 0 7 8 9 10 0 12 13 14 15 0 

REMOVE that just cleaning the diagonal is harder.

This should do the trick: (Keep in mind that memcpy from zero bytes can access elements that are not there).

 #include <stdio.h> #include <strings.h> static void printMat(char *mat, int xDim, int yDim,char *comment) { printf("%s:\n", comment); for(int jj=0; jj<yDim; jj++) { for(int ii=0; ii<xDim; ii++) { printf("%2d ",(mat[(jj)*xDim+ii]) ); } printf("\n"); } } main() { static char matrix[4][4]= { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9,10,11,12}, {13,14,15,16} }; static char new[4][3]; printMat((char*)matrix,4,4,"Before"); for(int ii=0; ii<4; ii++) { memcpy(&new[ii][0], &matrix[ii][0],ii); memcpy(&new[ii][ii],&matrix[ii][ii+1], 4-ii); } printMat((char*)new,3,4,"After"); } 

Results in:

 Before: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 After: 2 3 4 5 7 8 9 10 12 13 14 15 

Of course, if you want something in another language, this helps to ask.

+2
source share

Still using base R, you can use a combination of upper.tri() and lower.tri to find what you are looking for on the same line. For convenience, I created a one-line function. The code is as follows.

 a <- matrix(rnorm(100), nrow = 4, ncol = 4) select_all_but_diag <- function(x) matrix(x[lower.tri(x, diag = F) | upper.tri(x, diag = F)], nrow = nrow(x) - 1, ncol = ncol(x)) select_all_but_diag(a) 

This is the matrix earlier (in my case): a

  [,1] [,2] [,3] [,4] [1,] 0.3 2.5 -0.5 2.8 [2,] 0.7 1.1 -1.4 -0.7 [3,] 0.9 0.8 1.6 0.5 [4,] -0.8 -0.3 -0.9 1.6 

And this is the select_all_but_diag(a) output matrix:

  [,1] [,2] [,3] [,4] [1,] 0.7 2.5 -0.5 2.8 [2,] 0.9 0.8 -1.4 -0.7 [3,] -0.8 -0.3 -0.9 0.5 

EDIT for major line

Instead, if you want convolution to be the main row, you can use this advanced version of the function, which allows you to collapse the matrix, reducing the number of columns instead of the number of rows.

 select_all_but_diag <- function(x, collapse_by = "row") { if(collapse_by == "row") matrix(x[lower.tri(x, diag = F) | upper.tri(x, diag = F)], nrow = nrow(x) - 1, ncol = ncol(x)) else if(collapse_by == "col") t(matrix(t(x)[lower.tri(x, diag = F) | upper.tri(x, diag = F)], nrow = nrow(x) - 1, ncol = ncol(x))) else stop("collapse_by accepts only 'row' or 'col'.") } a select_all_but_diag(a, collapse_by = "col") 

This is the conclusion of the latter:

  [,1] [,2] [,3] [1,] 2.5 -0.5 2.8 [2,] 0.7 -1.4 -0.7 [3,] 0.9 0.8 0.5 [4,] -0.8 -0.3 -0.9 
0
source share

All Articles