
本文介绍一种递归方法,将具有三级嵌套结构的 json(含父子层级关系)高效扁平化为包含 id、name、code、level 和 parent_id 五列的 pandas dataframe,精准保留层级归属关系。
本文介绍一种递归方法,将具有三级嵌套结构的 json(含父子层级关系)高效扁平化为包含 id、name、code、level 和 parent_id 五列的 pandas dataframe,精准保留层级归属关系。
在处理树状结构的分类数据(如多级目录、组织架构或商品类目)时,原始 JSON 常以嵌套数组形式存储子节点(如 subLevelCategories),而直接使用 pd.json_normalize() 难以自动关联父级 ID。手动分层提取再拼接不仅代码冗长、易出错,且无法灵活应对动态深度(即使当前为三级,逻辑也应具备可扩展性)。最佳实践是采用递归遍历 + 父ID传递策略——在每层递归调用中显式传入当前节点的 id 作为下一层的 parent_id,从而天然构建完整的层级映射。
以下是完整、健壮的实现方案:
import pandas as pd
def flatten_categories(data, parent_id=0):
"""
递归扁平化嵌套分类数据
Parameters:
-----------
data : list of dict
待处理的分类数据列表(支持多根节点)
parent_id : int or None
当前层级的父节点ID;顶层默认为0(可按业务需求改为None或-1)
Returns:
--------
list of dict
扁平化后的记录列表,每项含 id, name, code, level, parent_id
"""
flattened = []
for item in data:
# 提取当前层级核心字段
flat_item = {
'id': item['id'],
'name': item['name'],
'code': item.get('code'), # 使用 get() 容错空字段
'level': item['level'],
'parent_id': parent_id
}
flattened.append(flat_item)
# 递归处理子节点(若存在且非空)
children = item.get('subLevelCategories')
if isinstance(children, list) and children:
flattened.extend(flatten_categories(children, parent_id=item['id']))
return flattened
# 示例数据(模拟 API 响应)
data = [
{
"id": 3372,
"name": "Archive",
"code": None,
"level": 1,
"subLevelCategories": [
{
"id": 16708,
"name": ".....",
"code": None,
"level": 2,
"subLevelCategories": [
{"id": 16727, "name": ".........", "code": None, "level": 3, "subLevelCategories": None},
{"id": 16726, "name": "........", "code": None, "level": 3, "subLevelCategories": None}
]
},
{
"id": 16701,
"name": ".......",
"code": None,
"level": 2,
"subLevelCategories": [
{"id": 16782, "name": "......", "code": None, "level": 3, "subLevelCategories": None},
{"id": 16785, "name": "......", "code": None, "level": 3, "subLevelCategories": None}
]
}
]
}
]
# 执行扁平化并转为 DataFrame
flattened_data = flatten_categories(data)
df = pd.DataFrame(flattened_data)
# 验证结果(按 level 排序便于观察层级)
df = df.sort_values(['level', 'id']).reset_index(drop=True)
print(df)
✅ 输出示例:
id name code level parent_id 0 3372 Archive None 1 0 1 16701 ....... None 2 3372 2 16782 ...... None 3 16701 3 16785 ...... None 3 16701 4 16708 ..... None 2 3372 5 16726 ........ None 3 16708 6 16727 ......... None 3 16708
? 关键设计说明:
- parent_id 传递机制:顶层调用设 parent_id=0,每进入子层即传入当前 item['id'],确保父子关系零丢失;
- 健壮性增强:使用 item.get('code') 和 isinstance(children, list) 避免 KeyError 或 TypeError;
- 可扩展性强:无需修改代码即可支持任意深度嵌套(不限于三级),且兼容多根节点(如 data 是列表);
- 性能友好:单次遍历完成全部扁平化,避免多次 json_normalize() 和 pd.concat() 的开销。
? 注意事项:
- 若实际 JSON 中 subLevelCategories 可能为 null(而非 [] 或缺失),item.get('subLevelCategories') 已安全处理;
- 如需保留原始字段顺序,可在 flat_item 构造时显式指定键顺序(Python 3.7+ 字典保持插入序);
- 对超大数据集,可考虑生成器版本减少内存占用,但本例简洁性优先。
该方法兼顾可读性、鲁棒性与可维护性,是处理层级 JSON 到关系型 DataFrame 的推荐范式。











