Извлечь несколько диапазонов из числового вектора - PullRequest
0 голосов
/ 04 ноября 2018

Во-первых, я упрощаю свой вопрос. Я хочу извлечь определенные диапазоны из числового вектора. Например, извлечение 3 диапазонов из 1:20 одновременно:

  • 1
  • 8 <х <12 </li>
  • 17 <х <20 </li>

Следовательно, ожидаемый результат равен 2, 3, 4, 9, 10, 11, 18, 19.

Я пытаюсь использовать для этого функцию findInterval() и управляющие аргументы rightmost.closed и left.open, но любые наборы аргументов не могут достичь цели.

x <- 1:20
v <- c(1, 5, 8, 12, 17, 20)

x[findInterval(x, v) %% 2 == 1]
# [1]  1  2  3  4  8  9 10 11 17 18 19

x[findInterval(x, v, rightmost.closed = T) %% 2 == 1]
# [1]  1  2  3  4  8  9 10 11 17 18 19 20

x[findInterval(x, v, left.open = T) %% 2 == 1]
# [1]  2  3  4  5  9 10 11 12 18 19 20

Кстати, условия тоже могут быть в виде такой матрицы:

     [,1] [,2]
[1,]    1    5
[2,]    8   12
[3,]   17   20

Я не хочу использовать цикл for, если в этом нет необходимости.

Я благодарен за любую помощь.

Ответы [ 4 ]

0 голосов
/ 17 декабря 2018

Я нашел простой способ с sapply():

x <- 1:20
v <- c(1, 5, 8, 12, 17, 20)
(v.df <- as.data.frame(matrix(v, 3, 2, byrow = T)))

  #   V1 V2
  # 1  1  5
  # 2  8 12
  # 3 17 20

y <- sapply(x, function(x){
  ind <- (x > v.df$V1 & x < v.df$V2)
  if(any(ind)) x else NA
})

y[!is.na(y)]
# [1]  2  3  4  9 10 11 18 19
0 голосов
/ 04 ноября 2018

Вы были на правильном пути, и left.open действительно помогает, но rightmost.closed на самом деле касается только последнего интервала, а не правой "стороны" каждого интервала. Следовательно, нам нужно использовать left.open дважды. Как вы сами поняли, похоже, что оптимальный способ сделать это -

x[findInterval(x, v) %% 2 == 1 & findInterval(x, v, left.open = TRUE) %% 2 == 1]
# [1]  2  3  4  9 10 11 18 19

Очевидно, что есть альтернативы. Например.,

fun <- function(x, v)
  if(length(v) > 1) v[1] < x & x < v[2] | fun(x, v[-1:-2]) else FALSE
x[fun(x, v)]
# [1]  2  3  4  9 10 11 18 19
0 голосов
/ 04 ноября 2018

Вы можете использовать data.table::inrange и его аргумент incbounds. Предполагая, что диапазоны находятся в матрице 'm', как показано в вашем вопросе:

x[data.table::inrange(x, m[ , 1], m[ , 2], incbounds = FALSE)]
# [1]  2  3  4  9 10 11 18 19

 m <- matrix(v, ncol = 2, byrow = TRUE)
0 голосов
/ 04 ноября 2018

Я бы, вероятно, сделал это, используя purrr :: map2 или Map, передавая ваши нижние и верхние границы в качестве аргументов и фильтруя ваш набор данных с помощью пользовательской функции

library(purrr)
x <- 1:20
lower_bounds <- c(1, 8, 17)
upper_bounds <- c(5, 12, 20)
map2(
    lower_bounds, upper_bounds, function(lower, upper) {
        x[x > lower & x < upper]
    }
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...