You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas条件合并:遇NaN时两列合并,否则三列合并

条件化合并两个DataFrame

需求:合并两个DataFrame时,根据第一个DataFrame(df1)中Name列是否为NaN,选择不同的合并键:

  • 当Name列值为NaN时,仅通过Number、Number2两列进行左合并
  • 当Name列值不为NaN时,通过Number、Number2、Name(对应第二个DataFrame的Name2列)三列进行左合并

示例数据

DataFrame 1(df1)

NumberNumber2Name
12One
22
32Three

DataFrame 2(df2)

NumberNumber2Name2
12One
22Two
22Two.5
32Three
32Three.5
42Four

预期合并结果

NumberNumber2NameName2
12OneOne
22Two
22Two.5
32ThreeThree

当前尝试的代码(存在问题)

import pandas as pd
import numpy as np

def merge_three_or_two(row):
        if row['Name'] == np.nan:
            row = pd.merge(row, df2,  how='left', left_on=['Number','Number2'], right_on = ['Number','Number2'])
        else:
            row = pd.merge(row, df2,  how='left', left_on=['Number','Number2','Name'], right_on = ['Number','Number2','Name2'])
    
df1 = df1.apply(merge_three_or_two, axis=1)

代码问题分析

  1. NaN判断逻辑错误:row['Name'] == np.nan永远返回False,因为NaN和任何值比较结果都是False,正确判断方式应为pd.isna(row['Name'])
  2. 逐行处理效率极低:apply逐行合并会严重拖慢大数据集的处理速度,应采用批量处理方式替代

优化后的解决方案

方法一:分数据集合并后拼接

将df1拆分为Name非NaN和Name为NaN的两部分,分别按对应规则合并后再拼接,逻辑清晰且效率高:

import pandas as pd
import numpy as np

# 拆分df1为两个子集
df1_non_nan = df1[~pd.isna(df1['Name'])]
df1_nan = df1[pd.isna(df1['Name'])]

# 非NaN子集:三键左合并
merge_non_nan = pd.merge(df1_non_nan, df2, 
                        how='left',
                        left_on=['Number', 'Number2', 'Name'],
                        right_on=['Number', 'Number2', 'Name2'])

# NaN子集:两键左合并
merge_nan = pd.merge(df1_nan, df2,
                    how='left',
                    left_on=['Number', 'Number2'],
                    right_on=['Number', 'Number2'])

# 拼接结果并恢复原索引顺序
result = pd.concat([merge_non_nan, merge_nan]).sort_index().reset_index(drop=True)

print(result)

方法二:先全量合并再补全匹配失败行

先执行三键合并,再针对Name为NaN且匹配失败的行,用两键合并补全结果:

import pandas as pd
import numpy as np

# 先执行三键合并,保留匹配状态标识
temp_merge = pd.merge(df1, df2,
                     how='left',
                     left_on=['Number', 'Number2', 'Name'],
                     right_on=['Number', 'Number2', 'Name2'],
                     indicator=True)

# 筛选出需要补全的行:Name为NaN且三键合并无匹配
mask = pd.isna(temp_merge['Name']) & (temp_merge['_merge'] == 'left_only')

# 对需要补全的行执行两键合并
nan_merge = pd.merge(temp_merge[mask], df2,
                    how='left',
                    left_on=['Number', 'Number2'],
                    right_on=['Number', 'Number2'])

# 合并最终结果,清理临时标识列
result = pd.concat([temp_merge[~mask], nan_merge]).drop(columns=['_merge']).sort_index().reset_index(drop=True)

print(result)

两种方法均能得到预期结果,且批量处理的效率远高于逐行合并方案,适合处理各类规模的数据集。


内容的提问来源于stack exchange,提问作者AvocadoToast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 16:45:30