Есть ли функция для проверки, перекрывается ли временной интервал в одном столбце, и сортировка по группе в R - PullRequest
1 голос
/ 13 февраля 2020

У меня большой набор данных, и я пытаюсь найти, где временные интервалы перекрываются группой. Чтобы еще больше усложнить ситуацию, я надеюсь, что код может быть интегрирован с функцией group_by 'dplyr', чтобы перекрывающиеся времена не путались с другими идентификаторами.

Я пытался использовать перекрывающуюся функцию "int_overlaps (int1, int2) "from" lubridate ", но это не работает для одного столбца. Любые другие перекрывающиеся функции не работают с временными интервалами.

library(lubridate)

id <- c(1,1,1,2,2)
start <-as.POSIXct(c("2017-06-27 09:30:00","2017-06-27 15:30:00",
                     "2017-06-27 14:30:00","2017-06-28 09:30:00","2017-06-28 15:00:00"),tz= "UTC")
end <-as.POSIXct(c("2017-06-27 10:30:00","2017-06-27 17:30:00",
                   "2017-06-27 18:30:00","2017-06-28 10:30:00","2017-06-28 16:00:00"),tz= "UTC")
inter1<- interval(start,end,tz="UTC")

df <- data.frame(id,inter1)

overlap <- c(FALSE,TRUE,TRUE,FALSE,FALSE)

new_df<-data.frame(id,inter1,overlap)

Ответы [ 2 ]

1 голос
/ 13 февраля 2020

Данные выборки не имеют перекрывающихся периодов. Было внесено следующее изменение:

start <-as.POSIXct(c("2017-06-27 09:30:00","2017-06-27 15:30:00",
                     "2017-06-27 14:30:00","2017-06-28 09:30:00","2017-06-28 15:00:00"), tz= "UTC")

Использование lead вернет NA, если это последняя запись в группе

library(dplyr)

new_df %>%
  group_by(id) %>%
  arrange(int_start(inter1), .by_group = TRUE) %>%
  mutate(overlap2 = lead(int_start(inter1)) < int_end(inter1))

# A tibble: 5 x 4
# Groups:   id [2]
     id inter1                                           overlap overlap2
  <dbl> <Interval>                                       <lgl>   <lgl>   
1     1 2017-06-27 09:30:00 UTC--2017-06-27 10:30:00 UTC FALSE   FALSE   
2     1 2017-06-27 14:30:00 UTC--2017-06-28 18:30:00 UTC TRUE    TRUE    
3     1 2017-06-27 15:30:00 UTC--2017-06-27 17:30:00 UTC TRUE    NA      
4     2 2017-06-28 09:30:00 UTC--2017-06-28 10:30:00 UTC FALSE   FALSE   
5     2 2017-06-28 15:00:00 UTC--2017-06-28 16:00:00 UTC FALSE   NA 

Если необходимо сравнить каждую строку со всеми строки в группе

library(tidyverse)

new_df %>%
  group_by(id) %>%
  arrange(int_start(inter1), .by_group = TRUE) %>%
  mutate(overlap2 = map_int(inter1, ~ sum(int_overlaps(.x, inter1))) > 1)

# A tibble: 5 x 4
# Groups:   id [2]
     id inter1                                           overlap overlap2
  <dbl> <Interval>                                       <lgl>   <lgl>   
1     1 2017-06-27 09:30:00 UTC--2017-06-27 10:30:00 UTC FALSE   FALSE   
2     1 2017-06-27 14:30:00 UTC--2017-06-28 18:30:00 UTC TRUE    TRUE    
3     1 2017-06-27 15:30:00 UTC--2017-06-27 17:30:00 UTC TRUE    TRUE    
4     2 2017-06-28 09:30:00 UTC--2017-06-28 10:30:00 UTC FALSE   FALSE   
5     2 2017-06-28 15:00:00 UTC--2017-06-28 16:00:00 UTC FALSE   FALSE 
1 голос
/ 13 февраля 2020

1) sqldf Предполагая, что вы хотите перекрывать только время, а не даты, замените inter1 на start, end, а также время начала и окончания, time1 и time2, давая new_df1. Затем выполните самообъединение на id и группировку условий перекрытия по rowid. overlap ИСТИНА, если число совпадающих строк превышает 1 (поскольку само перекрытие не учитывается).

library(dplyr)
library(lubridate)
library(sqldf)

new_df1 <- new_df %>% 
  mutate(
    start = int_start(inter1),
    end = int_end(inter1),
    time1 = sub(".* ", "", start),
    time2 = sub(".* ", "", end),
    inter1 = NULL
  )

sqldf("select a.id, a.start, a.end, count(*) > 1 as overlap
  from new_df1 a 
  join new_df1 b on a.id = b.id and
    (a.time1 between b.time1 and b.time2 or b.time1 between a.time1 and a.time2)
  group by a.rowid")

, что дает:

  id               start                 end overlap
1  1 2017-06-27 05:30:00 2017-06-27 06:30:00   FALSE
2  1 2017-06-27 11:30:00 2017-06-27 13:30:00    TRUE
3  1 2017-06-28 10:30:00 2017-06-28 14:30:00    TRUE
4  2 2017-06-28 05:30:00 2017-06-28 06:30:00   FALSE
5  2 2017-06-28 11:00:00 2017-06-28 12:00:00   FALSE

2) Это формирует полное соединение ni x ni для каждого идентификатора i, а затем отфильтровывает его и группирует как второй и третий этап, тогда как (1) делает все это одновременно, в зависимости от SQL оптимизаций, применяемых программным обеспечением базы данных (1 ) может быть гораздо более эффективным. В любом случае, это включается в id, а затем фильтрует условие перекрытия и, наконец, выполняет подсчет. new_df1 от (1).

new_df1 %>%
  mutate(rowid = 1:n()) %>%
  inner_join(new_df1, by = "id", suffix = c("", ".y")) %>%
  filter((time1 >= time1.y & time1 <= time2.y) | 
    (time1.y >= time1 & time1.y <= time2)) %>%
  count(rowid, id, start, end) %>%
  mutate(overlap = n > 1) %>%
  select(id, start, end, overlap)

давая:

# A tibble: 5 x 4
  rowid start               end                 overlap
  <int> <dttm>              <dttm>              <lgl>  
1     1 2017-06-27 09:30:00 2017-06-27 10:30:00 FALSE  
2     2 2017-06-27 15:30:00 2017-06-27 17:30:00 TRUE   
3     3 2017-06-28 14:30:00 2017-06-28 18:30:00 TRUE   
4     4 2017-06-28 09:30:00 2017-06-28 10:30:00 FALSE  
5     5 2017-06-28 15:00:00 2017-06-28 16:00:00 FALSE  

Примечание

Постер изменил вопрос после того, как на него уже был дан ответ, но в любом случае мы использовали это в качестве ввода.

new_df <-
structure(list(id = c(1, 1, 1, 2, 2), inter1 = new("Interval", 
    .Data = c(3600, 7200, 14400, 3600, 3600), start = structure(c(1498555800, 
    1498577400, 1498660200, 1498642200, 1498662000), tzone = "UTC", 
    class = c("POSIXct", 
    "POSIXt")), tzone = "UTC"), overlap = c(FALSE, TRUE, TRUE,
    FALSE, FALSE)), class = "data.frame", row.names = c(NA, -5L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...