You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多DataFrame日期匹配效率优化:寻求高效替代方案

高效实现DataFrame日期区间匹配方案

问题背景

现有三个DataFrame:

df1

tradeDatesecurityCode
20190319000001
20220505000001

(规模:(3829931, 2))

df2

payoutDatesecurityCode
20180708000001
20190221000002

(规模:(35689, 2))

df3

endDatesecurityCode
20200203000003
20210330000004

(规模:(10329, 2))

需要实现:

  1. 为df1新增列condition;
  2. 若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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 23:55:34