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

能否用Pandas的apply方法替代combine_first实现多列数据更新?

使用apply替代combine_first完成Pandas多列数据更新

首先明确你的需求:通过df1的id匹配df2、df3的no字段,更新df1里的date_i、rl、date_f列,同时保留原df1的其他字段(比如cho、gp),最终只保留cho不为空的行。

当然可以用apply来实现这个需求!相比combine_first的索引对齐逻辑,apply的逐行处理思路更直观,也更容易自定义更新规则。下面是具体的实现步骤:

步骤1:提前构建映射字典(提升效率)

为了避免在apply逐行处理时反复查询df2和df3(拖慢效率),我们先把需要匹配的字段转换成字典映射,这样查找值的速度会快很多:

import pandas as pd
import numpy as np

# 定义原始三个DataFrame
df1 = pd.DataFrame({'id' : ['1470', '1550', '1562', '1578', '1645', '1867', '1888', '2205', '2283', '2306'], 
                    'gp' : ['nl_i', 'adv_i', 'adv_i', 'nl_i', 'adv_i', 'early_i', 'nl_i', 'nl_i', 'nl_i', 'nl_i'], 
                    'cho' : [69626.0, 183425.0, 75418.0, 84239.0, 158721.0, 122857.0, 166052.0, 86686.0, 140407.0, 122792.0], 
                    'date_i' : ['2000-11-29', '2000-11-28', '2000-11-27', '2000-11-26', '2000-11-25', '2000-11-24', '2000-11-23', '2000-11-22', '2000-11-21', '2000-11-20'], })
df1['rl'] = np.NAN
df1['date_f'] = np.NAN

df2 = pd.DataFrame({'no' : ['2939', '2283', '1578', '2781', '2319', '2306', '1888', '1470', '2869', '2205'], 
                    'date_i' : ['2010-09-18', '2012-02-08', '2012-04-09', '2012-04-23', '2012-05-08', '2012-09-04', '2013-08-29', '2013-09-09', '2014-02-24', '2015-11-19'], 
                    'rl' : ['r', 'l', 'r', 'r', 'l', 'r', 'r', 'r', 'r', 'r']})

df3 = pd.DataFrame ({'no' : ['2319', '2306', '1888', '1470', '2869', '2205'], 
                     'date_f' : ['2019-05-10', '2013-09-24', '2019-06-12', '2016-08-29', '2016-10-10', '2017-11-30']})

# 构建映射字典:key是no/id,value是对应要更新的字段值
rl_map = df2.set_index('no')['rl'].to_dict()
df2_date_i_map = df2.set_index('no')['date_i'].to_dict()
df3_date_f_map = df3.set_index('no')['date_f'].to_dict()

步骤2:定义逐行更新的函数

写一个函数,接收df1的每一行数据,根据id去上面的字典里查找对应的值,更新目标列(如果找不到匹配的id,就保留原行的原值):

def update_row(row):
    # 更新rl列:如果id在rl_map里,用映射值,否则保留原row['rl']
    row['rl'] = rl_map.get(row['id'], row['rl'])
    # 更新date_i列:优先用df2的date_i,否则保留原df1的date_i
    row['date_i'] = df2_date_i_map.get(row['id'], row['date_i'])
    # 更新date_f列:如果id在df3的映射里,用对应值,否则保留原NaN
    row['date_f'] = df3_date_f_map.get(row['id'], row['date_f'])
    return row

步骤3:用apply执行更新并整理结果

调用df1.apply()逐行处理,最后做和原来combine_first一样的列顺序保留、空值过滤操作:

# 执行更新
df1_new = df1.apply(update_row, axis=1)

# 保持原df1的列顺序(和你原来的逻辑一致)
df1_new = df1_new[df1.columns]

# 过滤掉cho为空的行
df1_new.dropna(subset=['cho'], inplace=True)

效果对比

这个方法最终得到的df1_new和你用combine_first得到的结果完全一致。两者的区别在于:

  • combine_first是向量化操作,在大数据量下效率更高;
  • apply是逐行处理,逻辑更直观,如果你之后需要修改更新规则(比如添加条件判断),会更容易调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:28:07