Creating a symmetric matrix in R
Is the workaround really necessary if the values only differ by that much?
Someone pointed out that my previous answer was wrong. I like some of the other ones better, but since I can't delete this one (accepted by a user who left), here's yet another solution using the micEcon
package:
symMatrix(s[upper.tri(s, TRUE)], nrow=nrow(s), byrow=TRUE)
How do I make a symmetric matrix using R?
You can try this -
mat[upper.tri(mat)] <- mat[upper.tri(mat)] + mat[lower.tri(mat)]
mat[lower.tri(mat)] <- mat[upper.tri(mat)]
mat
# [,1] [,2] [,3]
#[1,] 1 6 10
#[2,] 6 5 14
#[3,] 10 14 9
data
mat <- structure(c(1L, 4L, 7L, 2L, 5L, 8L, 3L, 6L, 9L), .Dim = c(3L, 3L))
mat
# [,1] [,2] [,3]
#[1,] 1 2 3
#[2,] 4 5 6
#[3,] 7 8 9
Most Efficient way to create a symmetric matrix
Just for completion I would like to also show this technique. The addition of the transpose will not work if the lower part of the matrix (under the diagonal) has values filled in, as it will add them to the upper part of the matrix.
Using the Matrix package we can create a sparse Matrix, which in case of creating the symmetric of a big matrix would require much less memory and even speed it up.
In order to create a symmetric sparse matrix from matrix e
we would do:
library(Matrix)
rowscols <- which(upper.tri(e), arr.ind=TRUE)
sparseMatrix(i=rowscols[,1], #rows to fill in
j=rowscols[,2], #cols to fill in
x=e[upper.tri(e)], #values to use (i.e. the upper values of e)
symmetric=TRUE, #make it symmetric
dims=c(nrow(e),nrow(e))) #dimensions
Output:
5 x 5 sparse Matrix of class "dsCMatrix"
[1,] . 2 3 4 5
[2,] 2 . 6 8 10
[3,] 3 6 . 12 15
[4,] 4 8 12 . 20
[5,] 5 10 15 20 .
Microbenchmark:
Let's make a function to make a symmetric Matrix out of a matrix (copies the upper part of matrix to the lower by default):
symmetrise <- function(mat){
rowscols <- which(upper.tri(mat), arr.ind=TRUE)
sparseMatrix(i=rowscols[,1],
j=rowscols[,2],
x=mat[upper.tri(mat)],
symmetric=TRUE,
dims=c(nrow(mat),ncol(mat)) )
}
And test:
> microbenchmark(
e + t(e),
symmetrise(e),
e[lower.tri(e)] <- t(e)[lower.tri(e)],
times=1000
)
Unit: microseconds
expr min lq mean median uq max neval cld
e + t(e) 75.946 99.038 117.1984 110.841 134.9590 246.825 1000 a
symmetrise(e) 5530.212 6246.569 6950.7681 6921.873 7034.2525 48662.989 1000 c
e[lower.tri(e)] <- t(e)[lower.tri(e)] 261.193 322.771 430.4479 349.968 395.3815 36873.894 1000 b
As you can see symmetrise
is actually much slower than e + t(e)
or df[lower.tri(df)] <- t(df)[lower.tri(df)]
but at least you have a function that automatically symmetrises a matrix (takes the upper part and creates the lower by default) and in case you have a big matrix where memory is an issue, this might come in handy.
P.S. Wherever you see a .
in the Matrix this represents a zero. By using a different system a sparse Matrix is a kind of 'compressed' object making it more memory efficient.
Create a matrix symmetric from long table in r
You can get the data in wide format first.
library(dplyr)
library(tidyr)
mat <- df %>%
pivot_wider(names_from = Var2, values_from = pre, values_fill = 0) %>%
column_to_rownames('Var1') %>%
as.matrix()
mat
# a b c d e
#a 1 0 0 0 0
#b 2 1 0 0 0
#c 3 6 1 0 0
#d 4 7 9 1 0
#e 5 8 10 11 1
Since you have a symmetric matrix you can copy the lower triangular matrix to upper triangle.
mat[upper.tri(mat)] <- t(mat)[upper.tri(mat)]
mat
# a b c d e
#a 1 2 3 4 5
#b 2 1 6 7 8
#c 3 6 1 9 10
#d 4 7 9 1 11
#e 5 8 10 11 1
data
df <- data.frame (Var1 = c("a", "b", "c","d","e","b","c","d","e","c","d","e","d","e","e"),
Var2 = c("a","a","a","a","a","b","b","b","b","c","c","c","d","d","e"),
pre = c(1,2,3,4,5,1,6,7,8,1,9,10,1,11,1) )
R: make symmetric matrix from lower diagonal
You need to make sure that the elements you're copying are ordered correctly:
m <- matrix(NA,4,4)
m[lower.tri(m,diag=TRUE)] <- 1:10
[,1] [,2] [,3] [,4]
[1,] 1 NA NA NA
[2,] 2 5 NA NA
[3,] 3 6 8 NA
[4,] 4 7 9 10
makeSymm <- function(m) {
m[upper.tri(m)] <- t(m)[upper.tri(m)]
return(m)
}
makeSymm(m)
Or you can use the built-in
Matrix::forceSymmetric(m,uplo="L")
Create a symmetric matrix from circular shifts of a vector
Let me answer my own question in order to close it properly, using the incredible simple and easy solution from Henrik's comment:
matrix(v, nrow = 3, ncol = 4, byrow = TRUE)[ , 1:3]
Maybe the byrow = TRUE
matches the three steps of the illustration best conceptually, but the output is the same with:
matrix(v, nrow = 4, ncol = 3)[1:3, ]
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 2 3 1
# [3,] 3 1 2
Because there may be "many vectors with different lengths", it could be convenient to make a simple function and apply it to the vectors stored in a list
:
cycle = function(x){
len = length(x)
matrix(x, nrow = len + 1, ncol = len)[1:len , ]
}
l = list(v1 = 1:3, v2 = letters[1:4])
lapply(l, cycle)
# $v1
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 2 3 1
# [3,] 3 1 2
#
# $v2
# [,1] [,2] [,3] [,4]
# [1,] "a" "b" "c" "d"
# [2,] "b" "c" "d" "a"
# [3,] "c" "d" "a" "b"
# [4,] "d" "a" "b" "c"
How to create a symmetric matrix in R counting how often two columns have the same values?
In order to create a co-occurrence matrix from your data, you first need to convert your NA
s into 0s, then do a cross-product of your data without the first ID
column:
x = data.frame(ID = c(1:4), sp1 = c(NA,0,1,1), sp2 = c(1,0,NA,1), sp3 = c(1,1,0,1))
x[is.na(x)] = 0
crossprod(t(x[-1]))
[,1] [,2] [,3] [,4]
[1,] 2 1 0 2
[2,] 1 1 0 1
[3,] 0 0 1 1
[4,] 2 1 1 3
Constructing symmetric matrix on R
m <- matrix(0.5, ncol = 1000, nrow = 1000)
diag(m) <- 1
Related Topics
Create End of the Month Date from a Date Variable
Speed Up Plot() Function for Large Dataset
Duplicate 'Row.Names' Are Not Allowed Error
Add Objects to Package Namespace
Print Unicode Character String in R
How Subset a Data Frame by a Factor and Repeat a Plot for Each Subset
Change the Default Colour Palette in Ggplot
Pretty Ticks for Log Normal Scale Using Ggplot2 (Dynamic Not Manual)
How to Multiply Data Frame by Vector
Displaying a PDF from a Local Drive in Shiny
Show Frequencies Along with Barplot in Ggplot2
Count Number of Rows Matching a Criteria
Split Character Data into Numbers and Letters
Get X-Value Given Y-Value: General Root Finding for Linear/Non-Linear Interpolation Function