Home > Net >  How to symmetrically fill an half-full square matrix (tibble)?
How to symmetrically fill an half-full square matrix (tibble)?

Time:07-23

In a square matrix where only the cells above the diagonal is full (including the diagonal) and the rest is NA, I would like to symmetrically fill the NA's below the diagonal with the values above the diagonal.

Edit: The example may have been misleading, so I slightly modified it.

Example:

library(tidyverse)

Tibble <- tibble(A = c(5, NA, NA),
                 B = c(1, 3, NA),
                 C = c(6, 2, 4))

Tibble

Result:

# A tibble: 3 × 3
      A     B     C
  <dbl> <dbl> <dbl>
1     5     1     6
2    NA     3     2
3    NA    NA     4

Desired outcome:

# A tibble: 3 × 3
      A     B     C
  <dbl> <dbl> <dbl>
1     5     1     6
2     1     3     2
3     6     2     4

CodePudding user response:

With Matrix package:

library(tidyverse)
library(Matrix)

Tibble <- tibble(A = c(5, NA, NA),
       B = c(1, 3, NA),
       C = c(6, 2, 4)) %>% 
  as.matrix()

forceSymmetric(Tibble) 

  A B C
A 5 1 6
B 1 3 2
C 6 2 4

If you want a tibble

forceSymmetric(Tibble) %>% 
  as.matrix() %>% 
  as_tibble()

# A tibble: 3 x 3
      A     B     C
  <dbl> <dbl> <dbl>
1     5     1     6
2     1     3     2
3     6     2     4

CodePudding user response:

As @onyambu mentioned in the comments, you should first transpose the matrix. Here an example with more 3 rows/columns:

library(tibble)
#> Warning: package 'tibble' was built under R version 4.1.2
Tibble <- tibble(A = c(5, NA, NA, NA),
                 B = c(1, 3, NA, NA),
                 C = c(6, 2, 4, NA),
                 D = c(5, 2, 1, 3))

Tibble_m <- as.matrix(Tibble)
Tibble_m[lower.tri(Tibble_m)] <- t(Tibble_m)[lower.tri(Tibble_m)]
as_tibble(Tibble_m)
#> # A tibble: 4 × 4
#>       A     B     C     D
#>   <dbl> <dbl> <dbl> <dbl>
#> 1     5     1     6     5
#> 2     1     3     2     2
#> 3     6     2     4     1
#> 4     5     2     1     3

Created on 2022-07-22 by the reprex package (v2.0.1)

An option could be first convert your tibble to a matrix and then fill the lower.tri with the upper.tri like this:

library(tibble)
Tibble <- tibble(A = c(5, NA, NA),
                 B = c(1, 3, NA),
                 C = c(6, 2, 4))

Tibble_m <- as.matrix(Tibble)
Tibble_m[lower.tri(Tibble_m)] <- Tibble_m[upper.tri(Tibble_m)]
as_tibble(Tibble_m)
#> # A tibble: 3 × 3
#>       A     B     C
#>   <dbl> <dbl> <dbl>
#> 1     5     1     6
#> 2     1     3     2
#> 3     6     2     4

Created on 2022-07-22 by the reprex package (v2.0.1)

CodePudding user response:

Replace the NA's with 0 and then add the tranpose after the diagonal is zeroed. as_tibble can be omitted if a data frame result is ok.

library(dplyr)

Tibble %>%
  mutate(across(, coalesce, 0)) %>%
  ` `(`diag<-`(t(.), 0)) %>%
  as_tibble
## # A tibble: 3 × 3
##       A     B     C
##   <dbl> <dbl> <dbl>
## 1     5     1     6
## 2     1     3     2
## 3     6     2     4

Using tibbles or data frames is not the best way to represent symmetric matrices and suggest you use a matrix instead.

library(magrittr)

m <- as.matrix(Tibble)

m %>%
  { replace(., is.na(.), 0) } %>%
  ` `(`diag<-`(t(.), 0))

##      A B C
## [1,] 5 1 6
## [2,] 1 3 2
## [3,] 6 2 4

CodePudding user response:

Try this with base R for loop

for(i in 1:nrow(Tibble)){
    for(j in 1:ncol(Tibble)){
        if(is.na(Tibble[i,j])) Tibble[i,j] <- Tibble[j,i]
    }
}
  • output
# A tibble: 3 × 3
      A     B     C
  <dbl> <dbl> <dbl>
1     5     1     6
2     1     3     2
3     6     2     4

CodePudding user response:

You can try ifelse as.matrix to make it

> Tibble[] <- ifelse(is.na(as.matrix(Tibble)), t(Tibble), as.matrix(Tibble))

> Tibble
# A tibble: 3 × 3
      A     B     C
  <dbl> <dbl> <dbl>
1     5     1     6
2     1     3     2
3     6     2     4

or similarily with replace

> Tibble[] <- replace(as.matrix(Tibble), is.na(as.matrix(Tibble)), t(Tibble)[is.na(as.matrix(Tibble))])

> Tibble
# A tibble: 3 × 3
      A     B     C
  <dbl> <dbl> <dbl>
1     5     1     6
2     1     3     2
3     6     2     4
  • Related