I'm trying to find a way in pandas to
- Merge adjacent (+1 day) or partly overlapping time intervals
- Remove rows with an interval that is inclusive
Here is an example of the Dataset that I'm using:
import pandas as pd
df = pd.DataFrame([
[42,1,'1990-01-01','2099-12-31'],
[42,2,'1990-01-01','2099-12-31'],
[42,2,'2010-10-01','2016-02-29'],
[42,2,'2011-09-01','2014-09-30'],
[42,2,'2012-04-01','2016-07-31'],
[42,2,'2013-04-01','2014-06-30'],
[42,2,'2013-09-01','2014-02-28'],
[42,2,'2014-03-01','2017-04-30'],
[42,2,'2014-10-01','2017-10-31'],
[42,2,'2015-04-01','2015-12-31'],
[42,2,'2016-03-01','2020-03-31'],
[42,2,'2016-08-01','2016-12-31'],
[42,2,'2017-01-01','2018-08-31'],
[42,2,'2017-05-01','2018-12-31'],
[42,2,'2017-11-01','2021-06-14'],
[42,2,'2018-09-01','2019-01-31'],
[42,2,'2019-02-01','2019-05-31'],
[42,2,'2019-04-01','2021-03-31'],
[42,2,'2019-06-01','2020-07-31'],
[42,2,'2020-08-01','2021-03-14'],
[42,2,'2021-03-15','2021-06-30'],
[43,1,'1998-01-01','2001-12-31'],
[43,1,'2010-03-15','2021-06-30'],
[43,1,'2021-01-01','2021-12-31'],
[43,2,'1998-01-01','1998-12-31'],
[43,2,'1999-01-01','2000-12-31'],
[43,2,'2001-01-01','2021-06-30']
], columns=['Id', 'SubId', 'Start', 'End'])
df['Start'] = pd.to_datetime(df['Start'])
df['End'] = pd.to_datetime(df['End'])
Expected Output
The data I expect:
42, 1, 1990-01-01, 2099-12-31
42, 2, 1990-01-01, 2099-12-31
43, 1, 1998-01-01, 2001-12-31
43, 1, 2010-03-15, 2021-12-31
43, 2, 1998-01-01, 2021-06-30
Tested (not correctly working) Solution
Based on the solution to a similar problem Pandas: Combine rows with consecutive dates (with NaT) within groups of same id I have implemented their solution, but it does not yield the expected result
df = df.sort_values(['Id', 'SubId', 'Start'])
day_diff = (df['Start'] - df['End'].groupby([df['Id'], df['SubId']]).shift()).dt.days
group_no = (day_diff.isna() | day_diff.gt(1)).cumsum()
df_out = (df.groupby(['Id', 'SubId', group_no], dropna=False, as_index=False)
.agg({'Id': 'first',
'SubId': 'first',
'Start': 'first',
'End': lambda x: x.iloc[-1]
}))
As far as I understand the solution will work fine if all intervals are adjacent to each other, but if there is an overarching interval it will not remember the overarching interval.
42 ,1 , 1990-01-01, 2099-12-31
42 ,2 , 1990-01-01, 2015-12-31 <-- Wrong End date; expected 2099-12-31
42 ,2 , 2016-03-01, 2021-06-30 <-- Wrong; Should no be there, but included in above
43 ,1 , 1998-01-01, 2001-12-31
43 ,1 , 2010-03-15, 2021-12-31
43 ,2 , 1998-01-01, 2021-06-30
What would be interesting to know is: If it would be possible to keep track of the min Start and max End while iterating over the same Id, SubId pair.