Pandas使用apply调用多返回值函数时,如何直接提取多个独立Series
报错核心原因
你执行age, name = df["dict_col"].apply(unnest_dict)时的报错,本质是Series.apply返回的是一个和原列索引完全对齐的完整Series,每个元素是当前行函数返回的二元组。
直接对这个Series做解包时,Python会遍历Series的所有行元素拆分值——以你2行的DataFrame为例,遍历后一共会拿到4个待解包的值,却只准备了2个接收变量,自然触发too many values to unpack的错误。
你之前用列表推导逐行提取的写法逻辑是对的,但完全不需要手写Python层循环,用pandas原生能力就能直接提取出对齐索引的独立Series,以上方案可通用在任意需要多返回值的函数操作场景。
无需手写循环的实现方法
方法1:pandas 原生多返回值拆分(推荐,性能最优)
给apply方法传入result_type="expand"参数,pandas会自动把每一行的多返回值拆成独立的列,返回一个和原索引完全对齐的DataFrame,每一列按顺序对应一个函数返回值,不会打乱行顺序:
# 保留原函数的二元组返回逻辑即可 def unnest_dict(row): age = row["age"] name = row["name"] return (age, name) # 自动拆分多返回值为独立列 result = df["dict_col"].apply(unnest_dict, result_type="expand") # 按返回顺序直接取出对应Series age = result[0] name = result[1]
- 该方法是pandas内置的C层实现,大数量级下的运行速度远快于Python层的循环遍历。
- 生成的
age和name和原DataFrame的索引完全对齐,和你手写列表推导得到的结果无差异。
方法2:批量聚合转Series(灵活适配不定数量返回值)
如果不想手动给拆分后的列编号,可以用zip批量聚合所有返回值,再直接转换为对应Series,全程不需要手写遍历逻辑:
apply_result = df["dict_col"].apply(unnest_dict) # 按返回顺序聚合所有列,批量生成对齐索引的Series age, name = map(pd.Series, zip(*apply_result))
- 原理是
zip(*apply_result)会自动把所有元组的第1个元素聚为年龄列表、第2个元素聚为姓名列表,map(pd.Series)会自动继承原列的索引生成Series,不会出现行错位。
效果验证
两种方法的输出和你之前手写遍历的结果完全一致:
print(age) # 1 [1, 2] # 2 [3, 4] # dtype: object print(name) # 1 [john, doe] # 2 [foo, bar] # dtype: object
内容的提问来源于stack exchange,提问作者CutePoison
相关产品推荐
相关产品推荐

