如何优雅将三层嵌套JSON转换为含parent_id的DataFrame
问题
我有一个三层嵌套的JSON数据,想要扁平化为包含id、name、code、level、parent_id这五列的DataFrame。目前能提取各层级的嵌套项,但找不到优雅的方式保留parent_id,求更简洁的实现思路。
现有代码:
source = response.json() print ('there are ' + str(len(source)) + ' records') df_L1 = df df_L2 = json_normalize(df_L1['subLevelCategories'][0]) df_L3 = json_normalize(df_L2['subLevelCategories'][0]) #store for later !!!!! df_L2_wrapper = df_L2['id'] df_L3_wrapper = df_L3['id'] df_L2_wrapper.name = 'parent_id' df_L3_wrapper.name = 'parent_id' df_L1 = df_L1.head(5) df_L2 = df_L2.head(5) df_L3 = df_L3.head(5) df_L3_wrapper = df_L3_wrapper.head(5) df_L2_wrapper = df_L2_wrapper.head(5) # Build of df_L1 df_L1 = df_L1.drop(['subLevelCategories'], axis=1) df_L1['parentid']=0 # Build of df_L2 df_L2 = df_L2.drop(['name','code','level'], axis=1) # Rename the Series df_L2 = json_normalize(df_L2['subLevelCategories'][0]) # Concatenate the DataFrame and the renamed Series df_L2 = pd.concat([df_L2, df_L2_wrapper], axis=1) df_L2 = df_L2.drop(['subLevelCategories'], axis=1) # ////// L2 is built. # Build of df_L3 df_L3 = df_L3.drop(['subLevelCategories'], axis=1) df_L3 = pd.concat([df_L3, df_L3_wrapper], axis=1) df_combined = pd.concat([df_L1, df_L2, df_L3], ignore_index=True)
注:已将示例JSON修正为数组格式,source来自以下请求:
response = requests.get(url, headers=headers) source = response.json()
示例JSON:
[ { "id": 3372, "name": "Archive", "code": null, "level": 1, "subLevelCategories": [ { "id": 16708, "name": ".....", "code": null, "level": 2, "subLevelCategories": [ { "id": 16727, "name": ".........", "code": null, "level": 3, "subLevelCategories": null }, { "id": 16726, "name": "........", "code": null, "level": 3, "subLevelCategories": null } ] }, { "id": 16701, "name": ".......", "code": null, "level": 2, "subLevelCategories": [ { "id": 16782, "name": "......", "code": null, "level": 3, "subLevelCategories": null }, { "id": 16785, "name": "......", "code": null, "level": 3, "subLevelCategories": null } ] } ] } ]
简洁实现思路
用递归遍历嵌套结构,每一层自动记录当前节点的parent_id,收集所有节点数据后直接转成DataFrame,代码简洁且扩展性强(后续层级变动也无需修改逻辑)。
实现代码:
import pandas as pd def flatten_categories(categories, parent_id=0): flat_data = [] for cat in categories: # 提取当前节点核心字段,带上父ID node = { 'id': cat['id'], 'name': cat['name'], 'code': cat['code'], 'level': cat['level'], 'parent_id': parent_id } flat_data.append(node) # 递归处理子节点,父ID设为当前节点ID if cat.get('subLevelCategories') and cat['subLevelCategories']: flat_data.extend(flatten_categories(cat['subLevelCategories'], parent_id=cat['id'])) return flat_data # 处理source并生成DataFrame flat_list = flatten_categories(source) df_combined = pd.DataFrame(flat_list)
代码说明
- 递归函数
flatten_categories接收分类列表和当前父ID,遍历每个节点时先将核心字段(带parent_id)加入结果列表 - 若节点存在子分类,自动递归处理子节点,把父ID设为当前节点的ID,子节点结果直接合并到总列表
- 无需手动拆分L1/L2/L3层级,不管嵌套层数是3层还是更多,都能自动适配
- 最终直接用总列表生成DataFrame,逻辑清晰且代码量仅为原代码的1/3左右
内容的提问来源于stack exchange,提问作者Maxcot
相关产品推荐
相关产品推荐

