
本文介绍一种无需双重 for 循环的简洁方法,利用 `groupby().apply()` 链式调用,将 dataframe 按多个列分组并转换为深度嵌套字典(如 `{level1: {level2: [{record}, ...]}}` 结构)。
在数据处理中,常需将扁平化的 DataFrame 转换为结构化嵌套字典,尤其适用于生成 API 响应、配置文件或前端可消费的层级数据。传统双重循环虽直观,但代码冗长、可读性差且难以扩展。Pandas 提供了更优雅的函数式方案:嵌套 groupby().apply() 配合 to_dict(orient='records')。
核心思路是逐级分组:先按第一级键(如 'col1')分组,再对每个子组按第二级键(如 'col2')进一步分组,最后将每组记录转为字典列表。关键在于正确使用 .to_dict('index') ——它能将 Series 或 DataFrame 的索引作为键、值作为对应嵌套结构,从而自然构建两级字典。
以下为完整实现示例:
import pandas as pd
a = pd.DataFrame([
{'col1': 'A', 'col2': 'Person 1', 'height': 1, 'weight': 10},
{'col1': 'A', 'col2': 'Person 1', 'height': 2, 'weight': 20},
{'col1': 'A', 'col2': 'Person 1', 'height': 3, 'weight': 30},
{'col1': 'A', 'col2': 'Person 2', 'height': 4, 'weight': 40},
{'col1': 'A', 'col2': 'Person 2', 'height': 5, 'weight': 50},
{'col1': 'A', 'col2': 'Person 2', 'height': 6, 'weight': 60},
{'col1': 'B', 'col2': 'Person 1', 'height': 11, 'weight': 101},
{'col1': 'B', 'col2': 'Person 1', 'height': 21, 'weight': 201},
{'col1': 'B', 'col2': 'Person 1', 'height': 31, 'weight': 301},
{'col1': 'B', 'col2': 'Person 2', 'height': 41, 'weight': 401},
{'col1': 'B', 'col2': 'Person 2', 'height': 51, 'weight': 501},
{'col1': 'B', 'col2': 'Person 2', 'height': 61, 'weight': 601},
])
# ✅ 推荐:单行链式调用,生成两级嵌套字典
result = (a.groupby('col1')
.apply(lambda x: x.groupby('col2').apply(lambda y: y.to_dict('records')))
.to_dict('index'))
print(result.keys()) # dict_keys(['A', 'B'])
print(list(result['A'].keys())) # ['Person 1', 'Person 2']
print(len(result['A']['Person 1'])) # 3⚠️ 注意事项:
- .to_dict('index') 是关键:若误用 .to_dict()(默认 orient='dict'),会返回列优先结构,破坏嵌套逻辑;
- 所有分组列(如 'col1', 'col2')必须存在于原始 DataFrame 中,且值类型需支持哈希(如字符串、数字);
- 若需更多层级(如三级嵌套),可继续嵌套 groupby().apply(),但建议超过两层时改用 set_index().unstack() 或自定义递归函数以提升可维护性;
- 性能方面,该方法在中等规模数据(
总结:相比手动循环,嵌套 groupby().apply() 不仅代码更简洁、语义更清晰,还天然支持链式扩展与函数复用,是 Pandas 用户构建层级数据结构的首选范式。










