Python多DataFrame日期匹配效率优化:寻求高效替代方案
高效实现DataFrame日期区间匹配方案
问题背景
现有三个DataFrame:
df1
| tradeDate | securityCode |
|---|---|
| 20190319 | 000001 |
| 20220505 | 000001 |
(规模:(3829931, 2))
df2
| payoutDate | securityCode |
|---|---|
| 20180708 | 000001 |
| 20190221 | 000002 |
(规模:(35689, 2))
df3
| endDate | securityCode |
|---|---|
| 20200203 | 000003 |
| 20210330 | 000004 |
(规模:(10329, 2))
需要实现:
- 为df1新增列
condition; - 若df1某条记录的
securityCode对应的tradeDate过去两年区间内,df2的payoutDate或df3的endDate存在同securityCode的记录,condition设为1,否则为0。
原代码使用apply逐行遍历检查,因重复扫描小表导致时间复杂度极高,运行极慢,需优化。
优化思路
核心优化方向是避免逐行重复扫描小表:
- 先预处理df2和df3,按
securityCode分组并排序日期; - 利用二分查找快速判断目标区间内是否存在匹配日期,将单条记录的检查复杂度从O(M+K)降至O(log N)(N为单code对应的日期数量)。
具体实现代码
import pandas as pd import bisect # 1. 统一日期格式与列名,避免格式/大小写不一致问题 df1['tradeDate'] = pd.to_datetime(df1['tradeDate'], format='%Y%m%d') df2['payoutDate'] = pd.to_datetime(df2['payoutDate'], format='%Y%m%d') df3['endDate'] = pd.to_datetime(df3['endDate'], format='%Y%m%d') # 2. 合并df2与df3的日期数据,统一结构 df2_clean = df2[['securityCode', 'payoutDate']].rename(columns={'payoutDate': 'date'}) df3_clean = df3[['securityCode', 'endDate']].rename(columns={'endDate': 'date'}) combined_dates = pd.concat([df2_clean, df3_clean], ignore_index=True) # 3. 按securityCode分组,存储每个code对应的排序日期列表 date_groups = combined_dates.groupby('securityCode')['date'].apply(lambda x: sorted(x.tolist())).to_dict() # 4. 定义快速检查函数,用二分查找判断区间内是否存在日期 def check_condition_fast(row): code = row['securityCode'] trade_date = row['tradeDate'] two_years_ago = trade_date - pd.DateOffset(years=2) # 无对应code直接返回0 if code not in date_groups: return 0 dates = date_groups[code] # 找到区间左边界的第一个位置 left_pos = bisect.bisect_left(dates, two_years_ago) # 找到区间右边界的第一个位置 right_pos = bisect.bisect_right(dates, trade_date) # 两个位置不相等则说明区间内有匹配日期 return 1 if left_pos < right_pos else 0 # 5. 应用到df1 df1['condition'] = df1.apply(check_condition_fast, axis=1)
进阶向量化优化方案
若内存充足,可完全避免apply,利用pandas向量化合并操作实现:
# 给df1添加两年前的日期列 df1['two_years_ago'] = df1['tradeDate'] - pd.DateOffset(years=2) # 合并df1与日期数据,按securityCode匹配 merged = pd.merge(df1, combined_dates, on='securityCode', how='left') # 按df1的行分组,判断是否存在符合条件的日期 df1['condition'] = merged.groupby(merged.index).apply( lambda x: 1 if ((x['date'] >= x['two_years_ago']) & (x['date'] <= x['tradeDate'])).any() else 0, axis=1 )
内容的提问来源于stack exchange,提问作者Y L
相关产品推荐
相关产品推荐

