如何高效将含计划、活动、项目层级关系的Pandas DataFrame转换为字典列表?
高效实现Pandas多层级DataFrame转嵌套字典列表
Hey there! Let's tackle this problem of converting your hierarchical DataFrame into that nested dictionary list structure. First, let's recap your scenario:
问题回顾
你有这样一个存储计划-活动-项目层级关系的DataFrame:
| plan_id | plan_name | activity_id | activity_name | item_id | item_name |
|---|---|---|---|---|---|
| 1 | plan1 | 1 | activity1 | 1 | item1 |
| 1 | plan1 | 2 | activity2 | 3 | item3 |
| 2 | plan2 | 1 | activity1 | 1 | item1 |
目标是转换成每个计划包含下属活动、每个活动包含下属项目的嵌套字典列表,最终结构你已经明确给出。
你自己实现了一种拆分DataFrame后循环嵌套的方案:
plans_dict = plans_df.to_dict('records') for plan in plans_dict: plan['activities'] = activities_df[activities_df['id']==plan['id']].to_dict('records') for activity in plan['activities']: activity['items'] = items_df[items_df['activity_id']==activity['activity_id']].to_dict('records')
这个方案在小数据量下没问题,但如果数据规模变大,多次的切片查询会带来不少性能损耗,而且Python层面的循环效率也不如Pandas的向量化操作。下面给你两种更高效的实现思路:
更优实现方案
方案1:双层GroupBy + 嵌套聚合(性能最优)
这个思路是从最底层的项目开始,逐层向上聚合,全程用Pandas的内置操作,避免显式循环:
import pandas as pd # 假设你的原始DataFrame名为df def get_items(group): # 把每个活动下的项目转换成字典列表 return group[['item_id', 'item_name']].to_dict('records') def get_activities(group): # 对每个计划下的活动分组,聚合出对应的项目列表 activity_groups = group.groupby(['activity_id', 'activity_name']).apply(get_items).reset_index() activity_groups.columns = ['activity_id', 'activity_name', 'items'] return activity_groups.to_dict('records') # 对计划分组,聚合出对应的活动列表 plan_groups = df.groupby(['plan_id', 'plan_name']).apply(get_activities).reset_index() plan_groups.columns = ['plan_id', 'plan_name', 'activities'] # 生成最终的嵌套字典列表 final_result = plan_groups.to_dict('records')
为什么这个更高效?
- 全程用Pandas的GroupBy和Apply,都是C层面的优化操作,比Python循环快得多
- 只做了两次分组操作,避免了多次切片查询的开销,数据量越大,性能提升越明显
方案2:分组后字典推导(简洁易读)
如果追求代码的简洁性和可读性,也可以用分组+字典推导的方式,虽然有循环,但循环的是分组结果(数量远少于原始数据行数):
final_result = [] # 先按计划分组 for (plan_id, plan_name), plan_data in df.groupby(['plan_id', 'plan_name']): activities_list = [] # 再在每个计划内按活动分组 for (act_id, act_name), act_data in plan_data.groupby(['activity_id', 'activity_name']): # 生成当前活动的项目列表 items = act_data[['item_id', 'item_name']].to_dict('records') activities_list.append({ 'activity_id': act_id, 'activity_name': act_name, 'items': items }) # 把当前计划加入结果列表 final_result.append({ 'plan_id': plan_id, 'plan_name': plan_name, 'activities': activities_list })
这个方案比你的原始方案高效很多,因为它避免了每次循环都做一次布尔索引切片,而是直接基于分组后的子集操作,减少了不必要的数据复制。
性能对比小总结
- 你的原始方案:时间复杂度接近O(n*m)(n为计划数,m为活动数),数据量大时会明显变慢
- 推荐的方案:时间复杂度更接近O(n),利用Pandas的向量化操作,性能提升显著
内容的提问来源于stack exchange,提问作者psowa001
相关产品推荐
相关产品推荐

