解决匹配DataFrame时间窗口时KeyError: Timestamp不在索引中的问题
问题分析与解决
错误原因
原代码的核心问题在于:你试图用单个时间戳去索引IntervalIndex类型的索引,但IntervalIndex的索引元素是区间对象而非时间戳,当时间戳不落在任何定义的区间内时,就会触发KeyError。
修改方案
我们需要先为df2中的每个时间戳匹配对应的区间(无匹配则标记为无效),再过滤无效数据后分组计算均值,具体有两种实现方式:
方法一:使用apply匹配区间
通过自定义函数检查每个时间戳是否落在某个区间内,无匹配则返回空值,最后过滤空值分组:
from datetime import datetime, date import pandas as pd df1 = pd.DataFrame({'id': ['aa0', 'aa1', 'aa2', 'aa3'], 'number': [1, 2, 2, 1], 'color': ['blue', 'red', 'yellow', "green"], 'date1': [datetime(2022,1,1,1,1,1), datetime(2022,1,1,2,4,1), datetime(2022,1,1,3,8,1), datetime(2022,1,1,4,12,1)], 'date2': [datetime(2022,1,1,2,1,1), datetime(2022,1,1,3,6,1), datetime(2022,1,1,3,10,1), datetime(2022,1,1,4,14,1)] }) df2 = pd.DataFrame({'id': ['A', 'B', 'C', 'D'], 'value': [10,20,30,40], 'date': [datetime(2022,1,1,1,12,1), datetime(2022,1,1,1,40,1), datetime(2022,1,1,3,12,2), datetime(2022,1,1,4,12,2)] }) # 生成区间索引(默认左开右闭,符合预期的(date1, date2]格式) idx = pd.IntervalIndex.from_arrays(pd.to_datetime(df1['date1']), pd.to_datetime(df1['date2'])) # 自定义函数匹配区间 def match_interval(dt): # 找到包含当前时间戳的区间 matched = idx[idx.contains(dt)] return matched.item() if len(matched) > 0 else pd.NA # 为df2添加区间列 df2['interval'] = df2['date'].apply(match_interval) # 过滤无匹配的行,分组计算均值 result = df2.dropna(subset=['interval']).groupby('interval')['value'].mean() print(result)
方法二:使用get_indexer_for批量匹配
利用IntervalIndex.get_indexer_for批量获取每个时间戳对应的区间索引,-1表示无匹配,过滤后分组:
from datetime import datetime, date import pandas as pd df1 = pd.DataFrame({'id': ['aa0', 'aa1', 'aa2', 'aa3'], 'number': [1, 2, 2, 1], 'color': ['blue', 'red', 'yellow', "green"], 'date1': [datetime(2022,1,1,1,1,1), datetime(2022,1,1,2,4,1), datetime(2022,1,1,3,8,1), datetime(2022,1,1,4,12,1)], 'date2': [datetime(2022,1,1,2,1,1), datetime(2022,1,1,3,6,1), datetime(2022,1,1,3,10,1), datetime(2022,1,1,4,14,1)] }) df2 = pd.DataFrame({'id': ['A', 'B', 'C', 'D'], 'value': [10,20,30,40], 'date': [datetime(2022,1,1,1,12,1), datetime(2022,1,1,1,40,1), datetime(2022,1,1,3,12,2), datetime(2022,1,1,4,12,2)] }) idx = pd.IntervalIndex.from_arrays(pd.to_datetime(df1['date1']), pd.to_datetime(df1['date2'])) # 获取每个时间戳对应的区间索引,-1表示无匹配 interval_indices = idx.get_indexer_for(df2['date']) # 过滤无匹配的行,并添加区间列 valid_df = df2[interval_indices != -1].copy() valid_df['interval'] = idx[interval_indices[interval_indices != -1]] # 分组计算均值 result = valid_df.groupby('interval')['value'].mean() print(result)
输出结果
两种方法都会得到预期输出:
(2022-01-01 01:01:01, 2022-01-01 02:01:01] 15.0 (2022-01-01 04:12:01, 2022-01-01 04:14:01] 40.0 dtype: float64
内容的提问来源于stack exchange,提问作者ferrelwill
相关产品推荐
相关产品推荐

