Python/Pandas如何删除DataFrame中日期范围与之前任意行重叠的行
问题解决:Pandas按优先级保留不重叠日期区间
前置说明
核心需求是按Rank列的优先级(数值越小优先级越高)保留日期区间,只要当前行和任意已保留的高优先级行的日期区间重叠就删除。
你之前的方案问题在于:
- 第一种仅和上一行比较,没有和所有更早的已保留行校验重叠
- 第二种基于固定窗口的分组逻辑,无法适配日期间隔不固定的场景
实现方案
方案1:基础循环实现(适合10万行以内数据,逻辑清晰无歧义)
首先先把日期列转为datetime类型,再按优先级遍历校验:
import pandas as pd # 先转换日期列格式,原始日期是月/日/年格式,指定format避免解析错误 df['Start_Date'] = pd.to_datetime(df['Start_Date'], format='%m/%d/%Y') df['End_Date'] = pd.to_datetime(df['End_Date'], format='%m/%d/%Y') # 初始化保留的索引列表和已保留的日期区间列表 keep_idx = [] kept_ranges = [] # 按Rank顺序遍历(df已经按Rank升序排好,直接遍历即可) for idx, row in df.iterrows(): curr_start = row['Start_Date'] curr_end = row['End_Date'] # 标记是否重叠 overlap = False # 和所有已保留的区间校验 for (s, e) in kept_ranges: # 重叠判断逻辑:两个区间存在交集 if curr_start < e and curr_end > s: overlap = True break if not overlap: keep_idx.append(idx) kept_ranges.append((curr_start, curr_end)) # 过滤得到结果 result = df.loc[keep_idx] # 如果需要把日期转回字符串格式可以加下面这行 # result[['Start_Date','End_Date']] = result[['Start_Date','End_Date']].dt.strftime('%m/%d/%Y')
用你提供的示例数据测试,输出结果和期望完全一致。
方案2:优化版(适合10万行以上大数据量)
如果数据量较大,循环的O(n²)复杂度会比较慢,可以对已保留的区间做排序后用二分查找校验,把复杂度降到O(nlogn):
import pandas as pd import bisect df['Start_Date'] = pd.to_datetime(df['Start_Date'], format='%m/%d/%Y') df['End_Date'] = pd.to_datetime(df['End_Date'], format='%m/%d/%Y') keep_idx = [] # 分别存已保留区间的开始和结束日期,按结束日期升序排序 kept_ends = [] kept_starts = [] for idx, row in df.iterrows(): s, e = row['Start_Date'], row['End_Date'] # 找第一个结束日期大于当前开始日期的区间 pos = bisect.bisect_right(kept_ends, s) overlap = False # 只需要校验该位置往后的区间是否有开始日期小于当前结束日期的即可 if pos < len(kept_starts) and kept_starts[pos] < e: overlap = True if not overlap: keep_idx.append(idx) # 插入到对应位置保持排序 insert_pos = bisect.bisect_left(kept_ends, e) kept_ends.insert(insert_pos, e) kept_starts.insert(insert_pos, s) result = df.loc[keep_idx]
内容的提问来源于stack exchange,提问作者sdp501
相关产品推荐
相关产品推荐

