Home > Software engineering >  Fill matrix where submatrices are dimensions of value in a vector (vector can be random numbers) in
Fill matrix where submatrices are dimensions of value in a vector (vector can be random numbers) in

Time:10-13

I have a matrix that will represent infection values of bats (can either be 1 or 0). The animals live in larger units ("roost", each roost is a submatrix), and the full matrix is the population. For starters, I am trying to fill my matrix with submatrices, values all equal to 1.

The code is currently working for roosts where number of bats is all the same. Ex:

# Define our variables
numRoosts = 3

# Uniformly sized roosts....
roostSizes = rep(3, numRoosts) # Each roost has 3 bats, looks like c(3, 3, 3)

# Adjaceny matrix describing connections between bats in all roosts

batAdjacencyMatrix <- as.data.frame(matrix(0, nrow = sum(roostSizes), ncol = sum(roostSizes)))
colnames(batAdjacencyMatrix) = rownames(batAdjacencyMatrix) = paste0("Bat_", 1:sum(roostSizes))

# Start filling in the network structure
n = 0
for(size in roostSizes){
  
  # Fill the submatrices with dimension 'size x size' with 1's to create the subroost network
  
  # Line below works for uniform roost sizes, but is buggy for nonuniform roost sizes
  batAdjacencyMatrix[(1 n*size):((n 1)*size), (1 n*size):((n 1)*size)] <- 1 # Matrix indexing
  
  # Increment the counter
  n = n   1
  
}

This gives me the output I wanted: enter image description here

The issue is when I try to change the roosts to nonuniform sizes:

numRoosts = 3

# If you want variable sized roosts....
minRoostPopulation = 2  # Min number of bats in a roost
maxRoostPopulation = 5  # Maximum number of bats in a roost
roostSizes <- round(runif(numRoosts, minRoostPopulation, maxRoostPopulation)) #Here c(5, 2, 4)

batAdjacencyMatrix <- as.data.frame(matrix(0, nrow = sum(roostSizes), ncol = sum(roostSizes)))
colnames(batAdjacencyMatrix) = rownames(batAdjacencyMatrix) = paste0("Bat_", 1:sum(roostSizes))

# Start filling in the network structure
n = 0
for(size in roostSizes){
  
  # Fill the submatrices with dimension 'size x size' with 1's to create the subroost network
  
  # Line below works for uniform roost sizes, but is buggy for nonuniform roost sizes
  batAdjacencyMatrix[(1 n*size):((n 1)*size), (1 n*size):((n 1)*size)] <- 1 # Matrix indexing
  
  # Increment the counter
  n = n   1
  
}

enter image description here

There's something wrong with the indexing in my for loop- I can see when I put the numbers in manually. But I can't figure out how to define my submatrices so that the next number in the vector shifts down/right to the end of the matrix prior. Any thoughts? Thanks in advance!

CodePudding user response:

Your indexing is indeed somewhat off. If I were to modify your approach, I would do it like this:

numRoosts = 3
roostSizes <- c(5, 2, 4)
batAdjacencyMatrix <- as.data.frame(matrix(0, nrow = sum(roostSizes), ncol = sum(roostSizes)))
colnames(batAdjacencyMatrix) = rownames(batAdjacencyMatrix) = paste0("Bat_", 1:sum(roostSizes))

# Start filling in the network structure
n = 0
for(size in roostSizes){
  
  # sum of sizes of preceding roosts
  size.prior <- sum(head(roostSizes, n))
  # indices of the current roost
  ind <- size.prior   (1:size)
  batAdjacencyMatrix[ind, ind] <- 1 # Matrix indexing
  
  # Increment the counter
  n = n   1
}

However, an easier way is to use magic::adiag() which can build such block-diagonal matrices:

library(magic)
roostSizes <- c(5, 2, 4)
# create the three matrices of 1's
mat <- lapply(roostSizes, function(n) matrix(1, n, n))
# bind them diagonally
batAdjacencyMatrix <- do.call(adiag, mat)
rownames(batAdjacencyMatrix) <- colnames(batAdjacencyMatrix) <- 
  paste0('Bat_', seq_len(sum(roostSizes)))
  • Related