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