求助:Pandas中for循环内.replace无法按行迭代替换NaN值
问题
需要将DataFrame中Leg和SAP列的NaN值替换为对应行的ID列值,且不修改其他列。但使用for循环调用pandas.replace()时,所有NaN都被替换成了同一个ID值,无法按行对应替换。
代码示例
import pandas as pd import numpy as np df1 = pd.read_csv("df1.csv") df2 = pd.read_csv("df2.csv") print(df1) print(df2) df3 = pd.merge(df1, df2, on='ID', how='left') print(df3) C = len(df3.index) for i in range(C): if pd.isnull(df3.at[i, 'Leg']) == True: df3.replace((df3.at[i, 'Leg']), (df3.at[i, 'ID']), inplace=True) df3.replace((df3.at[i, 'SAP']), (df3.at[i, 'ID']), inplace=True) print(df3)
当前执行结果
ID Desc QTY 0 100 Test1 1 1 200 Test2 7 2 300 Test3 1 3 400 Test4 3 4 500 Test5 4 5 600 Test6 9 ID Leg SAP 0 100 165-8 142.0 1 200 NaN 655.0 2 300 NaN NaN 3 400 21-56 4343.0 4 500 65-5 NaN 5 600 556-4 233.0 ID Desc QTY Leg SAP 0 100 Test1 1 165-8 142.0 1 200 Test2 7 NaN 655.0 2 300 Test3 1 NaN NaN 3 400 Test4 3 21-56 4343.0 4 500 Test5 4 65-5 NaN 5 600 Test6 9 556-4 233.0 ID Desc QTY Leg SAP 0 100 Test1 1 165-8 142.0 1 200 Test2 7 200 200.0 2 300 Test3 1 200 200.0 3 400 Test4 3 21-56 4343.0 4 500 Test5 4 65-5 200.0 5 600 Test6 9 556-4 233.0
预期结果
ID Desc QTY Leg SAP 0 100 Test1 1 165-8 142.0 1 200 Test2 7 200 655.0 2 300 Test3 1 300 300.0 3 400 Test4 3 21-56 4343.0 4 500 Test5 4 65-5 500.0 5 600 Test6 9 556-4 233.0
问题原因
df.replace()方法默认会替换整个DataFrame中所有匹配的值,而非仅当前行的目标值。第一次循环(i=1)时,会把全表所有NaN替换成200,后续循环里已无NaN可处理,导致所有原NaN都变成第一个被处理的ID值。同时循环判断逻辑有漏洞:仅当Leg为NaN时才执行替换,会漏掉Leg非NaN但SAP为NaN的行(如i=4)。
解决方案
方法一:使用Pandas向量化操作(推荐)
用fillna()针对指定列按行匹配填充,效率远高于循环:
import pandas as pd import numpy as np df1 = pd.read_csv("df1.csv") df2 = pd.read_csv("df2.csv") df3 = pd.merge(df1, df2, on='ID', how='left') # 用对应行ID填充Leg和SAP的NaN df3['Leg'] = df3['Leg'].fillna(df3['ID'].astype(str)) # Leg是字符串类型,ID转字符串匹配格式 df3['SAP'] = df3['SAP'].fillna(df3['ID']) # SAP是数值型,直接用ID填充 print(df3)
说明
fillna()可接收Series作为填充值,自动按行匹配,仅修改目标列的NaN,不影响其他列。- 类型匹配:Leg列是字符串格式,需把数值型ID转为字符串再填充;SAP列是数值型,直接用ID填充即可。
方法二:修正循环写法(不推荐)
若必须用循环,直接定位单元格赋值,而非使用replace():
import pandas as pd import numpy as np df1 = pd.read_csv("df1.csv") df2 = pd.read_csv("df2.csv") df3 = pd.merge(df1, df2, on='ID', how='left') C = len(df3.index) for i in range(C): # 单独判断并替换Leg列的NaN if pd.isnull(df3.at[i, 'Leg']): df3.at[i, 'Leg'] = str(df3.at[i, 'ID']) # 单独判断并替换SAP列的NaN if pd.isnull(df3.at[i, 'SAP']): df3.at[i, 'SAP'] = df3.at[i, 'ID'] print(df3)
说明
df.at[i, '列名']精准定位单元格,赋值仅修改目标位置,不会影响全表。- 分开判断
Leg和SAP的NaN情况,避免遗漏。
内容的提问来源于stack exchange,提问作者Richard B
相关产品推荐
相关产品推荐

