You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 19:01:10