Is there an efficient way in R to "paste" each row of a matrix M2 onto each row of a matrix M1 to obtain all possible combinations?

Viewed 35

Say I have two matrices:

M1 <- matrix(letters[1:9], nrow = 3, ncol = 3, byrow = T)
M2 <- matrix(letters[10:18], nrow = 3, ncol = 3, byrow = T)

In reality I have much larger matrices with 1000 rows. What I'd like is an efficient way to produce the following without using for loops as this causes R to crash.

result <- rbind(cbind(M1, matrix(rep(letters[10:12], 3), nrow = 3, ncol = 3, byrow = T)),
                cbind(M1, matrix(rep(letters[13:15], 3), nrow = 3, ncol = 3, byrow = T)),
                cbind(M1, matrix(rep(letters[16:18], 3), nrow = 3, ncol = 3, byrow = T)))

Essentially "paste" every row of M2 onto every row of M1 so that I have every possible combination.

2 Answers

You can use expand.grid to create all possible combinations of row indices in M1 and M2.

mat <- expand.grid(1:nrow(M1), 1:nrow(M2))
cbind(M1[mat[[1]], ], M2[mat[[2]], ])

#     [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] "a"  "b"  "c"  "j"  "k"  "l" 
# [2,] "d"  "e"  "f"  "j"  "k"  "l" 
# [3,] "g"  "h"  "i"  "j"  "k"  "l" 
# [4,] "a"  "b"  "c"  "m"  "n"  "o" 
# [5,] "d"  "e"  "f"  "m"  "n"  "o" 
# [6,] "g"  "h"  "i"  "m"  "n"  "o" 
# [7,] "a"  "b"  "c"  "p"  "q"  "r" 
# [8,] "d"  "e"  "f"  "p"  "q"  "r" 
# [9,] "g"  "h"  "i"  "p"  "q"  "r" 

You could try RcppAlgos::permuteGeneral which is much faster than expand.grid.

FUN <- function(M1, M2) {
  stopifnot(all.equal(dim(M1), dim(M2)))
  p <- RcppAlgos::permuteGeneral(seq.int(dim(M1)[1]), 2, repetition=T)
  cbind(M1[p[,2],], M2[p[,1],])
}
FUN(M1, M2)
#     [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] "a"  "b"  "c"  "j"  "k"  "l" 
# [2,] "d"  "e"  "f"  "j"  "k"  "l" 
# [3,] "g"  "h"  "i"  "j"  "k"  "l" 
# [4,] "a"  "b"  "c"  "m"  "n"  "o" 
# [5,] "d"  "e"  "f"  "m"  "n"  "o" 
# [6,] "g"  "h"  "i"  "m"  "n"  "o" 
# [7,] "a"  "b"  "c"  "p"  "q"  "r" 
# [8,] "d"  "e"  "f"  "p"  "q"  "r" 
# [9,] "g"  "h"  "i"  "p"  "q"  "r" 

Benchmark

# Unit: microseconds
#        expr     min       lq      mean   median      uq       max neval cld
# expand.grid 147.724 151.4235 628.38420 154.8680 157.291 46840.374   100   a
#   RcppAlgos  74.500  77.4340  84.75624  80.1125  82.409   238.807   100   a
Related