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

基于条件DataFrame批量更新目标DataFrame值的性能优化求助

问题背景

我有一个约300行的条件DataFrame(命名为POOL):

pd.DataFrame({"PERSONALNR":["000009461","000009461"],"PERIODE":["202401","202402"],"MANDANT":["LB","LB"],"DA":["01","01"]})

其中PERSONALNR和PERIODE为匹配条件,需将MANDANT和DA的值替换到目标DataFrame(命名为LA)中。

目标DataFrame约有11万行,结构如下:

pd.DataFrame({"PERSONALNR":["000009461","000009461"],"PERIODE":["202401","202402"],"MANDANT":["LB","LB"],"DA":["01","01"], "KSTBEZ":["Springer pool","bla bla"]})

当前实现方案:

for row in POOL.itertuples():
    LA.loc[(LA.PERSONALNR==row.PERSONALNR)&(LA.PERIODE==row.PERIODE)&(LA.DA=="01")&(LA.KSTBEZ.str.contains("pool")),["MANDANT","DA"]]=[row.MANDANT,row.DA]

该方案处理11万行数据耗时约10秒,但处理100万行数据时耗时长达10分钟,现寻求更高效的优化方案。


优化方案

方法一:先筛选目标子集再批量合并(推荐)

利用pandas的向量化操作替代逐行循环,先定位需要更新的行,再通过合并批量赋值:

  1. 筛选LA中符合更新条件的子集:
mask = (LA["DA"] == "01") & LA["KSTBEZ"].str.contains("pool")
LA_subset = LA[mask].copy()
  1. 和POOL按匹配条件合并,获取新值:
merged = LA_subset.merge(POOL, on=["PERSONALNR", "PERIODE"], suffixes=("", "_new"), how="left")
  1. 更新子集并同步回原DataFrame:
# 用新值替换,未匹配到的保留原数据
merged["MANDANT"] = merged["MANDANT_new"].fillna(merged["MANDANT"])
merged["DA"] = merged["DA_new"].fillna(merged["DA"])
merged = merged.drop(["MANDANT_new", "DA_new"], axis=1)

# 同步回原LA
LA.update(merged)

方法二:构建字典映射批量更新

将POOL转换为匹配键值对的字典,直接批量映射赋值:

# 构建以(PERSONALNR, PERIODE)为键的映射字典
map_dict = POOL.set_index(["PERSONALNR", "PERIODE"])[["MANDANT", "DA"]].to_dict("index")

# 生成更新掩码
mask = (LA["DA"] == "01") & LA["KSTBEZ"].str.contains("pool")

# 批量赋值,未匹配到的保留原数据
LA.loc[mask, ["MANDANT", "DA"]] = (
    LA.loc[mask, ["PERSONALNR", "PERIODE"]]
    .apply(lambda x: map_dict.get(tuple(x), (x["MANDANT"], x["DA"])), axis=1)
    .tolist()
)

方法三:设置联合索引后直接更新

给两个DataFrame设置相同的联合索引,利用索引对齐快速更新:

# 设置联合索引
LA_indexed = LA.set_index(["PERSONALNR", "PERIODE"])
POOL_indexed = POOL.set_index(["PERSONALNR", "PERIODE"])

# 生成更新掩码
mask = (LA_indexed["DA"] == "01") & LA_indexed["KSTBEZ"].str.contains("pool")

# 批量更新匹配行
LA_indexed.loc[mask, ["MANDANT", "DA"]] = POOL_indexed.loc[LA_indexed[mask].index, ["MANDANT", "DA"]]

# 恢复原索引
LA = LA_indexed.reset_index()

性能说明

以上方案均采用pandas原生向量化操作,避免了逐行循环的性能损耗,百万级数据处理耗时可控制在几十秒内,远优于原循环方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:52:42