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

Pandas时间序列与区间DataFrame关联匹配KeyError问题求助

问题原因
  • IntervalIndex闭合方向不匹配:默认创建的IntervalIndex为右闭closed='right',若时间戳落在区间左边界、或业务预期的闭合逻辑与默认不一致,会出现匹配不到的情况。
  • 区间存在间隙:时间戳落在两个区间的空白区间,无对应匹配项。
  • 时间时区不匹配:时间序列的时间戳与区间的时间字段时区不一致,看似时间相同实际数值不匹配。
  • 取值方法不合理:直接用interval_idx[timestamp]的方式取值,匹配不到时会直接抛出KeyError,无容错机制。
  • 逐行apply操作性能极低,数据量超过1万条时运行效率会出现指数级下降,不推荐使用。
最优实现方案(推荐:向量化操作,性能远高于apply)

使用pd.merge_asof实现区间匹配,步骤如下:

import pandas as pd

# 1. 准备测试数据(替换为实际数据即可)
# 区间表:存储每个时间区间对应的Product
interval_df = pd.DataFrame({
    'start_time': pd.to_datetime(['2023-01-01', '2023-01-03', '2023-01-05']),
    'end_time': pd.to_datetime(['2023-01-03', '2023-01-05', '2023-01-07']),
    'Product': ['A', 'B', 'C']
})
# 时间序列表
ts_df = pd.DataFrame({
    'timestamp': pd.to_datetime(['2023-01-01 12:00:00', '2023-01-03 00:00:00', '2023-01-04 12:00:00', '2023-01-06 00:00:00', '2023-01-07 00:00:00']),
    'value': [10, 20, 30, 40, 50]
})

# 2. 对两个表的关联时间字段排序(merge_asof强制要求)
ts_df_sorted = ts_df.sort_values('timestamp').reset_index(drop=True)
interval_df_sorted = interval_df.sort_values('start_time').reset_index(drop=True)

# 3. 区间匹配:direction='backward'表示匹配小于等于当前时间戳的最大start_time
result = pd.merge_asof(
    ts_df_sorted,
    interval_df_sorted,
    left_on='timestamp',
    right_on='start_time',
    direction='backward'
)

# 4. 过滤掉超出end_time的匹配项,保留目标字段
# 如需保留未匹配到的行,将query替换为result['Product'] = result['Product'].where(result['timestamp'] < result['end_time'])
result = result.query('timestamp < end_time')[['timestamp', 'value', 'Product']]

上述代码默认匹配**左闭右开 [start_time, end_time)**的区间逻辑,如需调整为其他闭合规则,修改第4步的过滤条件即可:

  • 左开右闭 (start_time, end_time]:将关联时的right_on改为end_time,direction改为forward,过滤条件改为timestamp > start_time
  • 全闭 [start_time, end_time]:过滤条件改为timestamp <= end_time
IntervalIndex兼容方案(如必须使用IntervalIndex实现)

使用get_indexer方法替代直接索引取值,避免KeyError:

# 1. 构建IntervalIndex,明确指定闭合方向,不要用默认值
interval_idx = pd.IntervalIndex.from_arrays(
    interval_df['start_time'], 
    interval_df['end_time'], 
    closed='left' # 按需调整为right/both/neither
)
interval_df = interval_df.set_index(interval_idx)

# 2. 批量获取匹配位置,匹配不到返回-1
match_pos = interval_idx.get_indexer(ts_df['timestamp'])

# 3. 赋值匹配结果
ts_df['Product'] = interval_df.iloc[match_pos]['Product'].reset_index(drop=True)
# 未匹配到的位置设为空值
ts_df.loc[match_pos == -1, 'Product'] = pd.NA

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 06:06:01