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

基于日期区间匹配Pandas DataFrame对应Code的高效实现

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

问题描述

我有如下结构的Pandas DataFrame:

Code    StartDate      EndDate
   A   2024-07-01   2024-08-03
   B   2024-08-06   2024-08-10
   C   2024-08-11   2024-08-31

需要遍历从2024-07-01开始的每一天,根据给定日期返回对应的Code值;若日期不在任何StartDate/EndDate区间内,则返回'Fallback_Code'。

最初的嵌套迭代实现效率极低(因DataFrame记录量大):

DAYS = DAY_DF['Date'].tolist() # 存储所有需要匹配的日期列表
for DAY in DAYS:
    code = False
    for i,r in df.iterrows():
        if r['StartDate'] <= DAY <= r['EndDate']:
            code = r['Code']
            break
    if not code: # 如果没有匹配到任何区间
        code = 'Fallback_Code'

输入输出示例:

2024-07-03 -> 'A'
2024-08-04 -> 'Fallback_Code'
2024-08-10 -> 'B'
2024-08-11 -> 'C'

高效解决方案

方案一:使用pandas.merge_asof

merge_asof是Pandas专为有序键的近似匹配设计的高效方法,适合此类区间匹配场景:

  1. 转换日期类型:确保所有日期列都是datetime格式
df['StartDate'] = pd.to_datetime(df['StartDate'])
df['EndDate'] = pd.to_datetime(df['EndDate'])
DAY_DF['Date'] = pd.to_datetime(DAY_DF['Date'])
  1. 排序数据集:merge_asof要求左右两边的匹配键必须排序
df_sorted = df.sort_values('StartDate')
day_df_sorted = DAY_DF.sort_values('Date')
  1. 执行匹配与过滤:
# 按Date匹配最近的StartDate不大于当前日期的记录
merged = pd.merge_asof(day_df_sorted, df_sorted, left_on='Date', right_on='StartDate', direction='backward')
# 过滤掉日期超出对应EndDate的情况,赋值兜底Code
merged['Code'] = merged.apply(lambda x: x['Code'] if x['Date'] <= x['EndDate'] else 'Fallback_Code', axis=1)
# 恢复原始DAY_DF的顺序
result = merged.set_index(day_df_sorted.index).sort_index()

方案二:使用区间索引(IntervalIndex)

利用Pandas的区间索引实现矢量级的快速匹配:

  1. 转换日期并创建区间索引:
df['StartDate'] = pd.to_datetime(df['StartDate'])
df['EndDate'] = pd.to_datetime(df['EndDate'])
DAY_DF['Date'] = pd.to_datetime(DAY_DF['Date'])

# 创建包含起始和结束日期的闭区间
interval_idx = pd.IntervalIndex.from_arrays(df['StartDate'], df['EndDate'], closed='both')
  1. 匹配并映射Code:
# 获取每个日期对应的区间位置,未匹配到返回-1
positions = interval_idx.get_indexer(DAY_DF['Date'])
# 映射Code,未匹配的赋值兜底值
DAY_DF['Code'] = df['Code'].iloc[positions].fillna('Fallback_Code').values

方案三:向量化布尔匹配(适合无重叠区间)

若你的区间无重叠且数量较少,可采用批量布尔赋值的方式:

  1. 转换日期类型:同上述步骤
  2. 批量赋值:
# 先初始化所有Code为兜底值
DAY_DF['Code'] = 'Fallback_Code'

# 遍历每个区间,用布尔索引批量更新匹配的日期
for _, row in df.iterrows():
    mask = (DAY_DF['Date'] >= row['StartDate']) & (DAY_DF['Date'] <= row['EndDate'])
    DAY_DF.loc[mask, 'Code'] = row['Code']

此方法循环次数为区间记录数,远小于日期数时效率显著提升。


内容的提问来源于stack exchange,提问作者Bijan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:00:19