如何在pandas中按起止时间匹配合并两个DataFrame
实现DataFrame区间匹配合并的方法
前置处理:转换时间格式
首先要把两个DataFrame里的字符串时间转为pandas可比较的datetime类型,同时对匹配列排序:
import pandas as pd # 示例数据初始化 df1 = pd.DataFrame({"time": ["10:34:10", "10:34:20", "10:34:30", "10:34:40", "10:34:50", "10:35:00", "10:35:10", "10:35:20"]}) df2 = pd.DataFrame({"start_time": ["10:34:10", "10:34:40"], "end_time": ["10:34:20", "10:34:50"], "session_type": ["11v11", "zonal game"]}) # 转换时间格式 df1['time'] = pd.to_datetime(df1['time']) df2['start_time'] = pd.to_datetime(df2['start_time']) df2['end_time'] = pd.to_datetime(df2['end_time']) # 按时间列排序(merge_asof要求必须排序) df1 = df1.sort_values('time').reset_index(drop=True) df2 = df2.sort_values('start_time').reset_index(drop=True)
方法1:merge_asof实现(高效,适合非重叠区间场景)
这是性能最优的方案,适合大数据量、会话区间无重叠的场景:
# 匹配每个时间点最近的、小于等于该时间的会话开始时间 df3 = pd.merge_asof(df1, df2, left_on='time', right_on='start_time') # 过滤掉时间超出会话结束时间的记录,不符合的字段填充空值 match_mask = df3['time'] <= df3['end_time'] df3.loc[~match_mask, ['start_time', 'end_time', 'session_type']] = pd.NA # 可选:把时间转回字符串格式,和示例输出保持一致 df3['time'] = df3['time'].dt.strftime('%H:%M:%S') df3['start_time'] = df3['start_time'].dt.strftime('%H:%M:%S').where(match_mask, pd.NA) df3['end_time'] = df3['end_time'].dt.strftime('%H:%M:%S').where(match_mask, pd.NA)
方法2:IntervalIndex实现(支持重叠区间匹配)
如果存在一个时间点落在多个会话区间的场景,可以用这个方法,会返回所有匹配的会话记录:
# 基于df2的起止时间创建闭区间索引 session_intervals = pd.IntervalIndex.from_arrays(df2['start_time'], df2['end_time'], closed='both') # 为df1每个时间点匹配对应的区间索引 df1['interval_id'] = df1['time'].apply(lambda x: session_intervals.get_loc(x) if session_intervals.contains(x).any() else -1) # 关联会话字段,得到最终结果 df3 = df1.merge(df2, left_on='interval_id', right_index=True, how='left').drop(columns='interval_id')
内容的提问来源于stack exchange,提问作者Christian Rønsholt
相关产品推荐
相关产品推荐

