Tobias Dekker
Tobias Dekker

Reputation: 1030

Create a list of matrices with 1's / 0's based on a list of matrices with the index

I have the following problem: I do have a lists with matrices with indices. Every column of a matrix shows which row indices should be equal to 1 for that specific column. All the other values should be equal to 0. I do know the size of the output matrices and there are no duplicated values in a column. For example the following matrix should be translated as follows:

m_in  = matrix(c(1,3,5,7,3,4), nrow =2)
m_out = matrix(c(1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0), nrow = 7)

I did made a code that works, but it would be great if I could achieve this without loops in a more efficient/clever way.

  Index <- matrix(20, 100, data = sample(1:200))
  Vector <- c(2,3,5,8,20)
  ListIndices <- sapply(Vector, function(x)Index[0:x,])
  emptylistlist <- list()
  for (i in 1: length(ListIndices)){
    for (j in 1 : 100){  
      emptylistlist[[i]] <- matrix(nrow = 200, ncol = 100, data = 0) 
      emptylistlist[[i]][ListIndices[[i]],j]<-1
    }
  }

Upvotes: 1

Views: 184

Answers (2)

Frank
Frank

Reputation: 66819

The typical way is with matrix assignment:

m_out = matrix(0L, max(m_in), ncol(m_in))

m_out[cbind(c(m_in), c(col(m_in)))] <- 1L

How it works: The syntax for matrix assignment M[IND] <- V is described at help("[<-").

  • Each row of IND is a pair of (row, column) positions in M.
  • Elements of M at those positions will be overwritten with (corresponding elements of) V.

As far as the list of matrices goes, an array would be more natural:

set.seed(1)
Index <- matrix(20, 100, data = sample(1:200))
Vector <- c(2,3,5,8,20)
idx    <- sapply(Vector, function(x)Index[0:x,])
# "ListIndices" is too long a name

a_out = array(0L, dim=c(
  max(unlist(idx)), 
  max(sapply(idx,ncol)),
  length(idx)))

a_out[ cbind( 
  unlist(idx),
  unlist(lapply(idx,col)),
  rep(seq_along(idx),lengths(idx))
)] <- 1L

The syntax is the same as for matrix assignment.

Seeing as the OP has so many zeros and so few ones, a sparse matrix, as in @akrun's answer makes the most sense, or a sparse array, if such a thing has been implemented.

Upvotes: 1

akrun
akrun

Reputation: 887501

We can try sparseMatrix from library(Matrix) and then wrap it with as.matrix.

library(Matrix)
as.matrix(sparseMatrix(i= c(m1), j= c(col(m1)), x=1))
#      [,1] [,2] [,3]
#[1,]    1    0    0
#[2,]    0    0    0
#[3,]    1    0    1
#[4,]    0    0    1
#[5,]    0    1    0
#[6,]    0    0    0
#[7,]    0    1    0

If there is a list of matrices, then we can use lapply

lapply(lst, function(y) as.matrix(sparseMatrix(i= c(y), j= c(col(y)), x= 1)))

Upvotes: 3

Related Questions