如何用另一列上一行值填充Pandas DataFrame的NaN?自定义函数报错排查
Pandas填充NaN值函数的问题分析
问题背景
现有如下Pandas DataFrame:
import pandas as pd import numpy as np df = pd.DataFrame({"A":[0,np.nan,0,0,np.nan,1,np.nan,1,0,np.nan], "B":[0,1,0,0,1,1,1,0,0,0]})
需求:将A列中的NaN值替换为B列上一行对应的值,比如第2行(索引1)A列的NaN要替换为第1行(索引0)B列的0,第7行(索引6)A列的NaN要替换为第6行(索引5)B列的1。
用户定义了如下函数,但用apply调用后无法正常工作:
def impute_with_previous_B(df): for x in range(len(df)): if pd.isnull(df.loc[x,"A"]) == True: df.loc[x,"A"] = df.loc[x-1,"B"] df["A"] = df.apply(lambda x: impute_with_previous_B(x),axis=1)
错误原因分析
apply(axis=1)参数理解错误:apply(axis=1)是逐行处理数据,传入函数的是单行的Series对象,而非整个DataFrame。你的函数里依然用df.loc[x,"A"]这种操作整个DataFrame的写法,完全不匹配传入的参数,自然无法执行。- 函数无返回值:你的函数没有任何
return语句,apply执行后会返回一堆None,赋值给df["A"]会直接把整列变成NaN。 - 循环逻辑的潜在问题:就算不用
apply,直接调用这个函数,当索引为0(第一行)时,x-1=-1会取到DataFrame最后一行的B值,这不符合常规需求(第一行的NaN通常需要保留或单独处理)。
正确实现方式
推荐:Pandas向量化操作(高效简洁)
不用循环,直接通过布尔索引结合shift()方法实现,这是Pandas的最优写法:
# 筛选A列为NaN的行,将其值替换为B列上一行的值 df.loc[df["A"].isna(), "A"] = df["B"].shift(1)
执行后结果符合需求:
| A | B |
|---|---|
| 0.0 | 0 |
| 0.0 | 1 |
| 0.0 | 0 |
| 0.0 | 0 |
| 0.0 | 1 |
| 1.0 | 1 |
| 1.0 | 1 |
| 1.0 | 0 |
| 0.0 | 0 |
| 0.0 | 0 |
可选:循环实现(仅作理解用,不推荐)
如果一定要用循环,直接遍历DataFrame的索引即可,不需要apply:
for idx in df.index: if pd.isna(df.loc[idx, "A"]): # 跳过第一行,避免取到最后一行的B值 if idx > 0: df.loc[idx, "A"] = df.loc[idx-1, "B"] # 可选:如果第一行A是NaN,可以在这里加else处理,比如保持NaN
内容的提问来源于stack exchange,提问作者szaki
相关产品推荐
相关产品推荐

