Найти ближайшие неперекрывающиеся диапазоны от начала до конца

#r #dplyr #iranges

#r #dplyr #iranges

Вопрос:

Я хотел бы найти ближайшие диапазоны, которые не перекрываются от первого начала до последней конечной позиции. Есть идеи, как поступить? В приведенном ниже примере c (8, 33) и c (155, 161) должны быть отфильтрованы, поскольку они перекрываются с предыдущим диапазоном.

 #Example data
df <- data.frame(
  start = c(7,8,14,34,67,92,125,155,170,200),
  end = c(13,33,25,66,91,124,155,161,181,214)
)

   start end
1      7  13
2      8  33
3     14  25
4     34  66
5     67  91
6     92 124
7    125 155
8    155 161
9    170 181
10   200 214

#Overlapping rows
  start end
1     8  33
2   155 161

#Desired output where overlapping rows are filtered away
  start end
1     7  13
2    14  25
3    34  66
4    67  91
5    92 124
6   125 155
7   170 181
8   200 214
  

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

1. Строка 3, 14 25 перекрывается со строкой 2 8, 33, но она не удаляется?

Ответ №1:

Я бы сделал это как простой цикл, поскольку исключение строки зависит от результата вычисления для предыдущей строки

 i <- 2

while(i < nrow(df)) {
  if(df$start[i] <= df$end[i - 1]) {
    df <- df[-i,] 
  } else { 
    i <- i   1
  }
}

df
#>    start end
#> 1      7  13
#> 3     14  25
#> 4     34  66
#> 5     67  91
#> 6     92 124
#> 7    125 155
#> 9    170 181
#> 10   200 214
  

Ответ №2:

Я пошел со следующим ответом, опубликованным на веб-сайте сообщества R.:

 find_nonover <- function(df) {
  to_drop <- logical(nrow(df))
  for (i in seq_along(df[["end"]])) {
    if (i %in% which(to_drop)) next
    to_drop <- to_drop | c(logical(i), df[i, "end"] >= df[["start"]][-seq_len(i)])
  }
  list(nonover = df[!to_drop, ],
       over    = df[to_drop, ])
}
  

https://community.rstudio.com/t/find-closest-non-overlapping-ranges-from-start-to-end/79642/3

Ответ №3:

Поскольку ваш start столбец был в порядке возрастания, вы можете проверить перекрытие только по значениям end , например,

 repeat {
  ind <- with(df, head(which(!c(TRUE,end[-nrow(df)]<start[-1])),1))
  if (!length(ind)) break
  df <- df[-ind,]
}
  

что дает

 > df
   start end
1      7  13
3     14  25
4     34  66
5     67  91
6     92 124
7    125 155
9    170 181
10   200 214
  

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

1. очень хорошо, но это не сработало бы для следующей последовательности: df <- data.frame(start = c(7,8,100), end = c(8,100,101))

2. @Nivel Тогда каков ваш желаемый результат?

3. Желаемый результат был бы start = c (7, 100), end = c(8, 101). Если я использую вашу формулу, также отбрасывается последняя строка.

4. @Nivel Кажется, вы все равно сохраняете последнюю строку. Пожалуйста, ознакомьтесь с моим обновлением

5. Извините, но это все еще не дает правильного вывода. Рассмотрим следующее: df <- data.frame(начало = c (7,8,10,12,14), конец = c (16,9,11,13,15)). Желаемый результат — start = 7 и end = 16.