多条件对比两个DataFrame,移除符合对应ID日期范围的行
Pandas: Remove Rows Where ID Exists in Another DataFrame and Date Falls in Date Range
先明确我们的数据源(修正了原始数据的排版,区分行号与数据列):
原始DataFrames
df-a
| ID | Start_Date | End_Date |
|---|---|---|
| cd2 | 2020-06-01 | 2020-06-09 |
| cd2 | 2020-06-24 | 2020-07-21 |
| cd56 | 2020-06-10 | 2020-07-03 |
| cd915 | 2020-04-28 | 2020-07-21 |
| cd103 | 2020-04-13 | 2020-04-24 |
df-b
| ID | Date |
|---|---|
| cd2 | 2020-05-12 |
| cd2 | 2020-04-12 |
| cd2 | 2020-06-29 |
| cd15 | 2020-04-28 |
| cd193 | 2020-04-13 |
需求
移除df-b中满足以下条件的行:
- 该行的ID在df-a中存在
- 该行的Date落在df-a中对应ID的任意一个
[Start_Date, End_Date]区间内
解决方案
用Pandas的合并+分组操作实现,高效且逻辑清晰:
首先构造并格式化DataFrames(确保日期列是datetime类型,这是日期判断的前提):
import pandas as pd # 构造df-a df_a = pd.DataFrame({ 'ID': ['cd2', 'cd2', 'cd56', 'cd915', 'cd103'], 'Start_Date': pd.to_datetime(['2020-06-01', '2020-06-24', '2020-06-10', '2020-04-28', '2020-04-13']), 'End_Date': pd.to_datetime(['2020-06-09', '2020-07-21', '2020-07-03', '2020-07-21', '2020-04-24']) }) # 构造df-b df_b = pd.DataFrame({ 'ID': ['cd2', 'cd2', 'cd2', 'cd15', 'cd193'], 'Date': pd.to_datetime(['2020-05-12', '2020-04-12', '2020-06-29', '2020-04-28', '2020-04-13']) })
然后执行核心过滤逻辑:
# 按ID左连接两个DataFrame,保留df-b的所有行 merged = df_b.merge(df_a, on='ID', how='left') # 判断每行的Date是否落在对应的Start_Date和End_Date之间 in_range = (merged['Date'] >= merged['Start_Date']) & (merged['Date'] <= merged['End_Date']) # 对df-b的原始行分组,检查是否存在任意一个匹配区间包含Date to_remove = merged.groupby(merged.index)['in_range'].any() # 保留不需要移除的行 result = df_b[~to_remove] # 输出结果 print(result)
输出结果
ID Date 0 cd2 2020-05-12 1 cd2 2020-04-12 3 cd15 2020-04-28 4 cd193 2020-04-13
逻辑说明
- 左连接:确保df-b的所有行都被保留,ID不在df-a中的行,其Start/End_Date会是NaN,后续判断自动排除这类行的移除可能。
- 区间判断:对每个合并后的行,生成布尔值标记Date是否在对应区间内。
- 分组检查:按df-b原始行索引分组,只要该行有任意一个匹配区间满足条件,就标记为需要移除。
- 过滤结果:用
~to_remove取反,保留不符合移除条件的行。
这个方法避免了逐行循环,处理大规模数据集时效率更高。
内容的提问来源于stack exchange,提问作者twillk
相关产品推荐
相关产品推荐

