Проверьте, входит ли данное число в набор интервалов, определенных в фрейме данных

#r #dplyr

#r #dplyr

Вопрос:

У меня есть фрейм данных, который включает в себя 2 столбца, скажем, «левый» и «правый», которые определяют интервалы. Я хочу проверить, является ли данное число «x» частью любого интервала, определенного фреймом данных (если это так, оно должно быть только один раз, эти интервалы не перекрываются). Ожидаемое поведение:

 > df <- data.frame(id = c("A", "B", "C"), left = c(0, 50, 150), right = c(15, 78, 190))
> df
  id left right
1  A    0    15
2  B   50    78
3  C  150   190
> my_function(7)
TRUE
> my_function(20)
FALSE
 

Итак, я сделал это таким образом, но это ужасно медленно, и я уверен, что это можно было бы оптимизировать:

 my_function <- function(x) {
    test <- df %>% dplyr::rowwise() %>% dplyr::mutate(test = (x >= left) amp;amp; (x <= right)) %>% ungroup()
    test <- test %>% filter(test == T)
    nrow(test) == 1
}
 

Тогда мне было бы интересно получить соответствующую строку в случае, если вывод TRUE, но с текущей функцией это займет целую вечность (фактический фрейм данных содержит ~ 5000 строк, и я хочу проверить / получить координаты для тысяч значений x).

Я нашел библиотеку, которая управляет объектами интервалов, но, похоже, она адаптирована для временных интервалов. Есть предложения?

Ответ №1:

Вот простой способ с примером:

 z <- 567 # single dummy value
left <- x1 <- seq(100, 900, 200)
right <- seq(200, 1000, 200)
df <- data.frame(left, right) # dummy intervals

lo <- z >= df$left
hi <- z <= df$right
check <- lo * hi
introw <- which(check == 1)
introw
3

z2 <- c(356, 934, 134, 597, 771) # vector of values to check
lo2 <- sapply(z2, function(x) x >= df$left)
hi2 <- sapply(z2, function(x) x <= df$right)
check2 <- lo2 * hi2
introws <- apply(check2, 2, function(x) which(x ==1))
introws #vector of intervals for each input value
introws
2 5 1 3 4
final <- cbind(value = z2, interval = introws)
final
     value interval
[1,]   356        2
[2,]   934        5
[3,]   134        1
[4,]   597        3
[5,]   771        4
 

Комментарии:

1. Это действительно выглядит лучше, хотя все еще немного медленно user system elapsed 80.435 4.117 84.951

2. Я векторизовал свою функцию, поэтому я могу избавиться от rowwise() ungroup() вызовов and . Теперь намного быстрее! Спасибо user system elapsed 0.260 0.026 0.290

Ответ №2:

Попробуйте этот подход, используя between() :

 #Code
my_function <- function(x) {
  test <- df %>% dplyr::rowwise() %>%
    dplyr::mutate(test = between(x,left,right)) %>% ungroup()
  test <- test %>% filter(test == T)
  nrow(test) == 1
}
 

Комментарии:

1.Это так же медленно: user system elapsed 125.149 4.637 130.022 user system elapsed 135.310 4.640 140.233

2. @rioulan. Re: «Это так же медленно» Почему бы вам не попробовать мой ответ и не сообщить о результатах. Просто подключите свои собственные векторы для df$left , df$right и z2

3. О, ваш ответ исчез