基于相近时间合并DataFrame(类Excel VLOOKUP)失败求替代方案
按相近时间合并DataFrame的解决方案
一、修正你原本的merge_asof方法
你之前用merge_asof失败,通常是两个核心问题:时间列不是datetime类型,或者右侧数据集的时间列未排序。按下面步骤修正即可:
代码示例
import pandas as pd path = r"C:\Users\Documents\" df1 = pd.read_csv(path + '\obs_heads.csv') df2 = pd.read_csv(path + '\sim.csv') # 1. 将时间列转为pandas可识别的datetime类型 df1['A2'] = pd.to_datetime(df1['A2']) df2['A2'] = pd.to_datetime(df2['A2']) # 2. 对df2的时间列排序(merge_asof要求右侧数据集的匹配列必须有序) df2 = df2.sort_values('A2').reset_index(drop=True) # 3. 执行匹配:direction参数控制匹配规则 # - 'backward':找小于等于当前时间的最近值(类似VLOOKUP近似匹配) # - 'nearest':找时间差最小的绝对最近值 t = pd.merge_asof(df1, df2, on="A2", direction='nearest') print(t)
二、小数据集替代方案:逐行匹配最近时间
如果数据量不大,用apply逐行查找逻辑更直观:
代码示例
import pandas as pd path = r"C:\Users\Documents\" df1 = pd.read_csv(path + '\obs_heads.csv') df2 = pd.read_csv(path + '\sim.csv') # 转换时间列格式 df1['A2'] = pd.to_datetime(df1['A2']) df2['A2'] = pd.to_datetime(df2['A2']) # 定义函数,为df1的每一行找到df2中时间最近的行 def get_nearest_row(row): time_diff = abs(df2['A2'] - row['A2']) nearest_idx = time_diff.idxmin() return df2.loc[nearest_idx] # 合并结果 result = df1.merge( df1.apply(get_nearest_row, axis=1), left_index=True, right_index=True, suffixes=('_obs', '_sim') # 区分两个表的同名字段 ) print(result)
三、大数据集高效方案:KDTree快速匹配
如果数据量很大(十万条以上),用KDTree的空间索引可以大幅提升匹配速度:
代码示例
import pandas as pd from scipy.spatial import KDTree path = r"C:\Users\Documents\" df1 = pd.read_csv(path + '\obs_heads.csv') df2 = pd.read_csv(path + '\sim.csv') # 将时间转为 Unix 时间戳(数值型,方便KDTree计算距离) df1['A2_ts'] = pd.to_datetime(df1['A2']).astype('int64') // 10**9 df2['A2_ts'] = pd.to_datetime(df2['A2']).astype('int64') // 10**9 # 构建KDTree索引 tree = KDTree(df2[['A2_ts']]) # 为df1的每个时间点查找最近邻居 _, nearest_indices = tree.query(df1[['A2_ts']], k=1) # 合并结果并清理临时列 result = df1.join(df2.iloc[nearest_indices].reset_index(drop=True), lsuffix='_obs', rsuffix='_sim') result = result.drop(columns=['A2_ts_obs', 'A2_ts_sim']) print(result)
补充说明你的数据情况
从你提供的输入来看:
- df1(观测数据):包含索引列A1、时间列A2、数值列A3
- df2(模拟数据):包含时间列A2、数值列B1、B2
- 期望输出:以df1的行结构为基准,匹配df2中时间最接近的行,合并所有字段
以上三种方法都能实现这个需求,根据数据量选择即可。
内容的提问来源于stack exchange,提问作者Luis Camilo
相关产品推荐
相关产品推荐

