Сопоставить вектор внутри вектора - PullRequest
0 голосов
/ 30 мая 2018

У меня есть:

vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)

Я ожидаю:

magicFUN(x = vec1, y = vec2)
[1] 4 7 8

Это означает, что я хочу положение полного вектора внутри другого вектора.match и is.element были бесполезны, потому что они возвращают позицию каждого элемента vec2, и мне нужно, чтобы magicFUN соответствовал полному vec2 в vec1.

Ответы [ 7 ]

0 голосов
/ 31 мая 2018

Вот попытка векторизовать это, используя пакет data.table.Хотя, если vec2 становится очень длинным, у него могут возникнуть проблемы с памятью, потенциально

library(data.table)
l2 <- length(vec2)
setDT(shift(vec1, 0 : (l2 - 1), type = "lead")
      )[, which(rowSums(.SD == vec2[col(.SD)]) == l2)]
## [1] 4 7 8
0 голосов
/ 02 июня 2018

в базе R:

which(sapply(seq_along(vec1),function(x) identical(vec1[x:(x+1)],vec2)))
# [1] 4 7 8

Должны поддерживать списки и любой тип данных.

0 голосов
/ 30 мая 2018

Вот еще один метод, использующий grep:

vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)

magicFUN = function(x, y){
  y_len = length(y)
  temp_x = do.call(paste, lapply((y_len-1):0, function(lags){
    lag(x, lags)[-(0:(y_len-1))]
  }))
  temp_y = paste(y, collapse = ' ')
  return(grep(temp_y, temp_x, fixed = TRUE))
}

magicFUN(vec1, vec2)
# [1] 4 7 8
0 голосов
/ 30 мая 2018

Общее решение, где a - более длинный вектор, а b - более короткий

magicFun <- function(a,b){
  la <- length(a)
  lb <- length(b)
  out <- vector(mode = "numeric", length = la-1)
  for(i in 1:(la-lb)) {
    out[i] <- ifelse(all(a[i:(i+lb-1)] == b),i,0)
  }
  out <- out[out != 0]
  return(out)
}

magicFun(vec1,vec2)

[1] 4 7 8
0 голосов
/ 30 мая 2018

Можно использовать пакет zoo как:

library(zoo)
which(c(rollapply(vec1, width=2, function(x)all(x==vec2), align = "left"),0)==TRUE)
[1] 4 7 8

Отредактировано: Основано на отзывах от @G.Grothendieck:

Приведенное выше решение может масштабироватьсяс помощью length(vec2).Давайте создадим magicFUN как:

magicFUN <- function(vec1, vec2){
  which(rollapply(vec1, length(vec2), identical, vec2, align = "left"))
}    

magicFUN(vec1, vec2)
#[1] 4 7 8
0 голосов
/ 30 мая 2018

Общее решение:

magicFUN <- function(vec1, vec2) {
  if(length(vec2) > length(vec1)) stop("vec 2 should be shorter")
  len <- length(vec1) - length(vec2) + 1
  out <- vector(mode = "logical", length=len)     
  for(i in 1:len) {
    out[i] <- identical(vec2, vec1[i:(i+length(vec2)-1)])
  }
  return(which(out))
}

vec1 <- c(0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1)
vec2 <- c(1, 1)

magicFUN(vec1, vec2)

[1] 4 7 8

А для цикла будет самым быстрым решением (кроме использования Rcpp).См. Контрольные показатели ниже:

magicFUN <- function(vec1, vec2) {
  if(length(vec2) > length(vec1)) stop("vec 2 should be shorter")
  len <- length(vec1) - length(vec2) + 1
  out <- vector(mode = "logical", length=len)     
  for(i in 1:len) {
    out[i] <- identical(vec2, vec1[i:(i+length(vec2)-1)])
  }
  return(which(out))
}

magicFUN2 <- function(vec1, vec2){
  l1 <- length(vec1)
  l2 <- length(vec2)
  which(colSums(sapply(1:(l1-l2), function(i) vec1[i:(i+l2-1)]) == vec2) == l2)
}

magicFUN3 <- function(vec1, vec2){
  which(c(zoo::rollapply(vec1, width=length(vec2), 
                    function(x)all(x==vec2), align = "left"),rep(FALSE,length(vec2)-1))==TRUE)
}

library(microbenchmark)
microbenchmark(magicFUN(vec1, vec2), magicFUN2(vec1, vec2), magicFUN3(vec1, vec2))

Unit: milliseconds
                  expr       min        lq      mean    median        uq       max neval cld
  magicFUN(vec1, vec2)  6.083572  6.575844  7.292443  6.878016  7.421208  13.35746   100  a 
 magicFUN2(vec1, vec2)  8.289640  8.976736 11.007967  9.338644  9.951492 139.68886   100  a 
 magicFUN3(vec1, vec2) 39.131268 42.369479 46.303722 44.203563 45.053252 172.46151   100   b
0 голосов
/ 30 мая 2018

Это один из способов, но он не будет хорошо масштабироваться, если длина vec2 увеличится:

which(head(vec1, -1) == vec2[1] & tail(vec1, -1) == vec2[2])
# [1] 4 7 8

Редактировать: Более общее решение.

magicFUN <- function(vec1, vec2){
  l1 <- length(vec1)
  l2 <- length(vec2)
  which(colSums(sapply(1:(l1-l2), function(i) vec1[i:(i+l2-1)]) == vec2) == l2)
}

magicFUN(vec1, vec2)
# [1] 4 7 8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...