Pandas Merge:优雅处理合并时列值保留与空值填充的方案
合并DataFrame时优先保留主表列值,仅填充空值
现有两个DataFrame结构如下:
df1[['name', 'year', 'col1', 'col2', 'col3']] df2[['name', 'year', 'col2', 'col3', 'col4']]
需求:按name和year合并df1与df2,优先保留df1中col2、col3的所有值,仅当df1对应位置为None(即NaN)时,才用df2中的对应值填充。
传统做法是合并后用ffill()再删除重复列,但多次同类合并会导致代码冗余,想了解pd.merge是否有内置选项直接实现这个需求。
示例数据
df1
name year col1 col2 col3 0 a 2000 1 0.00 1.00 1 a 2001 2 2.00 3.00 2 b 2002 3 4.00 5.00 3 b 2003 4 6.00 7.00 4 c 2004 5 8.00 NaN 5 c 2005 6 NaN 9.00
df2
name year col2 col3 col4 0 b 2003 10.00 100.00 5 1 b 2004 20.00 300.00 6 2 c 2004 30.00 500.00 7 3 c 2005 NaN 700.00 8 4 d 2006 50.00 NaN 9 5 d 2007 60.00 900.00 10
解决方案
pd.merge本身没有直接实现该逻辑的内置参数,但可以通过合并后用combine_first填充重叠列的方式,替代繁琐的ffill和删列操作,代码更简洁且可复用。
实现代码
import pandas as pd # 初始化示例数据 df1 = pd.DataFrame({'name': ['a', 'a', 'b', 'b', 'c', 'c'], 'year': [2000, 2001, 2002, 2003, 2004, 2005], 'col1': [1,2,3,4,5,6], 'col2': [0,2,4,6,8,None], 'col3': [1,3,5,7,None,9]}) df2 = pd.DataFrame({'name': ['b', 'b', 'c', 'c', 'd', 'd'], 'year': [2003, 2004, 2004, 2005, 2006, 2007], 'col2': [10,20,30,None,50,60], 'col3': [100,300,500,700,None,900], 'col4': [5,6,7,8,9,10]}) # 1. 按name和year外合并,给重叠列加后缀区分 merged = pd.merge(df1, df2, on=['name', 'year'], how='outer', suffixes=('_df1', '_df2')) # 2. 对col2、col3优先保留df1的值,空值用df2填充 for col in ['col2', 'col3']: merged[col] = merged[f'{col}_df1'].combine_first(merged[f'{col}_df2']) # 3. 删除临时后缀列,整理最终列顺序 final_df = merged.drop(columns=['col2_df1', 'col2_df2', 'col3_df1', 'col3_df2'])[['name', 'year', 'col1', 'col2', 'col3', 'col4']] print(final_df)
运行结果
name year col1 col2 col3 col4 0 a 2000 1.0 0.0 1.0 NaN 1 a 2001 2.0 2.0 3.0 NaN 2 b 2002 3.0 4.0 5.0 NaN 3 b 2003 4.0 6.0 7.0 5.0 4 b 2004 NaN 20.0 300.0 6.0 5 c 2004 5.0 8.0 500.0 7.0 6 c 2005 6.0 NaN 9.0 8.0 7 d 2006 NaN 50.0 NaN 9.0 8 d 2007 NaN 60.0 900.0 10.0
逻辑说明
- 外合并:用
how='outer'确保保留两个表的所有行,suffixes给重叠列加后缀避免列名冲突。 - 优先填充:
combine_first会自动用右侧列的值填充左侧列的空值,完全匹配"保留df1值、仅空值用df2填充"的需求。 - 代码复用:可以把逻辑封装成函数,多次合并时直接调用:
def merge_with_priority(main_df, other_df, on_cols, priority_cols): merged = pd.merge(main_df, other_df, on=on_cols, how='outer', suffixes=('_main', '_other')) for col in priority_cols: merged[col] = merged[f'{col}_main'].combine_first(merged[f'{col}_other']) drop_cols = [f'{col}_main' for col in priority_cols] + [f'{col}_other' for col in priority_cols] final_cols = on_cols + [col for col in main_df.columns if col not in on_cols] + [col for col in other_df.columns if col not in on_cols + priority_cols] return merged.drop(columns=drop_cols)[final_cols] # 调用示例 final_df = merge_with_priority(df1, df2, on_cols=['name', 'year'], priority_cols=['col2', 'col3'])
内容的提问来源于stack exchange,提问作者PTQuoc
相关产品推荐
相关产品推荐

