2

Given is a matrix (no assumptions are made about its dimensions) which contains zeros below the diagonal that runs from the bottom left to the upper right corner:

m <- matrix(data = c(2, 1, 8, 9, 1,
                     5, 0, 4, 3, 6,
                     7, 1, 2, 5, 0,
                     3, 1, 0, 0, 0,
                     2, 8, 0, 0, 0,
                     9, 0, 0, 0, 0),
        nrow = 6,
        ncol = 5,
        byrow = TRUE)

The question is how to replace all these zeros below the diagonal with NA? The result should be the following:

       [,1] [,2] [,3] [,4] [,5]
 [1,]    2    1    8    9    1
 [2,]    5    0    4    3    6
 [3,]    7    1    2    5   NA
 [4,]    3    1    0   NA   NA
 [5,]    2    8   NA   NA   NA
 [6,]    9   NA   NA   NA   NA

The matrix may contain zeros elsewhere (on or above the diagonal). These zeros should not be replaced.

PeterD
  • 429
  • 2
  • 13
  • Have also a look at [Extract opposite-diagonal (not off-diagonal) elements of a matrix](https://stackoverflow.com/q/58277528/10488504) – GKi Sep 08 '21 at 12:13

3 Answers3

4

Use the base R functions row and col:

m[row(m) + col(m) > nrow(m) + 1] <- NA

Which gives the desired output:

> m
      [,1] [,2] [,3] [,4] [,5]
 [1,]    2    1    8    9    1
 [2,]    5    2    4    3    6
 [3,]    7    1    2    5   NA
 [4,]    3    1    3   NA   NA
 [5,]    2    8   NA   NA   NA
 [6,]    9   NA   NA   NA   NA

The trick is to add the row and column number of each cell. All cells that have a number greater than the number of rows plus 1 then correspond to the cells below the diagonal running from the bottom left to the upper right corner.

PeterD
  • 429
  • 2
  • 13
  • 1
    Why not just `m[row(m) + col(m) - nrow(m) > 1] <- NA` ? – GKi Sep 08 '21 at 12:06
  • Thanks GKi. I'll simplify my answer based on your suggestion. I took too much inspiration from the functions `lower.tri` and `upper.tri` I guess, which do similar things. – PeterD Sep 08 '21 at 12:31
4

Try upper.tri like below

> replace(m, upper.tri(m)[nrow(m):1, ], NA)
     [,1] [,2] [,3] [,4] [,5]
[1,]    2    1    8    9    1
[2,]    5    0    4    3    6
[3,]    7    1    2    5   NA
[4,]    3    1    0   NA   NA
[5,]    2    8   NA   NA   NA
[6,]    9   NA   NA   NA   NA
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
3

An option with ^ and NA

m * NA^upper.tri(m)[rev(seq(nrow(m))),]
  [,1] [,2] [,3] [,4] [,5]
[1,]    2    1    8    9    1
[2,]    5    0    4    3    6
[3,]    7    1    2    5   NA
[4,]    3    1    0   NA   NA
[5,]    2    8   NA   NA   NA
[6,]    9   NA   NA   NA   NA
akrun
  • 874,273
  • 37
  • 540
  • 662