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

多条件关联下更新Pandas DataFrame列的最佳实践探讨

Pandas条件更新DataFrame的最优实现方式

先明确我们的数据源:

import pandas as pd

df1 = pd.DataFrame([["SAP       ", 1, 'CHANGE_NEEDED', 10, 11],
                   ["SAP123", 1, 'CORRECT_VALUE', 10, 11],
                   ["NOTSAP123", 1, 'INCORRECT_VALUE', 10, 11],
                   ["NOTSAP456", 1, 'INCORRECT_VALUE', 10, 11]],
                  columns = ["RCD_ORIG_CD", "VEN_ID", "VLC_VEN_ID", "CNTRY_CD", "CO_CD"])
df2 = pd.DataFrame([["SAP_CORRECT_VALUE", 1, 'CORRECT_VALUE', 12, 13],
                    ["SAB123",1, "THIS_WONT_BE_USED", 12,13],
                    ["NOTSAP123", 1, 'CORRECT_VALUE', 10, 11],
                    ["NOTSAP457", 1, 'INCORRECT_VALUE', 10, 11]],
                    columns = ["RCD_ORIG_CD", "VEN_ID", "VLC_VEN_ID", "CNTRY_CD", "CO_CD"])

df1初始状态:

RCD_ORIG_CD  VEN_ID       VLC_VEN_ID  CNTRY_CD  CO_CD
0  SAP              1    CHANGE_NEEDED        10     11
1      SAP123       1    CORRECT_VALUE        10     11
2   NOTSAP123       1  INCORRECT_VALUE        10     11
3   NOTSAP456       1  INCORRECT_VALUE        10     11

df2初始状态:

RCD_ORIG_CD  VEN_ID         VLC_VEN_ID  CNTRY_CD  CO_CD
0  SAP_CORRECT_VALUE       1      CORRECT_VALUE        12     13
1             SAB123       1  THIS_WONT_BE_USED        12     13
2          NOTSAP123       1      CORRECT_VALUE        10     11
3          NOTSAP457       1    INCORRECT_VALUE        10     11

需要执行的更新规则整理如下:

  1. 如果df1的RCD_ORIG_CD前3位是"SAP":
    • 找到df2中VEN_ID相同且RCD_ORIG_CD前3位也是"SAP"的行,将df1的VLC_VEN_ID替换为该行的对应值;若df1的RCD_ORIG_CD是带空格的"SAP ",同时把该字段替换为df2对应的RCD_ORIG_CD
    • 找不到符合条件的df2行,就把df1的VLC_VEN_ID设为8个空格
  2. 如果df1的RCD_ORIG_CD不是SAP开头,但和df2的RCD_ORIG_CD、VEN_ID、CNTRY_CD、CO_CD完全匹配:
    • 将df1的VLC_VEN_ID替换为df2对应的VLC_VEN_ID
  3. 其他情况,把df1的VLC_VEN_ID设为8个空格

方案分析与最佳实践

为什么别用iterrows()

直接用iterrows()逐行循环是最直观但最糟糕的选择——Pandas的核心优势是向量化操作,底层基于numpy的C实现,而逐行循环相当于把Pandas当成普通列表用,数据量稍微大一点就会慢到离谱,完全浪费了Pandas的性能优势,绝对不推荐。

推荐方案:向量化关联+条件判断

核心思路是通过预筛选+多条件关联,把需要匹配的行先对应起来,再用np.where或者loc批量更新,全程避免循环。

代码实现

import pandas as pd
import numpy as np

# 1. 添加辅助列,标记是否为SAP开头的行
df1['is_sap'] = df1['RCD_ORIG_CD'].str[:3] == 'SAP'
df2['is_sap'] = df2['RCD_ORIG_CD'].str[:3] == 'SAP'

# 2. 准备SAP场景的匹配:按VEN_ID关联df2的SAP行(去重避免行膨胀)
sap_df2 = df2[df2['is_sap']].drop_duplicates('VEN_ID')
df1 = df1.merge(sap_df2[['VEN_ID', 'VLC_VEN_ID', 'RCD_ORIG_CD']], 
                on='VEN_ID', how='left', suffixes=('', '_sap'))

# 3. 准备非SAP场景的匹配:按多键完全匹配
non_sap_df2 = df2[~df2['is_sap']]
df1 = df1.merge(non_sap_df2[['RCD_ORIG_CD', 'VEN_ID', 'CNTRY_CD', 'CO_CD', 'VLC_VEN_ID']],
                on=['RCD_ORIG_CD', 'VEN_ID', 'CNTRY_CD', 'CO_CD'], how='left', suffixes=('', '_non_sap'))

# 4. 按规则更新VLC_VEN_ID
df1['VLC_VEN_ID'] = np.where(
    df1['is_sap'],
    np.where(df1['VLC_VEN_ID_sap'].notna(), df1['VLC_VEN_ID_sap'], '        '),
    np.where(df1['VLC_VEN_ID_non_sap'].notna(), df1['VLC_VEN_ID_non_sap'], '        ')
)

# 5. 更新带空格的SAP开头行的RCD_ORIG_CD
df1.loc[(df1['is_sap']) & (df1['RCD_ORIG_CD'] == 'SAP       '), 'RCD_ORIG_CD'] = df1['RCD_ORIG_CD_sap']

# 6. 清理辅助列
df1 = df1.drop(['is_sap', 'VLC_VEN_ID_sap', 'RCD_ORIG_CD_sap', 'VLC_VEN_ID_non_sap'], axis=1)

print(df1)

执行后得到的df1结果:

RCD_ORIG_CD  VEN_ID       VLC_VEN_ID  CNTRY_CD  CO_CD
0  SAP_CORRECT_VALUE       1    CORRECT_VALUE        10     11
1              SAP123       1    CORRECT_VALUE        10     11
2           NOTSAP123       1    CORRECT_VALUE        10     11
3           NOTSAP456       1                 10     11

关键细节说明

  • 合并时用drop_duplicates是为了避免一对多匹配导致的行膨胀,如果df2中同一个VEN_ID对应多个SAP行,需要先确定取哪一行(比如最新/最早)
  • 用np.where实现嵌套条件判断,完全是向量化操作,性能比循环高几个数量级
  • 最后清理辅助列,保持原DataFrame的结构整洁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:31:05