在Pandas DataFrame中按列值子集容差匹配输入输出行
解决方案
1. 拆分输入与输出行
先把原DataFrame拆成两类行,同时保留原始索引方便后续关联:
import pandas as pd import numpy as np # 假设数据已读入df,这里的输出标记值请替换为你实际数据中的值 input_rows = df[df['I'] != 'output'].copy() output_rows = df[df['I'] == 'output'][['F', 'G', 'H', 'I']].copy()
2. 矢量化容差匹配(无for循环)
利用numpy广播机制,基于已知的匹配列对(F/C、G/D、H/A)做批量容差匹配,锁定每个输出行对应的前置输入行:
# 定义匹配规则:输出列 → 对应输入列 match_pairs = {'F': 'C', 'G': 'D', 'H': 'A'} # 提取用于匹配的列数据,转成numpy数组 input_match_vals = input_rows[list(match_pairs.values())].values output_match_vals = output_rows[list(match_pairs.keys())].values # 设置容差,根据数据分辨率损失情况调整 tolerance = 1e-3 # 批量生成匹配掩码:每个输出行与所有输入行的匹配结果,仅保留三列都符合容差的行 match_mask = np.all(np.isclose(output_match_vals[:, None, :], input_match_vals[None, :, :], atol=tolerance), axis=2) # 筛选每个输出行对应的前置输入行索引 input_indices = input_rows.index.values output_indices = output_rows.index.values matched_input_ids = [] for output_idx in output_indices: # 只考虑时间上在输出行之前的输入行 prior_input_mask = input_indices < output_idx # 找出符合匹配条件的输入行索引 valid_matches = input_indices[prior_input_mask & match_mask[output_rows.index.get_loc(output_idx)]] # 取最近的匹配行(时间序上最后一个符合条件的) matched_input_ids.append(valid_matches[-1] if len(valid_matches) > 0 else None) # 给输出行添加匹配到的输入行索引 output_rows['matched_input_idx'] = matched_input_ids
3. 合并输出数据到对应输入行
将输出行的有效数据合并到匹配的输入行,原输入行无匹配的保持不变,原输出行可按需保留或删除:
# 重置输出行索引为匹配的输入行索引,准备合并 output_to_merge = output_rows.set_index('matched_input_idx').drop(columns=['I']) # 合并输出数据到输入行 merged_input = input_rows.join(output_to_merge, how='left') # 生成最终DataFrame,两种方案可选: # 方案1:保留原数据所有行,替换输入行为合并后的数据,输出行不变 final_df = df.copy() final_df.loc[merged_input.index, merged_input.columns] = merged_input # 方案2:仅保留合并后的输入行,删除原输出行 # final_df = merged_input
关键说明
- 矢量化优势:靠numpy广播替代逐行循环,处理大体积时间序列数据时效率提升显著。
- 容差调整:
np.isclose的atol参数可根据数据实际的分辨率损失灵活设置,确保匹配准确性。 - 时间序约束:通过
input_indices < output_idx确保只匹配输出行之前的输入行,符合数据采集的时间逻辑。
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

