Pandas中基于另一DataFrame最近时间戳匹配并赋值数据列
解决Pandas中按最近时间戳匹配数据列的报错问题
问题背景
有两个按时间排序的Pandas DataFrame(df1和df2),均包含时间戳列与数据列。需求为:针对df1中的每个时间戳,找到df2中时间戳最接近的行,并将该行的Data2值赋值给df1对应行。
已通过get_indexer获取到正确的索引位置及对应时间戳值,但执行最后一段代码时出现错误:
ValueError: cannot reindex from a duplicate axis
用户提供的完整代码及运行输出如下:
import pandas as pd df1 = pd.DataFrame({'Time1': ['2023-11-30 13:01:51.813', '2023-11-28 10:01:51.760', '2023-11-28 10:01:51.347', '2023-11-27 10:01:51.320', '2023-11-26 10:01:51.260'], 'Data1': [2, 4, 6, 8, 10]}) df2 = pd.DataFrame({'Time2': ['2023-11-30 10:00:03.733', '2023-11-29 08:00:03.767', '2023-11-28 16:00:03.523', '2023-11-27 14:00:03.827', '2023-11-26 12:00:03.417'], 'Data2': ['A', 'B', 'C', 'D', 'E']}) # 格式化时间为datetime类型 df1['Time1'] = pd.to_datetime(df1['Time1'], format='%Y-%m-%d %H:%M:%S.%f') df2['Time2'] = pd.to_datetime(df2['Time2'], format='%Y-%m-%d %H:%M:%S.%f') # 将Time2设为df2的索引 df2 = df2.set_index('Time2') # 为每个Time1找到最接近的Time2的位置索引 df1['Data2Index']= df2.index.get_indexer(df1['Time1'], method='nearest') # 为每个Time1找到最接近的Time2的索引值 df1['Data2Time'] = df2.index[df2.index.get_indexer(df1['Time1'], method='nearest')] print(df1) print(df2) # 运行输出 # Time1 Data1 Data2Index Data2Time # 0 2023-11-30 13:01:51.813 2 0 2023-11-30 10:00:03.733 # 1 2023-11-28 10:01:51.760 4 2 2023-11-28 16:00:03.523 # 2 2023-11-28 10:01:51.347 6 2 2023-11-28 16:00:03.523 # 3 2023-11-27 10:01:51.320 8 3 2023-11-27 14:00:03.827 # 4 2023-11-26 10:01:51.260 10 4 2023-11-26 12:00:03.417 # Data2 # Time2 # 2023-11-30 10:00:03.733 A # 2023-11-29 08:00:03.767 B # 2023-11-28 16:00:03.523 C # 2023-11-27 14:00:03.827 D # 2023-11-26 12:00:03.417 E # 尝试获取对应Data2值(执行报错) df1['Data2']= df2.Data2[df2.index.get_indexer(df1['Time1'], method='nearest')]
错误原因
报错核心在于:df2.Data2[索引数组]返回的Series保留了df2的原时间戳索引,而df1使用默认整数索引(0-4),两者索引体系不匹配。同时df1中存在重复的匹配位置(比如第1、2行都匹配到df2的位置2),导致Pandas无法完成索引对齐,从而抛出重复轴错误。
解决方案
方案1:利用已计算的Data2Index直接取值
既然已经在df1中存储了Data2Index(匹配到的df2行的位置索引),直接用.iloc按位置提取值,并转为numpy数组避免索引对齐问题:
df1['Data2'] = df2['Data2'].iloc[df1['Data2Index']].values
方案2:一步到位提取值
不需要重复计算索引,直接获取匹配位置后提取Data2值:
# 替换报错的最后一行代码 match_indices = df2.index.get_indexer(df1['Time1'], method='nearest') df1['Data2'] = df2['Data2'].iloc[match_indices].values
方案3:使用merge_asof(推荐)
Pandas内置的merge_asof专门用于按最近时间戳合并DataFrame,代码更简洁高效,无需手动处理索引:
# 确保两个DataFrame按时间排序(题目已说明排序,可再次确认) df1 = df1.sort_values('Time1') df2 = df2.reset_index().sort_values('Time2') # 按最近时间合并,direction='nearest'表示匹配最近的时间戳 merged_df = pd.merge_asof(df1, df2, left_on='Time1', right_on='Time2', direction='nearest') # 整理需要的列 merged_df = merged_df[['Time1', 'Data1', 'Data2', 'Time2']].rename(columns={'Time2': 'Data2Time'})
最终效果
执行任意方案后,df1会得到正确的Data2值:
Time1 Data1 Data2Index Data2Time Data2 0 2023-11-30 13:01:51.813 2 0 2023-11-30 10:00:03.733 A 1 2023-11-28 10:01:51.760 4 2 2023-11-28 16:00:03.523 C 2 2023-11-28 10:01:51.347 6 2 2023-11-28 16:00:03.523 C 3 2023-11-27 10:01:51.320 8 3 2023-11-27 14:00:03.827 D 4 2023-11-26 10:01:51.260 10 4 2023-11-26 12:00:03.417 E
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

