基于日期条件匹配两个DataFrame的高效方法求助(避免合并后过滤)
高效实现DataFrame日期区间匹配
针对你遇到的全量合并后过滤导致的性能问题,以下两种方案可以避免生成大量中间行,大幅提升处理效率:
数据准备(先确保日期类型正确)
首先将两个DataFrame的日期列转为datetime类型,这是后续操作的基础:
import pandas as pd # 第一个DataFrame(含DATE列) df1 = pd.DataFrame({'DATE': ['2022-10-01', '2022-10-22', '2022-11-14']}) df1['DATE'] = pd.to_datetime(df1['DATE']) # 第二个DataFrame(含区间和分类) df2 = pd.DataFrame({ 'CATEGORY': [1, 2, 3], 'START': ['2022-09-01', '2022-10-01', '2022-11-01'], 'END': ['2022-09-30', '2022-10-31', '2022-11-30'] }) df2['START'] = pd.to_datetime(df2['START']) df2['END'] = pd.to_datetime(df2['END'])
方案1:基于IntervalIndex的精准匹配(支持任意区间)
该方法通过将df2的日期区间转化为索引,直接匹配df1的DATE所在区间,无需生成笛卡尔积:
# 创建左闭右闭的区间索引(匹配DATE在START和END之间的情况) intervals = pd.IntervalIndex.from_arrays(df2['START'], df2['END'], closed='both') # 获取每个DATE对应的区间位置 match_idx = intervals.get_indexer(df1['DATE']) # 过滤无匹配的行,合并结果 mask = match_idx != -1 result = df1[mask].reset_index(drop=True).join(df2.iloc[match_idx[mask]].reset_index(drop=True))
优势:不依赖区间的有序性,支持重叠区间,时间复杂度接近O(n),内存占用极低。
方案2:使用merge_asof(适合非重叠有序区间)
如果df2的日期区间是不重叠且按START递增排序的,merge_asof是性能最优的选择,它采用线性扫描匹配,避免全量合并:
# 对两个DataFrame按日期排序(merge_asof要求) df1_sorted = df1.sort_values('DATE').reset_index(drop=True) df2_sorted = df2.sort_values('START').reset_index(drop=True) # 匹配<=当前DATE的最近START,再过滤DATE<=END的有效区间 merged = pd.merge_asof(df1_sorted, df2_sorted, left_on='DATE', right_on='START', direction='backward') result = merged[(merged['DATE'] >= merged['START']) & (merged['DATE'] <= merged['END'])].reset_index(drop=True)
优势:时间复杂度为O(n log n + m log m),数据量越大,相比全合并的优势越明显,适合百万级以上数据处理。
结果验证
执行上述任意方案后,得到的result将满足你的需求:
| DATE | CATEGORY | START | END |
|---|---|---|---|
| 2022-10-01 | 2 | 2022-10-01 | 2022-10-31 |
| 2022-10-22 | 2 | 2022-10-01 | 2022-10-31 |
| 2022-11-14 | 3 | 2022-11-01 | 2022-11-30 |
(注:你提供的期望结果中第一行的START/END存在逻辑矛盾,2022-10-01并不在2022-09-01至2022-09-30区间内,以上为符合需求逻辑的正确结果)
内容的提问来源于stack exchange,提问作者Jorge Vinseiro
相关产品推荐
相关产品推荐

