我在 pandas 数据框中有一些数据,其中包含排名列、开始日期和结束日期。数据按从低到高的排名列排序(因此开始/结束日期是无序的)。我希望删除日期范围与任何先前行重叠的每一行”
通过玩具示例:
原始数据
Rank Start_Date End_Date
1 1/1/2021 2/1/2021
2 1/15/2021 2/15/2021
3 12/7/2020 1/7/2021
4 5/1/2020 6/1/2020
5 7/10/2020 8/10/2020
6 4/20/2020 5/20/2020
期望的结果
Rank Start_Date End_Date
1 1/1/2021 2/1/2021
4 5/1/2020 6/1/2020
5 7/10/2020 8/10/2020
解释:第 2 行被删除,因为它的开头与第 1 行重叠,第 3 行被删除,因为它的结尾与第 1 行重叠。第 4 行被保留,因为它不与任何先前保留的行(即第 1 行)重叠。同样,保留第 5 行,因为它不与第 1 行或第 4 行重叠。删除第 6 行,因为它与第 4 行重叠。
尝试:
- 我可以使用 np.where 检查前一行与当前行并创建一个“重叠”列,然后过滤该列。但这不满足我的要求(即在上面的玩具示例中,第 3 行将被包括在内,因为它不与第 2 行重叠,但应该被排除在外,因为它与第 1 行重叠)。
df['overlap'] = np.where((df['start']> df['start'].shift(1)) &
(df['start'] < df['end'].shift(1)),1 ,0)
df['overlap'] = np.where((df['end'] < df['end'].shift(1)) &
(df['end'] > df['start'].shift(1)), 1, df['overlap'])
- 我尝试了基于这个问题 Removing 'overlapping' dates from pandas dataframe 的答案的实现,使用从结束日期开始的回溯期,但是我的开始日期和结束日期之间的天数不是恒定的,而且它似乎没有产生正确的答案无论如何。
target = df.iloc[0]
day_diff = abs(target['End_Date'] - df['End_Date'])
day_diff = day_diff.reset_index().sort_values(['End_Date', 'index'])
day_diff.columns = ['old_index', 'End_Date']
non_overlap = day_diff.groupby(day_diff['End_Date'].dt.days // window).first().old_index.values
results = df.iloc[non_overlap]
最佳答案
如果 (a) End2>Start1 和 (b) Start2
a = np.triu(df['End_Date'].values>df['Start_Date'].values[:,None])
b = np.triu(df['Start_Date'].values<df['End_Date'].values[:,None])
好的行是那些在 a&b
的对角线上只有 True 的行
df[(a&b).sum(0)==1]
输出:
Rank Start_Date End_Date
1 2021-01-01 2021-02-01
4 2020-05-01 2020-06-01
5 2020-07-10 2020-08-10
注意。由于需要计算行的组合,当数组变大时,这种方法会占用大量内存,但速度应该很快
关于python - 检查行的日期范围是否与 Python/Pandas Dataframe 中的任何先前行日期范围重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68627118/