如何基于多条件左连接两个Pandas DataFrame并保留左表全部行?
解决左连接并保留左表所有行的条件匹配问题
你原来的代码先做左连接再过滤,会把左表(dat1)中没有满足col2_x < col2_y条件的行直接剔除,这不符合左连接“保留左表所有行”的核心要求。正确的做法应该是保留dat1的全部行,仅对右表(dat2)的匹配结果应用条件过滤,不满足条件的右表列用空值填充。
方法一:保留所有有效匹配明细并补全未匹配行
适合需要完整保留dat2中所有满足条件的匹配记录的场景:
import pandas as pd dat1 = pd.DataFrame({'col1' : ['AA', 'AA'], 'col2' : [10,20]}) dat2 = pd.DataFrame({'col1' : ['AA', 'BB', 'AA', 'BB'], 'col2' : [11,11,11,11]}) # 给dat1添加原始索引,用于后续找回未匹配的行 dat1_with_idx = dat1.reset_index(names='orig_idx') # 执行左连接 dat_com = pd.merge(dat1_with_idx, dat2, how='left', on='col1') # 筛选出满足条件的有效匹配行 valid_matches = dat_com[dat_com['col2_x'] < dat_com['col2_y']] # 找出dat1中没有有效匹配的行 unmatched_rows = dat1_with_idx[~dat1_with_idx['orig_idx'].isin(valid_matches['orig_idx'])] # 给未匹配行添加空值的col2_y列 unmatched_rows = unmatched_rows.assign(col2_y=pd.NA) # 合并结果并恢复原顺序,移除临时索引列 result = pd.concat([valid_matches, unmatched_rows]).sort_values('orig_idx').drop('orig_idx', axis=1) print(result)
输出结果:
col1 col2_x col2_y 0 AA 10 11.0 1 AA 10 11.0 3 AA 20 NaN
方法二:简洁处理,合并重复无效匹配
如果不需要保留dat2中重复的满足条件记录,可使用更简洁的方式:
import pandas as pd import numpy as np dat1 = pd.DataFrame({'col1' : ['AA', 'AA'], 'col2' : [10,20]}) dat2 = pd.DataFrame({'col1' : ['AA', 'BB', 'AA', 'BB'], 'col2' : [11,11,11,11]}) # 执行左连接 dat_com = pd.merge(dat1, dat2, how='left', on='col1') # 将不满足条件的col2_y替换为空值 dat_com['col2_y'] = np.where(dat_com['col2_x'] < dat_com['col2_y'], dat_com['col2_y'], pd.NA) # 去掉同一dat1行对应的重复空值行 result = dat_com.drop_duplicates(subset=['col1', 'col2_x'], keep='first') print(result)
输出结果:
col1 col2_x col2_y 0 AA 10 11.0 2 AA 20 NaN
关键说明
左连接的核心是保留左表的所有行,所以不能直接过滤整个结果集,而是要针对右表的匹配结果做条件筛选:
- 方法一完整保留了dat2中所有符合条件的匹配记录,适合需要明细数据的场景;
- 方法二合并了重复的无效匹配行,适合只需要确认是否存在匹配的场景。
内容的提问来源于stack exchange,提问作者Brian Smith
相关产品推荐
相关产品推荐

