如何通过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
相关产品推荐
相关产品推荐

