Replace off-block diagonal elements with 0

107 Views Asked by At

I'm working in R and I have a matrix with dimensions 6n x 6n. I would like to replace all elements out of a 6x6 block diagonal matrix with zero. Any suggestions?

For example (reporting just a 12x12 sample)

# create a sample 12x12 matrix
> mat <- matrix(1:144, nrow=12, ncol=12)
> mat
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] 
 [1,]    1   13   25   37   49   61   73   85   97   109   121   133
 [2,]    2   14   26   38   50   62   74   86   98   110   122   134
 [3,]    3   15   27   39   51   63   75   87   99   111   123   135
 [4,]    4   16   28   40   52   64   76   88  100   112   124   136
 [5,]    5   17   29   41   53   65   77   89  101   113   125   137
 [6,]    6   18   30   42   54   66   78   90  102   114   126   138
 [7,]    7   19   31   43   55   67   79   91  103   115   127   139
 [8,]    8   20   32   44   56   68   80   92  104   116   128   140
 [9,]    9   21   33   45   57   69   81   93  105   117   129   141
[10,]   10   22   34   46   58   70   82   94  106   118   130   142
[11,]   11   23   35   47   59   71   83   95  107   119   131   143
[12,]   12   24   36   48   60   72   84   96  108   120   132   144

What I would like to obtain is

new_mat
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] 
 [1,]    1   13   25   37   49   61    0    0    0     0     0     0  
 [2,]    2   14   26   38   50   62    0    0    0     0     0     0  
 [3,]    3   15   27   39   51   63    0    0    0     0     0     0 
 [4,]    4   16   28   40   52   64    0    0    0     0     0     0  
 [5,]    5   17   29   41   53   65    0    0    0     0     0     0  
 [6,]    6   18   30   42   54   66    0    0    0     0     0     0  
 [7,]    0    0    0    0    0    0   79   91  103   115   127   139
 [8,]    0    0    0    0    0    0   80   92  104   116   128   140
 [9,]    0    0    0    0    0    0   81   93  105   117   129   141
[10,]    0    0    0    0    0    0   82   94  106   118   130   142
[11,]    0    0    0    0    0    0   83   95  107   119   131   143
[12,]    0    0    0    0    0    0   84   96  108   120   132   144
4

There are 4 best solutions below

0
G. Grothendieck On

Take the kronecker product of an identity matrix and a matrix of all 1's and multiply mat by that.

mat * (diag(nrow(mat) / 6) %x% matrix(1, 6, 6))

giving:

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
 [1,]    1   13   25   37   49   61    0    0    0     0     0     0
 [2,]    2   14   26   38   50   62    0    0    0     0     0     0
 [3,]    3   15   27   39   51   63    0    0    0     0     0     0
 [4,]    4   16   28   40   52   64    0    0    0     0     0     0
 [5,]    5   17   29   41   53   65    0    0    0     0     0     0
 [6,]    6   18   30   42   54   66    0    0    0     0     0     0
 [7,]    0    0    0    0    0    0   79   91  103   115   127   139
 [8,]    0    0    0    0    0    0   80   92  104   116   128   140
 [9,]    0    0    0    0    0    0   81   93  105   117   129   141
[10,]    0    0    0    0    0    0   82   94  106   118   130   142
[11,]    0    0    0    0    0    0   83   95  107   119   131   143
[12,]    0    0    0    0    0    0   84   96  108   120   132   144
0
akrun On

Try

library(Matrix)
as.matrix(bdiag(replicate(2, matrix(1, 6, 6), simplify = FALSE)) * mat)

-output

       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
 [1,]    1   13   25   37   49   61    0    0    0     0     0     0
 [2,]    2   14   26   38   50   62    0    0    0     0     0     0
 [3,]    3   15   27   39   51   63    0    0    0     0     0     0
 [4,]    4   16   28   40   52   64    0    0    0     0     0     0
 [5,]    5   17   29   41   53   65    0    0    0     0     0     0
 [6,]    6   18   30   42   54   66    0    0    0     0     0     0
 [7,]    0    0    0    0    0    0   79   91  103   115   127   139
 [8,]    0    0    0    0    0    0   80   92  104   116   128   140
 [9,]    0    0    0    0    0    0   81   93  105   117   129   141
[10,]    0    0    0    0    0    0   82   94  106   118   130   142
[11,]    0    0    0    0    0    0   83   95  107   119   131   143
[12,]    0    0    0    0    0    0   84   96  108   120   132   144
0
Mikael Jagan On

You can also do the replacement directly. One benefit of this approach is that it does not depend on the type of the matrix or the replacement value.

## Number of rows in square matrix
n <- nrow(mat)
## Number of rows in rectangular block
b <- 6L

## Index of block diagonal elements
k <- sequence(rep.int(b, n), 
              rep(seq.int(1L, n, b), each = b) + seq.int(0L, n * n - 1L, n))

## Replacement
mat[-k] <- 0L
mat
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
 [1,]    1   13   25   37   49   61    0    0    0     0     0     0
 [2,]    2   14   26   38   50   62    0    0    0     0     0     0
 [3,]    3   15   27   39   51   63    0    0    0     0     0     0
 [4,]    4   16   28   40   52   64    0    0    0     0     0     0
 [5,]    5   17   29   41   53   65    0    0    0     0     0     0
 [6,]    6   18   30   42   54   66    0    0    0     0     0     0
 [7,]    0    0    0    0    0    0   79   91  103   115   127   139
 [8,]    0    0    0    0    0    0   80   92  104   116   128   140
 [9,]    0    0    0    0    0    0   81   93  105   117   129   141
[10,]    0    0    0    0    0    0   82   94  106   118   130   142
[11,]    0    0    0    0    0    0   83   95  107   119   131   143
[12,]    0    0    0    0    0    0   84   96  108   120   132   144

Having said that, for matrices of type "double" or "complex", multiplying elementwise by a suitable Kronecker product is probably the right (most transparent) answer.

0
ThomasIsCoding On

You can use kronecker like below to create a mask matrix

> mat * kronecker(diag(c(1, 1)), matrix(1, 6, 6))
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
 [1,]    1   13   25   37   49   61    0    0    0     0     0     0
 [2,]    2   14   26   38   50   62    0    0    0     0     0     0
 [3,]    3   15   27   39   51   63    0    0    0     0     0     0
 [4,]    4   16   28   40   52   64    0    0    0     0     0     0
 [5,]    5   17   29   41   53   65    0    0    0     0     0     0
 [6,]    6   18   30   42   54   66    0    0    0     0     0     0
 [7,]    0    0    0    0    0    0   79   91  103   115   127   139
 [8,]    0    0    0    0    0    0   80   92  104   116   128   140
 [9,]    0    0    0    0    0    0   81   93  105   117   129   141
[10,]    0    0    0    0    0    0   82   94  106   118   130   142
[11,]    0    0    0    0    0    0   83   95  107   119   131   143
[12,]    0    0    0    0    0    0   84   96  108   120   132   144