2013-04-24 6 views
9

У меня есть следующий векторКак можно векторизовать доступ к соседним векторным элементам в R?

v = c(F, F, F, T, F, F, F, F, F, T, F, F, F) 

Как я могу изменить V так, что предыдущие 2 элементов и следующие 2 элементов каждого элемента ИСТИНЫ об также установлены в TRUE, используя векторизованные операции? То есть, результат должен быть:

F, T, T, T, T, T, F, T, T, T, T, T, F 

Конечно, это можно сделать с петлей на каждом элементе об, но я хочу понять, если это возможно, векторизации такого рода операций. Также отличные от this question элементы из v независимы, и мне не нужно выполнять вычисления на каждом из них. Это чистая проблема индексации.

ответ

11

Это рода вещей, вероятно, как векторный, как вы собираетесь получить:

v[unlist(sapply(which(v),function(x) {x + c(-2,-1,1,2)},simplify = FALSE))] <- TRUE 
> v 
[1] FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 

Но обратите внимание, что вы не указали, что должно произойти в подлинных элементах находятся вблизи кончики вектор. Для этого потребуется больше работы. Вы также не указываете, что произойдет, если есть два ИСТИННЫХ элемента, которые ближе друг к другу, чем две позиции.

В качестве альтернативы:

v[outer(which(v),c(-2,-1,1,2),"+")] <- TRUE 
> v 
[1] FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 

На базовом уровне, мы делаем то же самое здесь, но второй вариант, конечно, более компактный, хотя, возможно, труднее понять.

+1

Вы можете изменить его, чтобы включить эти ограничения: 'v [уникальный (as.vector (sapply (который (v), функция (х) {если (x> 2) {x + c (-2, -1,1,2)} else {1: (x + 2)}})))] <- TRUE' – harkmug

+1

@rmk Да, хотя это касается только левые конечные точки, я думаю. Разумеется, что-то подобное можно было бы сделать для другого конца, но тогда я думаю, что мы хотели бы отказаться от анонимной функции, я полагаю. – joran

+1

@rmk проверить эту тему для обсуждения того, как обрезать вектор по краям: http://stackoverflow.com/questions/16220521/how-to-trim-an-r-vector/16222580#16222580 –

3

Вот еще одна попытка. Он, похоже, работает с вашими данными, а также когда первый элемент имеет значение ИСТИНА.

as.logical(rowSums(embed(c(FALSE, FALSE, v, FALSE, FALSE), 5))) 
# [1] FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 

# another attempt with beginning and end TRUE 
v = c(T, F, F, F, F, F, T, F, F, F, F, F, T) 
# [1] TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE 

Подобно @ flodel задумке, можно было бы создать функцию здесь:

rollOR <- function(vec, dir="both", dist=2) { 
    stopifnot(dir %in% c("left", "right", "both")) 
    stopifnot(dist >= 0) 
    stopifnot(is.logical(vec)) 

    cvec <- rep(FALSE, dist) 
    switch(dir, 
     both = { 
      vec <- c(cvec, vec, cvec) 
      dist <- dist * 2 + 1 
     }, 
     left = { 
      vec <- c(vec, cvec) 
      dist <- dist + 1 
     }, 
     right = { 
      vec <- c(cvec, vec) 
      dist <- dist + 1 
     }) 

    as.logical(rowSums(embed(vec, dist))) 
} 
# direction both sides 
rollOR(v, "both", 2) 
# [1] FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 

# left alone 
rollOR(v, "left", 2) 
# [1] FALSE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE 

# right alone 
rollOR(v, "right", 2) 
# [1] FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE TRUE FALSE 
+0

+1 - очень хорошо! – flodel

5

Поздно партии ... Вы должны применить свертке фильтр а. Это будет быстрее, чем что угодно. Единственная трудность заключается в том, что на обоих концах вы должны добавить/добавить пару FALSE, чтобы фильтр не инициализировался с помощью NA. Вот функция, которая сделает это за вас:

within.distance <- function(x, d = 2) { 
    xxx <- c(rep(FALSE, d), x, rep(FALSE, d)) 
    yyy <- as.logical(filter(xxx, rep(1, 2*d+1))) 
    head(tail(yyy, -d), -d) 
} 

within.distance(v) 
# [1] FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
+1

Хорошее использование фильтра. –

+0

Доказательство того, что первый ответ не всегда лучший. Ницца. – joran

1

Еще один подход. Создать набор запаздывающих векторов и or их вместе:

library(Hmisc) 
library(functional) 
within.distance <- function(x, d=2) { 
    FLag <- function(x, shift) { 
    x <- Lag(x, shift) 
    x[is.na(x)] <- FALSE 
    return(x) 
    } 

    l <- lapply((-d):d, Curry(FLag, x=x)) 
    return(Reduce(`|`, l)) 
} 
Смежные вопросы