4

We can use diag() to remove diagonal elements of a matrix, but what if we want to remove a diagonal square of elements? Like in a 6x6 matrix, I want to remove 2x2 squares in the diagonal. It looks very basic, but how to do that in r?

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]   23   98   12   98   32   99
[2,]   54   11   13   02   31   78
[3,]   25   85   15   09   46   87
[4,]   98   98   16   17   45   48
[5,]   88   00   68   99   89   89
[6,]   05   33   66   12   14   78

and I want to set the diagonal square to NA

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]   NA   NA   12   98   32   99
[2,]   NA   NA   13   02   31   78
[3,]   25   85   NA   NA   46   87
[4,]   98   98   NA   NA   45   48
[5,]   88   00   68   99   NA   NA
[6,]   05   33   66   12   NA   NA

remove all the NAs and then we combine the columns

     [,1] [,2] [,3] [,4]
 [1,]  12   98   32   99
 [2,]  13   02   31   78
 [3,]  25   85   46   87
 [4,]  98   98   45   48
 [5,]  88   00   68   99
 [6,]  05   33   66   12
user3697665
  • 297
  • 1
  • 6
  • 17
  • Remove it how? What would you be left with? It would help to include a [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input and desired output. – MrFlick Oct 31 '15 at 05:09

3 Answers3

4

I expect there's a more elegant way to do this, but here's one way:

# Create a matrix
mat = matrix(1:36, nrow=6)

# Set block diagonal elements to NA
for (i in seq(1, nrow(mat), 2)) {
  mat[i:(i+1),i:(i+1)] = NA
}

# Reform the matrix with the NA values excluded
matrix(mat[!is.na(mat)], nrow=nrow(mat)-2)
eipi10
  • 91,525
  • 24
  • 209
  • 285
2

You could use the Kronecker product to quickly construct a block diagonal matrix indicating which elements are to be kept and which are to be removed.

## An example matrix
set.seed(1)
m <- matrix(sample(1:100, 36), ncol=6)

## Construct a logical block diagonal matrix, then use it to remove blocks along diagonal
ii <- !kronecker(diag(1, nrow(m)/2), matrix(1, ncol=2, nrow=2))
matrix(m[ii], ncol = ncol(m)-2)
##      [,1] [,2] [,3] [,4]
## [1,]   57   19   32    1
## [2,]   89   16   63   28
## [3,]   20   61   51   87
## [4,]   86   34   10   42
## [5,]   58   88   21   70
## [6,]    6   83   29   13
Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
2

We create 3 matrix of 1 in a list, build a block diagonal matrix with bdiag, double negate to coerce binary to logical, replace the TRUE elements with NA, multiply with 'm1' to get 'm2'.

library(Matrix)
m2 <- as.matrix((NA^!!bdiag(lapply(1:3, matrix, data=1,ncol=2, nrow=2)))*m1)
m2
#      [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]   NA   NA   12   98   32   99
#[2,]   NA   NA   13    2   31   78
#[3,]   25   85   NA   NA   46   87
#[4,]   98   98   NA   NA   45   48
#[5,]   88    0   68   99   NA   NA
#[6,]    5   33   66   12   NA   NA

We remove the NA elements in each row using apply with MARGIN=1 to get the expected output.

t(apply(m2, 1, function(x) x[!is.na(x)]))
 #      [,1] [,2] [,3] [,4]
#[1,]   12   98   32   99
#[2,]   13    2   31   78
#[3,]   25   85   46   87
#[4,]   98   98   45   48
#[5,]   88    0   68   99
#[6,]    5   33   66   12

data

m1 <- structure(c(23L, 54L, 25L, 98L, 88L, 5L, 98L, 11L, 85L, 98L, 
0L, 33L, 12L, 13L, 15L, 16L, 68L, 66L, 98L, 2L, 9L, 17L, 99L, 
12L, 32L, 31L, 46L, 45L, 89L, 14L, 99L, 78L, 87L, 48L, 89L, 78L
), .Dim = c(6L, 6L))
akrun
  • 874,273
  • 37
  • 540
  • 662