pandas应用自定义字典拆分函数触发'DataFrame' object is not callable报错
Pandas 字典列拆分封装触发
TypeError 报错排查 场景说明
- 日常数据处理中持有多个独立 pandas DataFrame,其中至少1列存储字符串格式的字典内容,单条值示例为
{'description': 'Customer Operations', 'code': '51254185'} - 未做封装时,可通过原生逻辑将字典列拆分为独立列,最终可实现类似下表的效果:
| fiscalYear | prodID | position | position_name | positionID |
|---|---|---|---|---|
| 2020 | 123 | {'des': 'Customer Operations', 'code': '51254185'} | Customer Operations | 51254185 |
| 2020 | 456 | {'des': 'Support', 'code': '50544654'} | Support | 50544654 |
- 原生可运行的拆分逻辑代码:
position_df['position'] = main_df['position'].apply(lambda x: dict(eval(x))) position_df = position_df['position'].apply(pd.Series) position_df.rename(columns={'des': 'position_name', 'code':'positionID'},inplace=True) result = pd.concat([main_df, position_df], axis=1, join="inner")
报错表现
将上述拆分逻辑封装为通用函数后,调整入参调用时触发 TypeError: 'DataFrame' object is not callable 报错,封装的函数与实际调用代码如下:
def dictionary_to_columns(dic_column,rename_col,df): temp_df = pd.DataFrame() temp_df['temporary'] = df[dic_column].apply(lambda x: dict(eval(x))) temp_df = temp_df['temporary'].apply(pd.Series) temp_df.rename(columns=rename_col,inplace=True) result = pd.concat([df, temp_df], axis=1, join="inner") return result # 触发报错的调用代码 main_df['position'] = main_df['position'].apply(dictionary_to_columns('position',{'des': 'name', 'code':'ID'},main_df))
已完成的初步排查:在函数
return语句前打印拆分结果的前5行,内容显示完全正常,无内部逻辑异常。
问题定位与修复
根因
问题和函数返回逻辑完全无关,出在调用方式的错配上:
- 上述调用代码的执行顺序是:先执行括号内的
dictionary_to_columns(...),直接得到一个已经拼接完成的 DataFrame 结果,再把这个结果作为参数传给外层的main_df['position'].apply()方法。 - pandas 的
apply()方法要求传入的必须是可调用的函数对象,现在传入的是一个静态的 DataFrame,自然会抛出TypeError: 'DataFrame' object is not callable。 - 这个封装函数本身是整表维度的处理逻辑:入参已经包含了全量 df、待拆分的列名、列重命名规则,是一次性完成全表的字典拆分、结果拼接,完全不需要套在逐元素处理的
apply()方法里。
修复代码
直接去掉外层多余的 main_df['position'].apply() 包裹,直接调用封装函数即可:
# 错误写法(触发报错) # main_df['position'] = main_df['position'].apply(dictionary_to_columns('position',{'des': 'name', 'code':'ID'},main_df)) # 正确写法 result = dictionary_to_columns( dic_column='position', rename_col={'des': 'name', 'code':'ID'}, df=main_df )
可选优化点
- 原代码用
eval()解析字符串字典存在安全风险,若处理的字符串来源不是绝对可信的场景,建议替换为ast.literal_eval(),解析更安全且性能更优。 - pandas 版本 ≥1.4.0 时,可直接用字符串访问器快速拆分字典列,不需要手动
apply转 Series,代码更简洁:import ast temp_df = main_df['position'].apply(ast.literal_eval).str.split(expand=True)
内容的提问来源于stack exchange,提问作者Kroky1
相关产品推荐
相关产品推荐

