Make a matrix being symmetric
A symmetric matrix can be useful is many context and it is good to be able to generate such a matrix. Here are several solutions. The most complete function was symmetricize() available in the discontinuited package ENA. I copy the function from this package to my package HelpersMG to make it again available:
> essai <- matrix(data = 1:25, nrow = 5)
> essai
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
>
>
> diag(essai) <- 0
> library("gdata")
> lowerTriangle(essai, diag=FALSE, byrow=FALSE) <- upperTriangle(essai, diag=FALSE, byrow=TRUE)
>
> essai
[,1] [,2] [,3] [,4] [,5]
[1,] 0 6 11 16 21
[2,] 6 0 12 17 22
[3,] 11 12 0 18 23
[4,] 16 17 18 0 24
[5,] 21 22 23 24 0
A function symmetricize() was present in the package ENA, but this package is no more available (some dependencies do not exist anymore).
But it was possible to extract the code of this function:
symmetricize <-
function(matrix, method=c("max", "min","avg", "ld", "ud"), adjacencyList=FALSE){
method <- match.arg(method)
if (missing(matrix)){
stop("You must provide a matrix to symmetricize.")
}
x <- matrix
if (method=="ld"){
#solution from Michael Conklin, http://www.biostat.wustl.edu/archives/html/s-news/2000-03/msg00127.html
x[matrix(c(col(x)[lower.tri(x)], row(x)[lower.tri(x)]), ncol = 2)] <-
x[matrix(c(row(x)[lower.tri(x)], col(x)[lower.tri(x)]), ncol = 2)]
}
if (method=="ud"){
x[matrix(c(col(x)[upper.tri(x)], row(x)[upper.tri(x)]), ncol = 2)] <-
x[matrix(c(row(x)[upper.tri(x)], col(x)[upper.tri(x)]), ncol = 2)]
}
if (method=="max" || method=="min" || method=="avg"){
#retrieve the (row,col) indices for the lower-diagonal entries in the matrix
ldi <- matrix(c(row(x)[lower.tri(x)], col(x)[lower.tri(x)]), ncol = 2)
#already column-major, so we can leave this
#retrieve the (row,col) indices for the upper-diagonal entries in the matrix
udi <- matrix(c(row(x)[upper.tri(x)], col(x)[upper.tri(x)]), ncol = 2)
#in order for these to be in the symmetrical order as ldi, we need to sort.
udi <- udi[order(udi[,1], udi[,2]),]
#extract the upper and lower diagonal elements in a way that's symmetrical in their indexces
ud <- x[udi]
ld <- x[ldi]
#replace with either the min, max, or mean, depending on the selection
if (method=="max"){
x[ldi] <- apply(rbind(ld,ud),2,max);
x[udi] <- apply(rbind(ld,ud),2,max);
}
if (method=="min"){
x[ldi] <- apply(rbind(ld,ud),2,min);
x[udi] <- apply(rbind(ld,ud),2,min);
}
if (method=="avg"){
x[ldi] <- apply(rbind(ld,ud),2,mean);
x[udi] <- apply(rbind(ld,ud),2,mean);
}
}
if (!adjacencyList){
#return the adjacency matrix
return(x)
}
else{
#convert to adjacency list and add addressing
if (is.null(rownames(matrix))){
stop("You requested adjacency list format, but the matrix provided has no (row) names.")
}
names <- rownames(matrix)
add <- getTableAddressing(names)
toReturn <- (cbind(add, x[upper.tri(x)]))
colnames(toReturn) <- c("Source", "Dest", "Symmetric")
return(toReturn)
}
}
Matrix library
> library(Matrix)
> essai <- matrix(data = 1:25, nrow = 5)
>
> forceSymmetric(x=essai, uplo="U")
5 x 5 Matrix of class "dsyMatrix"
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 6 7 12 17 22
[3,] 11 12 13 18 23
[4,] 16 17 18 19 24
[5,] 21 22 23 24 25
gdata library
> essai <- matrix(data = 1:25, nrow = 5)
> essai
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
>
>
> diag(essai) <- 0
> library("gdata")
> lowerTriangle(essai, diag=FALSE, byrow=FALSE) <- upperTriangle(essai, diag=FALSE, byrow=TRUE)
>
> essai
[,1] [,2] [,3] [,4] [,5]
[1,] 0 6 11 16 21
[2,] 6 0 12 17 22
[3,] 11 12 0 18 23
[4,] 16 17 18 0 24
[5,] 21 22 23 24 0
ENA and now HelpersMG library
A function symmetricize() was present in the package ENA, but this package is no more available (some dependencies do not exist anymore).
symmetricize {ENA}
Make a matrix symmetric
Description
Make the matrix symmetric by making all "mirrored" positions consistent. A variety of methods are provided to make the matrix symmetrical.
Usage
symmetricize(matrix, method = c("max", "min", "avg", "ld", "ud"), adjacencyList = FALSE)
Arguments
- matrix
- The matrix to make symmatric
- method
- The method to use to make the matrix symmetric. Default is to take the maximum.
- "max" For each position, m_{i,j}, use the maxiumum of (m_{i,j}, m_{j,i})
- "min" For each position, m_{i,j}, use the minimum of (m_{i,j}, m_{j,i})
- "avg" For each position, m_{i,j}, use the mean:
- "ld" Copy the lower triangular portion of the matrix to the upper triangular portion.
- "ud" Copy the upper triangular portion of the matrix to the lower triangular portion.
- adjacencyList
- Logical. If false, returns the symmetric matrix (the same format as the input). If true, returns an adjacency list representing the upper triangular portion of the adjacency matrix with addressing based on the row.names of the matrix provided.
Values
The symmetric matrix
Examples
#Create a sample 3x3 matrix mat <- matrix(1:9, ncol=3) #Copy the upper diagonal portion to the lower symmetricize(mat, "ud") #Take the average of each symmetric location symmetricize(mat, "avg")
Documentation reproduced from package ENA, version 1.3-0. License: GPL (>= 2)
symmetricize <-
function(matrix, method=c("max", "min","avg", "ld", "ud"), adjacencyList=FALSE){
method <- match.arg(method)
if (missing(matrix)){
stop("You must provide a matrix to symmetricize.")
}
x <- matrix
if (method=="ld"){
#solution from Michael Conklin, http://www.biostat.wustl.edu/archives/html/s-news/2000-03/msg00127.html
x[matrix(c(col(x)[lower.tri(x)], row(x)[lower.tri(x)]), ncol = 2)] <-
x[matrix(c(row(x)[lower.tri(x)], col(x)[lower.tri(x)]), ncol = 2)]
}
if (method=="ud"){
x[matrix(c(col(x)[upper.tri(x)], row(x)[upper.tri(x)]), ncol = 2)] <-
x[matrix(c(row(x)[upper.tri(x)], col(x)[upper.tri(x)]), ncol = 2)]
}
if (method=="max" || method=="min" || method=="avg"){
#retrieve the (row,col) indices for the lower-diagonal entries in the matrix
ldi <- matrix(c(row(x)[lower.tri(x)], col(x)[lower.tri(x)]), ncol = 2)
#already column-major, so we can leave this
#retrieve the (row,col) indices for the upper-diagonal entries in the matrix
udi <- matrix(c(row(x)[upper.tri(x)], col(x)[upper.tri(x)]), ncol = 2)
#in order for these to be in the symmetrical order as ldi, we need to sort.
udi <- udi[order(udi[,1], udi[,2]),]
#extract the upper and lower diagonal elements in a way that's symmetrical in their indexces
ud <- x[udi]
ld <- x[ldi]
#replace with either the min, max, or mean, depending on the selection
if (method=="max"){
x[ldi] <- apply(rbind(ld,ud),2,max);
x[udi] <- apply(rbind(ld,ud),2,max);
}
if (method=="min"){
x[ldi] <- apply(rbind(ld,ud),2,min);
x[udi] <- apply(rbind(ld,ud),2,min);
}
if (method=="avg"){
x[ldi] <- apply(rbind(ld,ud),2,mean);
x[udi] <- apply(rbind(ld,ud),2,mean);
}
}
if (!adjacencyList){
#return the adjacency matrix
return(x)
}
else{
#convert to adjacency list and add addressing
if (is.null(rownames(matrix))){
stop("You requested adjacency list format, but the matrix provided has no (row) names.")
}
names <- rownames(matrix)
add <- getTableAddressing(names)
toReturn <- (cbind(add, x[upper.tri(x)]))
colnames(toReturn) <- c("Source", "Dest", "Symmetric")
return(toReturn)
}
}
Commentaires
Enregistrer un commentaire