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:

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 
    Package: 
     ENA 
    Version: 
     1.3-0 

    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")

    Author(s)

    Documentation reproduced from package ENA, version 1.3-0. License: GPL (>= 2)
    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)
        }
      }


    Commentaires

    Posts les plus consultés de ce blog

    Standard error from Hessian Matrix... what can be done when problem occurs

    stepAIC from package MASS with AICc

    Install treemix in ubuntu 20.04