如何用Python规范化含4层嵌套数组的复杂JSON结构?
解决嵌套JSON数据规范化生成目标DataFrame的问题
先明确示例数据(模拟你提到的4层嵌套结构)
sample_json = { "vendor_name": "ABC Corp", "score_card": { "risk_groups": [ { "name": "Acquisitions", "risk_score": None, "risks": [ { "name": "Unapproved Acquisitions", "risk_score": 7.5, "indicators": [ { "name": "Missing Approval Docs", "risk_score": 8.0 }, { "name": "Overbudget Spending", "risk_score": 7.0 } ] }, { "name": "Integration Risks", "risk_score": 6.0, "indicators": [ { "name": "Cultural Misalignment", "risk_score": 6.5 } ] } ] }, { "name": "Financial Health", "risk_score": 5.0, "risks": [ { "name": "Cash Flow Issues", "risk_score": 6.5, "indicators": [] } ] } ] } }
报错原因解析
你遇到的TypeError是因为pd.json_normalize在指定record_path时,路径对应的字段存在非列表值(比如某个risk_groups/risks/indicators不是数组),或者JSON结构存在不一致(比如部分节点缺失子数组)。直接用复杂路径时容易忽略这种结构差异,导致解析失败。
两种可行解决方案
方案1:结构一致时用pd.json_normalize快速展开
如果你的JSON结构完全统一(所有risk_groups都有risks数组,所有risks都有indicators数组),可以直接用多层record_path和meta参数提取:
import pandas as pd # 多层展开嵌套数组 df = pd.json_normalize( sample_json['score_card']['risk_groups'], record_path=['risks', 'indicators'], meta=[ ['name'], ['risk_score'], ['risks', 'name'], ['risks', 'risk_score'] ], errors='ignore' # 忽略空数组的情况 ) # 重命名列并调整顺序到目标结构 df.columns = [ 'indicator_name', 'indicator_risk_score', 'risk_group_name', 'risk_group_risk_score', 'risk_name', 'risk_risk_score' ] df = df[[ 'risk_group_name', 'risk_group_risk_score', 'risk_name', 'risk_risk_score', 'indicator_name', 'indicator_risk_score' ]] print(df)
方案2:递归遍历提取(适配结构不一致场景)
如果你的JSON存在结构差异(比如部分risks没有indicators数组),递归遍历的方式更可靠,也更容易调试:
import pandas as pd def extract_risk_details(json_data): result_list = [] # 遍历顶层risk_groups for risk_group in json_data['score_card']['risk_groups']: rg_name = risk_group.get('name') rg_score = risk_group.get('risk_score') # 遍历当前risk_group下的所有risks for risk in risk_group.get('risks', []): r_name = risk.get('name') r_score = risk.get('risk_score') # 处理indicators:没有的话生成空值行,有的话遍历每个indicator indicators = risk.get('indicators', []) if not indicators: result_list.append({ 'risk_group_name': rg_name, 'risk_group_risk_score': rg_score, 'risk_name': r_name, 'risk_risk_score': r_score, 'indicator_name': None, 'indicator_risk_score': None }) else: for indicator in indicators: result_list.append({ 'risk_group_name': rg_name, 'risk_group_risk_score': rg_score, 'risk_name': r_name, 'risk_risk_score': r_score, 'indicator_name': indicator.get('name'), 'indicator_risk_score': indicator.get('risk_score') }) return result_list # 生成DataFrame extracted_data = extract_risk_details(sample_json) target_df = pd.DataFrame(extracted_data) print(target_df)
方案选择建议
- 方案1代码简洁,适合结构完全规范的JSON;
- 方案2灵活性强,能处理各种结构不一致的情况,新手也能通过打印中间值快速调试。
内容的提问来源于stack exchange,提问作者Rafał Pietrak
相关产品推荐
相关产品推荐

