Search code examples
radjacency-matrix

How to reduce resolution of adjacency matrix by grouping nodes


I have an adjacency matrix that expresses feeding links between species (column eats row)

mat1<-matrix(data=c(0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0), 
                nrow=4, 
                ncol=4, 
                byrow = TRUE,
                dimnames = list(c("a","b","c","d"), 
                                c("a","b","c","d")))

I want to reduce the resolution of this matrix to family level using a dataframe that shows which family each species belongs to,

df <- data.frame(Species = c("a","b","c","d"), Family = c("E","E","F","F"))

so that the resulting matrix will give the number of feeding links between families

mat2<-matrix(data=c(0,2,1,0), 
            nrow=2, 
            ncol=2, 
            byrow = TRUE,
            dimnames = list(c("E","F"), 
                            c("E","F")))

Thank you for your time


Solution

  • Because it's the only way I know how, here's a solution using the tidyverse.
    It turns the matrix into a long-form tibble, aggregates by family and then makes it wide again.

    library(tidyverse)
    
    # create a tibble that looks like the desired end-result matrix
    df2 <- mat1 %>% 
      as_tibble(rownames = "Species_from") %>% # make a tibble
      pivot_longer(cols = -Species_from,
                   names_to = "Species_to") %>% # turn into long form
      left_join(df, by = c("Species_from" = "Species")) %>% # add Family_from and Family_to
      left_join(df, by = c("Species_to" = "Species"), suffix = c("_from", "_to")) %>% 
      group_by(Family_from, Family_to) %>% # aggregate Family_from and Family_to
      summarise(value = sum(value)) %>% # ... by taking their sum
      pivot_wider(names_from = Family_to,
                  values_from = value) # turn back into wide form
    
    # turn into a matrix
    mat2 <- as.matrix(df2[, c("E", "F")])
    rownames(mat2) <- df2$Family_from
    
    mat2
    
    #   E F
    # E 0 2
    # F 1 0