如何基于另一Pandas DataFrame按规则补全Python中DataFrame的NaN值
问题描述
现有两个Pandas DataFrame:
df1 的定义与数据
import pandas as pd import numpy as np d1 = {'id': [1, 2, 3, 4], 'col1': [13, np.nan, 15, np.nan], 'col2': [23, np.nan, np.nan, np.nan]} df1 = pd.DataFrame(data=d1)
df1 数据展示:
| id | col1 | col2 |
|---|---|---|
| 1 | 13.0 | 23.0 |
| 2 | NaN | NaN |
| 3 | 15.0 | NaN |
| 4 | NaN | NaN |
df2 的定义与数据
d2 = {'id': [2, 3, 4], 'col1': [14, 150, 16], 'col2': [24, 250, np.nan]} df2 = pd.DataFrame(data=d2)
df2 数据展示:
| id | col1 | col2 |
|---|---|---|
| 2 | 14 | 24.0 |
| 3 | 150 | 250.0 |
| 4 | 16 | NaN |
替换规则
需用df2的非NaN值替换df1的NaN字段,满足以下条件:
- 两个DataFrame的
id列值唯一,替换时需匹配相同id - 两个DataFrame行数不一定相同
- 仅处理
col1和col2列,其他列不受影响 - 仅当df1对应行的
col1/col2存在NaN,且df2同id行的col1和col2均为非NaN时,才用df2的整行替换df1该行;若df2对应行有任一NaN,则不替换df1该行
预期结果
处理后df1应如下:
| id | col1 | col2 |
|---|---|---|
| 1 | 13.0 | 23.0 |
| 2 | 14 | 24 |
| 3 | 150.0 | 250.0 |
| 4 | NaN | NaN |
解决方案
推荐两种简洁的Pandas实现方式,都能完美满足需求:
方法一:分步清晰版
# 1. 筛选df2中col1和col2均非空的行——只有这些行具备替换资格 valid_updates = df2.dropna(subset=["col1", "col2"]) # 2. 按id左连接df1与有效更新行,获取对应可替换的值 merged = df1.merge(valid_updates, on="id", how="left", suffixes=("", "_from_df2")) # 3. 对col1和col2分别替换:优先用df2的有效值,无有效值则保留df1原数据 for col in ["col1", "col2"]: df1[col] = merged[f"{col}_from_df2"].combine_first(df1[col])
方法二:链式简洁版
如果追求代码更紧凑,可借助索引匹配实现:
# 筛选df2有效行并将id设为索引 valid_updates = df2.dropna(subset=["col1", "col2"]).set_index("id") # 将df1设为id索引,用combine_first自动匹配替换,最后重置索引恢复结构 df1 = df1.set_index("id").combine_first(valid_updates).reset_index()
核心逻辑说明
dropna(subset=["col1", "col2"]):精准过滤掉df2中任一目标列有空值的行,确保只有完全有效的数据参与替换combine_first:Pandas原生的缺失值替换方法,调用A.combine_first(B)时,会用B的非空值替换A的空值,A的非空值则保留,完全契合替换规则- 以
id为匹配键(索引或merge关联键),保证只有同id的行才会触发替换,符合id唯一的要求
运行后得到的结果与预期完全一致:
id col1 col2 0 1 13.0 23.0 1 2 14.0 24.0 2 3 150.0 250.0 3 4 NaN NaN
内容的提问来源于stack exchange,提问作者edn
相关产品推荐
相关产品推荐

