समूहों में अतिव्यापी अंतराल का पता लगाएं और सबसे बड़ी गैर-अतिव्यापी अवधि बनाए रखें
समस्या I ओवरलैपिंग अंतराल (ymd के रूप में दिनांक) के साथ एक समूहीकृत डेटाफ़्रेम है। मैं प्रत्येक समूह में केवल सबसे बड़े गैर-अतिव्यापी अंतराल को बनाए रखना चाहता हूं।
उदाहरण डेटा
# Packages
library(tidyverse)
library(lubridate)
# Example data
df <- tibble(
group = c(1, 1, 1, 2, 2, 3, 3, 3, 3),
start = as_date(
c("2019-01-10", "2019-02-01", "2019-10-05", "2018-07-01", "2019-01-01", "2019-10-01", "2019-10-01", "2019-11-30","2019-11-20")),
end = as_date(
c("2019-02-07", "2019-05-01", "2019-11-15", "2018-07-31", "2019-05-05", "2019-11-06", "2019-10-07", "2019-12-10","2019-12-31"))) %>%
mutate(intval = interval(start, end),
intval_length = intval / days(1))
df
#> # A tibble: 9 x 5
#> group start end intval intval_length
#> <dbl> <date> <date> <Interval> <dbl>
#> 1 1 2019-01-10 2019-02-07 2019-01-10 UTC--2019-02-07 UTC 28
#> 2 1 2019-02-01 2019-05-01 2019-02-01 UTC--2019-05-01 UTC 89
#> 3 1 2019-10-05 2019-11-15 2019-10-05 UTC--2019-11-15 UTC 41
#> 4 2 2018-07-01 2018-07-31 2018-07-01 UTC--2018-07-31 UTC 30
#> 5 2 2019-01-01 2019-05-05 2019-01-01 UTC--2019-05-05 UTC 124
#> 6 3 2019-10-01 2019-11-06 2019-10-01 UTC--2019-11-06 UTC 36
#> 7 3 2019-10-01 2019-10-07 2019-10-01 UTC--2019-10-07 UTC 6
#> 8 3 2019-11-30 2019-12-10 2019-11-30 UTC--2019-12-10 UTC 10
#> 9 3 2019-11-20 2019-12-31 2019-11-20 UTC--2019-12-31 UTC 41
# Goal
# Row: 1 and 2; 6 to 9 have overlaps; Keep rows with largest intervals (in days)
df1 <- df[-c(1, 7, 8),]
df1
#> # A tibble: 6 x 5
#> group start end intval intval_length
#> <dbl> <date> <date> <Interval> <dbl>
#> 1 1 2019-02-01 2019-05-01 2019-02-01 UTC--2019-05-01 UTC 89
#> 2 1 2019-10-05 2019-11-15 2019-10-05 UTC--2019-11-15 UTC 41
#> 3 2 2018-07-01 2018-07-31 2018-07-01 UTC--2018-07-31 UTC 30
#> 4 2 2019-01-01 2019-05-05 2019-01-01 UTC--2019-05-05 UTC 124
#> 5 3 2019-10-01 2019-11-06 2019-10-01 UTC--2019-11-06 UTC 36
#> 6 3 2019-11-20 2019-12-31 2019-11-20 UTC--2019-12-31 UTC 41
वर्तमान दृष्टिकोण मुझे एक और सूत्र में एक संबंधित प्रश्न मिला (देखें: समूह द्वारा अवधि अंतराल के भीतर तिथियां ढूंढें )। हालाँकि, संबंधित समाधान समूह द्वारा सभी अतिव्यापी पंक्तियों की पहचान करता है। इस तरह, मैं सबसे बड़े गैर-अतिव्यापी अंतराल की पहचान नहीं कर सकता।
df$overlap <- unlist(tapply(df$intval, #loop through intervals
df$group, #grouped by id
function(x) rowSums(outer(x,x,int_overlaps)) > 1))
एक उदाहरण के रूप में, मेरे उदाहरण डेटा में समूह 3 पर विचार करें। यहाँ पंक्ति 6/7 और 8/9 ओवरलैप होती है। पंक्ति 6 और 9 सबसे बड़ी गैर-अतिव्यापी अवधि होने के साथ, मैं पंक्ति 7 और 8 को निकालना चाहूंगा।
मैं बहुत सराहना करता हूं अगर कोई मुझे एक समाधान के लिए इंगित कर सकता है।
जवाब
स्टैकओवरफ़्लो पर संबंधित समस्याओं के लिए खोज करने के बाद, मैंने पाया कि निम्नलिखित दृष्टिकोण (यहां: समय अंतराल को संकुचित करें और मर्ज करें ) और (यहाँ: समयावधि ओवरलैपिंग / मर्ज कैसे करें ) मेरे मुद्दे के अनुकूल हो सकते हैं।
# Solution adapted from:
# here https://stackoverflow.com/questions/53213418/collapse-and-merge-overlapping-time-intervals
# and here: https://stackoverflow.com/questions/28938147/how-to-flatten-merge-overlapping-time-periods/28938694#28938694
# Note: df and df1 created in the initial reprex (above)
df2 <- df %>%
group_by(group) %>%
arrange(group, start) %>%
mutate(indx = c(0, cumsum(as.numeric(lead(start)) > # find overlaps
cummax(as.numeric(end)))[-n()])) %>%
ungroup() %>%
group_by(group, indx) %>%
arrange(desc(intval_length)) %>% # retain largest interval
filter(row_number() == 1) %>%
ungroup() %>%
select(-indx) %>%
arrange(group, start)
# Desired output?
identical(df1, df2)
#> [1] TRUE