如何用另一DataFrame的多行替换pandas DataFrame中的对应行?
解决Pandas多DataFrame合并保留行与列的问题
问题描述
定义的两个Pandas DataFrame如下:
import pandas as pd left = pd.DataFrame({"A": [1, 2], "B": ["a", "b"]}) left["C"] = pd.Series(dtype="int64") right = pd.DataFrame({"A": [1, 1], "B": ["a", "a"], "C": [10, 20]})
背景说明:right由left经loc过滤并添加列得到,匹配列的值一致,right可能有额外列。需要将多个right依次合并到left,期望输出为:
A B C 0 1 a 10 1 1 a 20 2 2 b NaN
尝试的三种方法均存在问题:
- loc赋值:
left.loc[left["A"] == right["A"]] = right,得到正确列但丢失一行; - merge:
left.merge(right, on="A", how="left"),得到所有行但列名被重命名,后续合并会更麻烦; - join:
left.join(right, on="A", how="left", rsuffix="R"),既丢失行又重命名列。
解决方案
要实现需求,核心是保留right的所有匹配行,同时保留left中未匹配的行,推荐两种实用方法:
方法1:拼接匹配行与未匹配行(简单直接)
# 提取left中未出现在right里的行(按A列判断) unmatched_rows = left[~left["A"].isin(right["A"])] # 拼接right的所有行和未匹配行,重置索引 final_df = pd.concat([right, unmatched_rows], ignore_index=True) # 可选:按A列排序让结果更规整 final_df = final_df.sort_values(by="A", ignore_index=True)
运行后得到的结果完全符合预期:
A B C 0 1 a 10.0 1 1 a 20.0 2 2 b NaN
方法2:Merge+字段覆盖(适合多right依次合并场景)
如果后续要合并多个类似的right,这种方法不会出现列名混乱的问题:
# 以A、B为匹配键,outer merge保留所有行 merged = left.merge(right, on=["A", "B"], how="outer", suffixes=("", "_tmp")) # 用right的C值覆盖原C列的空值,删除临时列 merged["C"] = merged["C_tmp"].combine_first(merged["C"]) merged = merged.drop(columns=["C_tmp"]).reset_index(drop=True)
后续合并新的right时,只需将merged作为新的left,重复上述merge和字段覆盖步骤即可,始终保持列名一致。
之前方法的问题原因
- loc赋值:
left["A"] == right["A"]会做广播匹配,只能匹配到left中第一行A=1的记录,无法容纳right的两行数据,导致丢行; - 仅按A列merge:会让left的A=1行和right的两行生成笛卡尔积,同时产生
C_x、C_y这类重复列; - join:默认按索引匹配,指定
on="A"后同样会出现笛卡尔积和列名重复,且索引不对齐会导致丢行。
内容的提问来源于stack exchange,提问作者Woody1193
相关产品推荐
相关产品推荐

