1

How can I create a Binary matrix in R where there is only one 1 in each row but it does not matter the number of ones in each column? I have this script but it is creating a random matrix. What I want is to specify the number of ones in the rows and columns:

mm <- matrix(0, 6, 5)
apply(mm, c(1, 2), function(x) sample(c(0, 1), 1))

Thanks

Edward
  • 10,360
  • 2
  • 11
  • 26
  • Please provide more information for others to be able to provide you an answer. This link https://stackoverflow.com/help/how-to-ask will be helpful to rephrase and improve your question. Also this for providing reproducible questions https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610#5963610 – M_Shimal Mar 08 '20 at 13:44

2 Answers2

1

You could sample the positions rather than their values.

set.seed(42)
t(apply(mm, 1, function(x) {x[sample(1:length(x), 1)] <- 1;x}))
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    0    0    0    0
# [2,]    0    0    0    0    1
# [3,]    1    0    0    0    0
# [4,]    1    0    0    0    0
# [5,]    0    1    0    0    0
# [6,]    0    0    0    1    0

Or using replicate,

set.seed(42)
t(replicate(6, sample(c(rep(0, 5 - 1), 1))))
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    1    0    0    0
# [2,]    0    0    1    0    0
# [3,]    0    0    1    0    0
# [4,]    0    1    0    0    0
# [5,]    0    0    1    0    0
# [6,]    1    0    0    0    0

which you also could wrap into a function.

genBin <- function(n.row, n.col) t(replicate(n.row, sample(c(rep(0, n.col - 1), 1))))

set.seed(42)
genBin(6, 5)
# # output as one above
jay.sf
  • 60,139
  • 8
  • 53
  • 110
1

Here we create a function, foo which creates a random vector of 0s and 1s, with only one 1 and the same length as the number of columns of the required matrix. Then, replicate this nrows.

nr <- 6; nc <- 5
foo <- function() sample(c(1, rep(0, nc-1)), nc)
t(replicate(nr, foo()))

Edit: To randomly assign one 1 to each row and one 1 to each column means that the matrix would need to be square. And one way to do this is to use the sparseMatrix function from the Matrix package.

library(Matrix)
args(sparseMatrix)
# function (i = ep, j = ep, p, x, dims, dimnames, symmetric = FALSE, 
#     triangular = FALSE, index1 = TRUE, giveCsparse = TRUE, check = TRUE, 
#     use.last.ij = FALSE)

The i and j specify the locations of the non-zero entries of the matrix. So we can specify these using sample(1:n) where n is the number of rows and columns of the square matrix.

set.seed(1234) # For reproducibility. Omit in reality.
A <- sparseMatrix(i=sample(1:4), j=sample(1:4))
# 4 x 4 sparse Matrix of class "ngCMatrix"          
# [1,] . | . .
# [2,] . . | .
# [3,] | . . .
# [4,] . . . |

Here the | represent non-zero values (TRUE).

The above matrix A can be converted into a binary matrix using as.matrix.

as.matrix(A) * 1
     [,1] [,2] [,3] [,4]
[1,]    0    1    0    0
[2,]    0    0    1    0
[3,]    1    0    0    0
[4,]    0    0    0    1
Edward
  • 10,360
  • 2
  • 11
  • 26