基于datetime合并Pandas DataFrame 按时间区间匹配Testphase字段
Pandas 按时间区间匹配合并数据集实现
所有方案执行前都需要先将时间字段转换为datetime类型,避免字符串比较导致的逻辑错误:
import pandas as pd import numpy as np # 初始化示例数据 df1 = pd.DataFrame({'Timestamp': ['2022-03-20 08:25:01', '2022-03-20 08:25:02', '2022-03-20 08:25:03', '2022-03-20 08:25:04', '2022-03-20 08:25:05', '2022-03-20 08:25:06'], 'Temperature': ['650', '720', '40', '30', '500', '130']}) df2 = pd.DataFrame({'Testphase': ['A1', 'A2', 'A3'], 'Begin_time': ['2022-03-20 08:25:01', '2022-03-20 08:25:04', '2022-03-20 08:25:30'], 'End_time': ['2022-03-20 08:25:03', '2022-03-20 08:25:05' , '2022-03-20 08:25:35']}) # 转换时间字段类型 df1['Timestamp'] = pd.to_datetime(df1['Timestamp']) df2['Begin_time'] = pd.to_datetime(df2['Begin_time']) df2['End_time'] = pd.to_datetime(df2['End_time'])
方案1:逐行遍历匹配(对应你提出的第一种思路)
逻辑为逐行读取df1的时间戳,遍历df2判断是否落在对应区间内,匹配成功则写入Testphase值,未匹配默认填充NaN。
该方法实现简单,但数据量较大时遍历效率极低,仅适合千行级以内的小数据集使用
# 初始化Testphase列 df1['Testphase'] = np.nan for idx, row in df1.iterrows(): current_ts = row['Timestamp'] for _, phase in df2.iterrows(): # 闭区间判断,包含首尾端点 if phase['Begin_time'] <= current_ts <= phase['End_time']: df1.loc[idx, 'Testphase'] = phase['Testphase'] break # 调整列顺序匹配预期输出 df_res1 = df1[['Timestamp', 'Testphase', 'Temperature']]
方案2:秒级展开后关联(对应你提出的第二种思路)
逻辑为将df2的每个时间区间按秒级粒度拆分为单时间戳行,再通过左连接按Timestamp字段和df1关联,未匹配到的记录自动填充NaN。
该方法逻辑直观,但如果时间区间跨度大(如跨天级区间),展开后会产生大量冗余数据,内存占用高
expanded_data = [] for _, row in df2.iterrows(): # 生成当前区间包含首尾的所有秒级时间戳 ts_list = pd.date_range(start=row['Begin_time'], end=row['End_time'], freq='S') expanded_data.append(pd.DataFrame({ 'Timestamp': ts_list, 'Testphase': row['Testphase'] })) df2_expanded = pd.concat(expanded_data, ignore_index=True) # 左连接关联 df_res2 = df1.merge(df2_expanded, on='Timestamp', how='left')[['Timestamp', 'Testphase', 'Temperature']]
方案3:区间索引匹配(推荐,性能最优)
使用pandas原生的IntervalIndex构建时间区间索引直接做映射匹配,无需遍历、无需展开数据,万行以上数据集性能比前两种方案高1~2个数量级:
# 构建闭区间索引(包含首尾端点) interval_idx = pd.IntervalIndex.from_arrays( df2['Begin_time'], df2['End_time'], closed='both' ) # 直接映射匹配 df1['Testphase'] = df2.set_index(interval_idx)['Testphase'].reindex(df1['Timestamp']).values df_res3 = df1[['Timestamp', 'Testphase', 'Temperature']]
以上三种方案输出结果完全和你给出的预期DataFrame一致。
注意:如果df2中存在时间区间重叠的情况,上述方法默认匹配重叠区间中最后一个定义的Testphase,使用前建议先对df2的区间做去重、排重处理。
内容的提问来源于stack exchange,提问作者Berendvv
相关产品推荐
相关产品推荐

