You need to enable JavaScript to run this app. 如何通过pandas.DataFrame.apply()一次性生成多个新列
优惠活动
大模型
产品
解决方案
定价
更多

如何通过pandas.DataFrame.apply()一次性生成多个新列

一次性生成多列的正确实现方案

你提供的错误伪代码无法运行的核心原因:df.apply 逐行调用函数时,若函数返回裸元组/普通列表,pandas会将整个返回值作为单个对象存入单列,不会自动拆分给多列;同时pandas也不会自动对apply的返回结果做解包,匹配多个目标列名。

核心实现逻辑

只要让逐行执行的函数返回带列名索引的pandas.Series对象,apply 就会自动把所有行的计算结果对齐成一个多列的DataFrame,全程仅对每行执行一次计算,不存在重复调用函数的开销。

可直接运行的代码示例

1. 常规自定义函数写法(适合计算逻辑复杂、需要单独封装的场景)

from eunrg_utils.testing_functions.random_dataframe import random_dataframe
import pandas as pd

df = random_dataframe(columns=2, rows=4)

# 自定义单行计算函数,返回带目标列名的Series
def my_func(row):
    value1 = row.A + row.B
    value2 = row.B - row.A
    # Series的索引名就是要生成的DataFrame列名,与返回值一一对应
    return pd.Series({"X": value1, "Y": value2})

# 一次性执行apply,得到与原df索引完全对齐的多列结果
new_cols = df.apply(axis=1, func=my_func)
# 直接把新列合并回原DataFrame
df[new_cols.columns] = new_cols

2. 简洁的lambda写法(适合计算逻辑简单的场景)

from eunrg_utils.testing_functions.random_dataframe import random_dataframe
import pandas as pd

df = random_dataframe(columns=2, rows=4)

# 直接在lambda中返回带指定索引的Series
df[["X", "Y"]] = df.apply(
    axis=1,
    func=lambda row: pd.Series(
        data=[row.A + row.B, row.B - row.A],
        index=["X", "Y"]
    )
)

关键注意事项

  • 不要让函数直接返回裸元组、普通Python列表作为返回值,否则pandas会把整行计算结果当成单个对象塞到单列中,无法自动拆分为多列
  • 该方案不需要额外编写缓存逻辑,每一行的所有衍生值都会在一次函数调用中全部计算完成;相比逐次调用apply逐列生成的写法,该方案仅遍历一次DataFrame行,计算开销减少近一半,行数越多性能优势越明显
  • 如果不想修改原有自定义函数的返回值格式(即函数本身返回裸元组),也可以通过转换的方式实现多列拆分:
# 原有自定义函数返回固定顺序的元组,不需要改动函数内部逻辑
def my_func(row):
    return (row.A + row.B, row.B - row.A)

# 拿到apply返回的、每行为元组的Series
apply_result = df.apply(axis=1, func=my_func)
# 把元组列表转换为与原df索引对齐、带指定列名的DataFrame
new_cols = pd.DataFrame(apply_result.tolist(), index=df.index, columns=["X", "Y"])
# 合并到原df
df[["X", "Y"]] = new_cols

上述转换写法的最终效果和函数直接返回带索引Series的写法完全一致,适合不想调整已有函数返回格式的存量代码场景。


内容的提问来源于stack exchange,提问作者Salim Fadhley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.29 21:45:02