pandas merge_asof合并时仅保留键双向最近匹配行的实现方案咨询
双向最近匹配实现方案
要实现df1和df2互为最近匹配的合并,核心思路是执行两次merge_asof分别验证双向匹配关系,再筛选符合条件的行,具体代码调整如下:
第一步:修正原有代码的小问题
你原有代码中判断NaN的写法有误,NaN无法直接用==/!=比较,需替换为pd.notna:
# 替换原有的NaN判断逻辑 # df2filt = df2[(df2['Fuel2 (l)'] != NaN) & (df2['Meter_Indication'] != NaN)] df2filt = df2[pd.notna(df2['Fuel2 (l)']) & pd.notna(df2['Meter_Indication'])]
第二步:替换原有合并逻辑
删除原代码末尾的merged_df = df1filt2.merge(df2filt, on='Meter_Indication'),替换为以下双向匹配逻辑:
# 1. 确保两个表按合并键升序排列(merge_asof强制要求) df1_sorted = df1filt2.sort_values('Meter_Indication').reset_index(drop=True) df2_sorted = df2filt.sort_values('Meter_Indication').reset_index(drop=True) # 2. 第一次匹配:每个df1行匹配最近的df2行,同时记录匹配到的df2索引 merge_left = pd.merge_asof( df1_sorted, df2_sorted.reset_index(names='df2_idx'), # 给df2加索引列用于校验 on='Meter_Indication', direction='nearest' # 最近匹配规则,可根据需求调整为backward/forward # 可选:加tolerance参数过滤里程差过大的匹配,比如差超过50km就不匹配 # tolerance=50 ) # 3. 第二次匹配:每个df2行匹配最近的df1行,记录匹配到的df1索引 merge_right = pd.merge_asof( df2_sorted, df1_sorted[['Meter_Indication']].reset_index(names='df1_idx'), on='Meter_Indication', direction='nearest' # 保持和第一次匹配一致的tolerance参数 # tolerance=50 ) # 4. 构建df2索引到匹配的df1索引的映射 df2_match_df1 = dict(zip(merge_right.index, merge_right['df1_idx'])) # 5. 仅保留双向匹配的行:df1匹配的df2,其最近匹配也是当前df1行 merged_df = merge_left[ merge_left.apply(lambda row: df2_match_df1.get(row['df2_idx'], -1) == row.name, axis=1) ].drop(columns='df2_idx').reset_index(drop=True)
可选优化
如果需要过滤里程差过大的无效匹配,可在两次merge_asof中添加tolerance参数,单位和Meter_Indication一致,超出阈值的匹配会返回NaN,额外调用dropna()即可过滤。
内容的提问来源于stack exchange,提问作者Leopold Wahlbeck
相关产品推荐
相关产品推荐

