Сопоставьте вектор внутри вектора

У меня есть:

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.

вам нужно делать это только с числами? Насколько важна скорость?

Calum You 30.05.2018 22:09

@Calum Да, я бы предпочел числовой вывод.

Wencheng Lau-Medrano 30.05.2018 22:11

@ WenchengLau-Medrano Хороший вопрос. У тебя так много оставленных вопросов. Вы можете принять ответы на эти вопросы, чтобы они были полезны будущим пользователям. Спасибо большое.

MKR 30.05.2018 22:31

связанные с stackoverflow.com/questions/48660606/…

chinsoon12 31.05.2018 02:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
4
120
7

Ответы 7

Вот один способ, но он не будет хорошо масштабироваться, если длина 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

Спасибо, но, конечно, пример, который я привел, предназначен только для быстрого объяснения моей проблемы. В моих реальных данных vec1 - это вектор длины 10k, а vec2 - вектор переменной длины (2-10).

Wencheng Lau-Medrano 30.05.2018 22:15

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

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

Цикл for будет самым быстрым решением (помимо использования 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

Очевидно, что ответ на основе for-loop будет быстрее :-)

MKR 30.05.2018 22:43

Вы жмете на векторах длины 3/10? Думаю, это будет быстро, даже если запустить в Excel

David Arenburg 30.05.2018 23:16

Векторов длины 10k / 5.

thc 31.05.2018 07:10

Можно использовать пакет 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

Обратите внимание, что мы можем написать: which(rollapply(vec1, length(vec2), identical, vec2, align = "left")).

G. Grothendieck 31.05.2018 23:41

@ G.Grothendieck Очень верное замечание. На самом деле, я изменил свой код, чтобы использовать эту альтернативу, пытаясь повысить производительность, но это не сильно улучшилось. Следовательно, я не думал об обновлении. Хорошо, что вы сегодня отметили. Я обновлю свой ответ сейчас. Спасибо.

MKR 01.06.2018 00:02

Общее решение, где 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

Вот еще один метод с использованием 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

Вот попытка векторизовать это с помощью пакета 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

в базе R:

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

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

Другие вопросы по теме