Intersection of two integer matrices by position R

Viewed 80

I would like to know which positions of one matrix intersect with another matrix and which values, for example

lab <- as.matrix(read.table(text="[1,]    0    0    0    0    0    0    0    0    0     1
 [2,]    2    0    2    2    2    2    2    2    2     0
 [3,]    2    0    2    0    0    0    0    0    2     2
 [4,]    2    2    2    0    0    0    0    0    2     2
 [5,]    2    0    2    0    0    0    0    0    0     0
 [6,]    2    0    2    0    0    0    0    0    0     0
 [7,]    2    0    2    0    0    0    0    0    0     0
 [8,]    2    0    2    0    0    0    0    3    3     3
 [9,]    2    0    2    0    0    0    0    0    3     3
[10,]    2    0    2    0    0    0    0    0    0     3")[,-1])
str(lab)

la1 <- as.matrix(read.table(text="[1,]    0    1    0    0    0    0    0    0    0     2
 [2,]    3    0    4    4    4    4    4    4    4     0
 [3,]    3    0    4    0    0    0    0    0    4     4
 [4,]    3    0    4    0    5    5    0    0    4     4
 [5,]    3    0    4    0    5    5    0    0    0     0
 [6,]    3    0    4    0    0    0    0    0    0     0
 [7,]    3    0    4    0    0    0    0    0    0     0
 [8,]    3    0    4    0    0    0    0    6    6     6
 [9,]    3    0    4    0    0    0    0    6    6     6
[10,]    3    0    4    0    0    0    0    0    0     6")[,-1])

Then, these numbers represent patches, patch 3 of la1 intersect patch 3 and 4 of la1, patch 1 of lab intersect 0 (no other patch), patch 3 of lab intersect patch 6 of la1. I am using the following code

require(dplyr)
tuples <- tibble()
dx <- dim(lab)[1]
for( i in seq_len(dx))
  for( j in seq_len(dx))
  {
     ii <- tibble(l0=lab[i,j],l1=la1[i,j])
     tuples <- bind_rows(tuples,ii)
  }
tuples %>% distinct()

As I will use big 3000x3000 matrices so I am thinking if there is any faster way, maybe with rcpp or raster, of doing it.

3 Answers

Without a double for loop, we can transpose the matrixes into a two column tibble and get the distinct rows

out <- tibble(l0 = c(t(lab)), l1 = c(t(la1))) %>%
            distinct

-checking with OP's output

out_old <- tuples %>% 
              distinct()
all.equal(out, out_old, check.attributes = FALSE)
#[1] TRUE

Benchmarks

lab2 <- matrix(sample(0:9, size = 3000 * 3000, replace = TRUE), 3000, 3000)
la2 <- matrix(sample(0:9, size = 3000 * 3000, replace = TRUE), 3000, 3000)
system.time({out2 <- tibble(l0 = c(t(lab2)), l1 = c(t(la2))) %>%
             distinct})
#   user  system elapsed 
#  0.398   0.042   0.440 

If you just want to speed up, you can try unique over data.table, e.g.,

unique(data.table(c(lab), c(la)))

Here comes a base R solution.

as.vector might be faster than c.

unique(cbind(as.vector(lab), as.vector(la1)))
#      [,1] [,2]
# [1,]    0    0
# [2,]    2    3
# [3,]    0    1
# [4,]    2    0
# [5,]    2    4
# [6,]    0    5
# [7,]    3    6
# [8,]    0    6
# [9,]    1    2
Related