Search code examples
rmatrixsapply

how can I extract a position of values that match a logical selection in a matrix in r?


How can I extract the position of every 0 per column in a following matrix:

bm <- matrix(c(0,1,0,1,1,1,0,1,1,1,1,0,0,0,0),5,3) 

that gives a matrix like:

+---+---+---+
| x | y | z |
+---+---+---+
| 0 | 1 | 1 |
+---+---+---+
| 1 | 0 | 0 |
+---+---+---+
| 0 | 1 | 0 |
+---+---+---+
| 1 | 1 | 0 |
+---+---+---+
| 1 | 1 | 0 |
+---+---+---+

So I want to have a data frame or matrix in whichever form it's easier with the positions of each 0 according to the rows or column position. Something like:

+---+---+---+
| x | y | z |
+---+---+---+
| 1 | 2 | 2 |
+---+---+---+
| 3 |   | 3 |
+---+---+---+
|   |   | 4 |
+---+---+---+
|   |   | 5 |
+---+---+---+
|   |   |   |
+---+---+---+

It's a very basic question that I did not find an answer right away yet.


Solution

  • If we don't want to reorder the index by column

    row(bm) * !bm
    

    If we want to reorder, an option is row multiplied with the logical matrix and then reorder the positions

    apply(row(bm)* !bm, 2, function(x) c(x[x!=0], x[x==0]))
    #      [,1] [,2] [,3]
    #[1,]    1    2    2
    #[2,]    3    0    3
    #[3,]    0    0    4
    #[4,]    0    0    5
    #[5,]    0    0    0
    

    Or using order

    apply(row(bm) * !bm, 2, function(x) x[order(!x)])
    

    Or another option

    sapply(asplit(replace(row(bm), !!bm, NA), 2),
           function(x)  x[order(is.na(x))])