使用.loc赋值Pandas apply扩展结果时出现NaN列,[]索引却正常
Pandas apply+loc多列赋值NaN问题分析与解决
复现代码
基于pandas==2.2.1的完整可复现示例:
import pandas as pd df = pd.DataFrame({"a":["ABC", "DEF", "GHI"], "b":[1, 2, 3]}) def some_func(param_a: str, param_b: int) -> tuple[str, str]: output_a = param_a + " " + str(param_b) output_b = param_a.lower() + " " + str(param_b) return output_a, output_b # []索引赋值:正常生成新列 df['new_col1'], df['new_col2'] = zip(*df.apply(lambda x: some_func(x['a'], x['b']), axis=1)) print("[]索引赋值结果:") print(df) # .loc赋值:新列全为NaN df.loc[:, 'new_col3'], df.loc[:, 'new_col4'] = zip(*df.apply(lambda x: some_func(x['a'], x['b']), axis=1)) print("\n.loc赋值结果:") print(df)
原因说明
这不是bug,是Pandas .loc 多列赋值的特性导致的:
- 用
zip(*df.apply(...))解包后得到两个独立的迭代器,它们没有绑定DataFrame的索引元数据。 .loc在同时对多列赋值时,要求右侧数据必须能和目标索引对齐,迭代器无法提供这种对齐依据,最终Pandas无法正确匹配数据,只能填充NaN。- 而直接用
[]索引赋值时,Pandas会自动将迭代器转换为带默认索引的Series,能和原DataFrame索引匹配,因此可以正常赋值。
解决办法
方法1:先转DataFrame再赋值
把apply的结果转换成DataFrame,再通过.loc一次性赋值:
# 将apply返回的元组序列转为DataFrame result_df = df.apply(lambda x: pd.Series(some_func(x['a'], x['b'])), axis=1) # 用.loc批量赋值多列 df.loc[:, ['new_col3', 'new_col4']] = result_df
方法2:拆分单列赋值
避免同时操作多列,单独给每列用.loc赋值:
# 将解包结果转为列表,方便索引调用 results = list(zip(*df.apply(lambda x: some_func(x['a'], x['b']), axis=1))) # 单独为每列赋值 df.loc[:, 'new_col3'] = results[0] df.loc[:, 'new_col4'] = results[1]
方法3:用assign方法替代(更简洁)
如果不需要强制使用.loc,assign方法语法清晰且不会出现该问题:
df = df.assign(**dict(zip(['new_col3', 'new_col4'], zip(*df.apply(lambda x: some_func(x['a'], x['b']), axis=1)))))
内容的提问来源于stack exchange,提问作者DLJ
相关产品推荐
相关产品推荐

