使用iterrows填充DataFrame df_3时返回NaN的问题及解决
问题:Pandas按动态列名取值填充DataFrame返回NaN的解决办法
数据与需求
有两个DataFrame:
df_1存储各届毕业生的分数,索引为日期:
import numpy as np import pandas as pd data_1 = {"Grad_22": [96, np.nan, np.nan], "Grad_23": [92, 97, np.nan], "Grad_24": [np.nan, 93, 95]} df_1= pd.DataFrame(data_1) df_1["DATE"] = pd.to_datetime(["2022-12-31","2023-12-31","2024-12-31"]) df_1.set_index("DATE", inplace=True)
输出的df_1:
Grad_22 Grad_23 Grad_24 DATE 2022-12-31 96.0 92.0 NaN 2023-12-31 NaN 97.0 93.0 2024-12-31 NaN NaN 95.0
df_2存储每年对应的毕业生类别(Sr/Jr)与分数列的映射,索引同样为日期:
data_2 = { "Sr": ["Grad_22","Grad_23"], "Jr": ["Grad_23","Grad_24"] } df_2 = pd.DataFrame(data_2) df_2["DATE"] = pd.to_datetime(["2022-12-31","2023-12-31"]) df_2.set_index("DATE", inplace=True)
输出的df_2:
Sr Jr DATE 2022-12-31 Grad_22 Grad_23 2023-12-31 Grad_23 Grad_24
需要用df_2的每行作为列名标签,从df_1中取值填充df_3:
data_3= {"Sr": [0, 0], "Jr": [0, 0]} df_3 = pd.DataFrame(data_3) df_3 ["DATE"] = pd.to_datetime(["2022-12-31","2023-12-31"]) df_3.set_index("DATE", inplace=True)
尝试用iterrows遍历赋值:
for index, row in df_2.iterrows(): df_3.loc[index] = df_1.loc[index, row]
期望得到:
Sr Jr DATE 2022-12-31 96.0 92.0 2023-12-31 97.0 93.0
但实际返回全NaN的df_3:
Sr Jr DATE 2022-12-31 NaN NaN 2023-12-31 NaN NaN
原因分析
问题出在索引对齐逻辑上:当用row(Series类型)作为df_1的列索引时,返回的Series的索引是Grad_xx这类分数列名,而不是df_3的Sr/Jr列名。Pandas赋值时会严格对齐索引,两者索引不匹配,导致无法正确填充值,最终返回NaN。
比如当index=2022-12-31时,df_1.loc[index, row]返回的结果是:
Grad_22 96.0 Grad_23 92.0 Name: 2022-12-31 00:00:00, dtype: float64
这个Series的索引是Grad_22和Grad_23,和df_3的Sr/Jr列索引完全不匹配,所以赋值后只能填充NaN。
解决方法
方法1:修正循环赋值的索引匹配
在循环中提取值后,重新匹配df_3的列索引:
for index, row in df_2.iterrows(): # 提取对应分数值,用df_3的列名作为新索引 score_values = df_1.loc[index, row].values df_3.loc[index] = pd.Series(score_values, index=df_3.columns)
方法2:向量化操作(推荐,避免循环)
用apply按行处理,直接生成目标结构的DataFrame:
df_3 = df_2.apply(lambda x: df_1.loc[x.name, x], axis=1)
这里x.name是每行的日期索引,x是该行的列名映射,apply(axis=1)按行处理后会自动生成与df_2结构一致的结果,直接赋值给df_3即可。
方法3:使用lookup函数(Pandas 1.2+支持)
通过lookup直接定位对应位置的值:
df_3 = pd.DataFrame({ col: df_1.lookup(df_2.index, df_2[col]) for col in df_2.columns }) df_3.index = df_2.index
以上三种方法都能得到期望的结果。
内容的提问来源于stack exchange,提问作者user23557334
相关产品推荐
相关产品推荐

