Search code examples
rfor-loopmatrixsymmetric

Change elements in one matrix based on positions given by another matrix in R


Let's say I have a symmetric matrix A, for example:

> A <- matrix(runif(16),nrow = 4,byrow = T)
> ind <- lower.tri(A)
> A[ind] <- t(A)[ind]
> A
          [,1]      [,2]      [,3]       [,4]
[1,] 0.4212778 0.6874073 0.1551896 0.46757640
[2,] 0.6874073 0.5610995 0.1779030 0.54072946
[3,] 0.1551896 0.1779030 0.9515304 0.79429777
[4,] 0.4675764 0.5407295 0.7942978 0.01206526

I also have a 4 x 3 matrix B that gives specific positions of matrix A, for example:

> B<-matrix(c(1,2,4,2,1,3,3,2,4,4,1,3),nrow=4,byrow = T)
> B
      [,1] [,2] [,3]
[1,]    1    2    4
[2,]    2    1    3
[3,]    3    2    4
[4,]    4    1    3

The B matrix represents the following positions of A: (1,1), (1,2), (1,4), (2,2), (2,1), (2,3), (3,3), (3,2), (3,4), (4,4), (4,1), (4,3).

I want to change the values of A that are NOT in the positions given by B, replacing them by Inf. The result I want is:

          [,1]      [,2]      [,3]       [,4]
[1,] 0.4212778 0.6874073       Inf 0.46757640
[2,] 0.6874073 0.5610995 0.1779030        Inf
[3,]       Inf 0.1779030 0.9515304 0.79429777
[4,] 0.4675764       Inf 0.7942978 0.01206526

How can I do that quickly avoiding a for loop (which I'm able to code)? I've seen many similar posts, but no one gave me what I want. Thank you!


Solution

  • You want to do something like matrix subsetting (e.g., P[Q]) except that you can't use negative indexing in matrix subsetting (e.g., P[-Q] is not allowed). Here's a work-around.

    Store the elements you want to retain from A in a 2-column matrix where each row is a coordinate of A:

    Idx <- cbind(rep(1:4, each=ncol(B)), as.vector(t(B)))
    

    Create a matrix where all values are Inf, and then overwrite the values you wanted to "keep" from A:

    Res <- matrix(Inf, nrow=nrow(A), ncol=ncol(A))
    Res[Idx] <- A[Idx]
    

    Result

    Res
    #          [,1]        [,2]        [,3]       [,4]
    #[1,] 0.9043131 0.639718071         Inf 0.19158238
    #[2,] 0.6397181 0.601327568 0.007363378        Inf
    #[3,]       Inf 0.007363378 0.752123162 0.61428003
    #[4,] 0.1915824         Inf 0.614280026 0.02932679