матрица% в% матрица - PullRequest
       9

матрица% в% матрица

14 голосов
/ 30 октября 2011

Предположим, у меня есть две матрицы, каждая с двумя столбцами и разными номерами строк.Я хочу проверить и посмотреть, какие пары одной матрицы находятся в другой матрице.Если бы они были одномерными, я бы просто сделал a %in% x, чтобы получить свои результаты.match, кажется, работает только с векторами.

> a
      [,1] [,2]
[1,]    1    2
[2,]    4    9
[3,]    1    6
[4,]    7    7
> x
     [,1] [,2]
[1,]    1    6
[2,]    2    7
[3,]    3    8
[4,]    4    9
[5,]    5   10

Я бы хотел, чтобы результат был c(FALSE,TRUE,TRUE,FALSE).

Ответы [ 5 ]

11 голосов
/ 30 октября 2011

Воссоздайте ваши данные:

a <- matrix(c(1, 2, 4, 9, 1, 6, 7, 7), ncol=2, byrow=TRUE)
x <- matrix(c(1, 6, 2, 7, 3, 8, 4, 9, 5, 10), ncol=2, byrow=TRUE)

Определите функцию %inm%, которая является матричным аналогом %in%:

`%inm%` <- function(x, matrix){
  test <- apply(matrix, 1, `==`, x)
  any(apply(test, 2, all))
}

Примените это к своим данным:

apply(a, 1, `%inm%`, x)
[1] FALSE  TRUE  TRUE FALSE

Для сравнения одной строки:

a[1, ] %inm% x
[1] FALSE

a[2, ] %inm% x
[1] TRUE
10 голосов
/ 30 октября 2011

Решение Андри прекрасно.Но если у вас большие матрицы, вы можете попробовать что-то еще, основанное на рекурсии.Если вы работаете по столбцам, вы можете сократить время расчета, исключив все, что не совпадает в первой позиции:

fastercheck <- function(x,matrix){
  nc <- ncol(matrix)
  rec.check <- function(r,i,id){
    id[id] <- matrix[id,i] %in% r[i]
    if(i<nc & any(id)) rec.check(r,i+1,id) else any(id)
  }
  apply(x,1,rec.check,1,rep(TRUE,nrow(matrix)))
}

Сравнение:

> set.seed(100)
> x <- matrix(runif(1e6),ncol=10)
> a <- matrix(runif(300),ncol=10)
> a[c(3,7,9,15),] <- x[c(1000,48213,867,20459),]
> system.time(res1 <- a %inm% x)
   user  system elapsed 
  31.16    0.14   31.50 
> system.time(res2 <- fastercheck(a,x))
   user  system elapsed 
   0.37    0.00    0.38 
> identical(res1, res2)
[1] TRUE
> which(res2)
[1]  3  7  9 15

РЕДАКТИРОВАТЬ:

Я проверил принятый ответ просто для удовольствия.Работает лучше, чем двойное применение (когда вы избавляетесь от внутреннего цикла), но рекурсия все еще правит!; -)

> system.time(apply(a, 1, paste, collapse="$$") %in% 
 + apply(x, 1, paste, collapse="$$"))
   user  system elapsed 
   6.40    0.01    6.41 
10 голосов
/ 30 октября 2011

Другой подход будет:

> paste(a[,1], a[,2], sep="$$") %in% paste(x[,1], x[,2], sep="$$")
[1] FALSE  TRUE  TRUE FALSE

Более общая версия этого:

> apply(a, 1, paste, collapse="$$") %in% apply(x, 1, paste, collapse="$$")
[1] FALSE  TRUE  TRUE FALSE
5 голосов
/ 31 октября 2011

Вот еще один подход, использующий пакет digest и создающий checksums для каждой строки, которые генерируются с использованием алгоритма хеширования (по умолчанию md5)

a <- matrix(c(1, 2, 4, 9, 1, 6, 7, 7), ncol=2, byrow=TRUE)
x <- matrix(c(1, 6, 2, 7, 3, 8, 4, 9, 5, 10), ncol=2, byrow=TRUE)
apply(a, 1, digest) %in% apply(x, 1, digest)

[1] FALSE  TRUE  TRUE FALSE
1 голос
/ 16 июля 2014

Позднее в игре: я ранее написал алгоритм с использованием метода «вставить с разделителем», а затем нашел эту страницу. Я предполагал, что один из фрагментов кода будет самым быстрым, но:

andrie<-function(mfoo,nfoo) apply(mfoo, 1, `%inm%`, nfoo)
# using Andrie's %inm% operator exactly as above
carl<-function(mfoo,nfoo) {
 allrows<-unlist(sapply(1:nrow(mfoo),function(j) paste(mfoo[j,],collapse='_'))) 
 allfoo <- unlist(sapply(1:nrow(nfoo),function(j) paste(nfoo[j,],collapse='_')))
 thewalls<-setdiff(allrows,allfoo)
 dowalls<-mfoo[allrows%in%thewalls,]
}

 ramnath <- function (a,x) apply(a, 1, digest) %in% apply(x, 1, digest)

 mfoo<-matrix( sample(1:100,400,rep=TRUE),nr=100)
 nfoo<-mfoo[sample(1:100,60),]

 library(microbenchmark)
 microbenchmark(andrie(mfoo,nfoo),carl(mfoo,nfoo),ramnath(mfoo,nfoo),times=5)

Unit: milliseconds
                expr       min        lq    median        uq            max neval
  andrie(mfoo, nfoo) 25.564196 26.527632 27.964448 29.687344     102.802004     5
    carl(mfoo, nfoo)  1.020310  1.079323  1.096855  1.193926       1.246523     5
 ramnath(mfoo, nfoo)  8.176164  8.429318  8.539644  9.258480       9.458608     5

Таким образом, очевидно, что создание символьных строк и выполнение одной операции над множеством происходит быстрее всего! (PS Я проверил и все 3 алгоритма дают одинаковый результат)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...