为何JSON代码片段可正常运行,完整文件加载却报Key Error?
问题:pd.json_normalize处理openFDA完整NDC文件时报KeyError,片段却正常
用pd.json_normalize指定record_path和meta参数处理JSON数据片段时运行正常,但加载完整的openFDA药品NDC JSON文件时,却抛出KeyError。
运行正常的片段代码
import pandas as pd data = { "meta": { "disclaimer": "Do not rely on openFDA to make decisions regarding medical care. While we make every effort to ensure that data is accurate, you should assume all results are unvalidated. We may limit or otherwise restrict your access to the API in line with our Terms of Service.", "terms": "https://open.fda.gov/terms/", "license": "https://open.fda.gov/license/", "last_updated": "2024-11-15", "results": { "skip": 0, "limit": 2, "total": 118943 } }, "results": [ { "product_ndc": "73647-062", "generic_name": "MENTHOL, CAMPHOR", "labeler_name": "Just Brands LLC", "brand_name": "JUST CBD - CBD AND THC ULTRA RELIEF", "active_ingredients": [ { "name": "CAMPHOR (SYNTHETIC)", "strength": "2 g/100g" }, { "name": "MENTHOL", "strength": "6 g/100g" } ], "finished": True, "packaging": [ { "package_ndc": "73647-062-04", "description": "113 g in 1 BOTTLE, PUMP (73647-062-04)", "marketing_start_date": "20230314", "sample": False } ], "listing_expiration_date": "20251231", "openfda": { "manufacturer_name": ["Just Brands LLC"], "spl_set_id": ["f664eb79-8897-3a49-e053-2995a90a37b4"], "is_original_packager": [True], "unii": ["5TJD82A1ET", "L7T10EIP3A"] }, "marketing_category": "OTC MONOGRAPH DRUG", "dosage_form": "GEL", "spl_id": "16c906dd-6989-9a79-e063-6394a90afa71", "product_type": "HUMAN OTC DRUG", "route": ["TOPICAL"], "marketing_start_date": "20230314", "product_id": "73647-062_16c906dd-6989-9a79-e063-6394a90afa71", "application_number": "M017", "brand_name_base": "JUST CBD - CBD AND THC ULTRA RELIEF" }, { "product_ndc": "0591-4039", "marketing_end_date": "20250930", "generic_name": "CLOBETASOL PROPIONATE", "labeler_name": "Actavis Pharma, Inc.", "brand_name": "CLOBETASOL PROPIONATE", "active_ingredients": [ { "name": "CLOBETASOL PROPIONATE", "strength": ".05 g/mL" } ], "finished": True, "packaging": [ { "package_ndc": "0591-4039-46", "description": "1 BOTTLE in 1 CARTON (0591-4039-46) / 59 mL in 1 BOTTLE", "marketing_start_date": "20150828", "marketing_end_date": "20250930", "sample": False }, { "package_ndc": "0591-4039-74", "description": "1 BOTTLE in 1 CARTON (0591-4039-74) / 125 mL in 1 BOTTLE", "marketing_start_date": "20150828", "marketing_end_date": "20250930", "sample": False } ], "openfda": { "manufacturer_name": ["Actavis Pharma, Inc."], "rxcui": ["861512"], "spl_set_id": ["907e425a-720a-4180-b97c-9e25008a3658"], "is_original_packager": [True], "unii": ["779619577M"] }, "marketing_category": "NDA AUTHORIZED GENERIC", "dosage_form": "SPRAY", "spl_id": "33a56b8b-a9a6-4287-bbf4-d68ad0c59e07", "product_type": "HUMAN PRESCRIPTION DRUG", "route": ["TOPICAL"], "marketing_start_date": "20150828", "product_id": "0591-4039_33a56b8b-a9a6-4287-bbf4-d68ad0c59e07", "application_number": "NDA021835", "brand_name_base": "CLOBETASOL PROPIONATE", "pharm_class": [ "Corticosteroid Hormone Receptor Agonists [MoA]", "Corticosteroid [EPC]" ] } ] } packaging_data = pd.json_normalize( data['results'], record_path=["packaging"], meta=['product_ndc', 'brand_name', 'generic_name'] ) active_ingredients_data = pd.json_normalize( data['results'], record_path=["active_ingredients"], meta=['product_ndc', 'brand_name', 'generic_name'] ) combined_data = pd.merge( packaging_data, active_ingredients_data, on=['product_ndc', 'brand_name', 'generic_name'], how='outer' )
加载完整文件报Key Error的代码
import pandas as pd import json import requests, zipfile, io, os cwd = os.getcwd() zip_url = 'https://download.open.fda.gov/drug/ndc/drug-ndc-0001-of-0001.json.zip' r = requests.get(zip_url) z = zipfile.ZipFile(io.BytesIO(r.content)) z.extractall(cwd) with open('drug-ndc-0001-of-0001.json', 'r') as file: data = json.load(file) packaging_data = pd.json_normalize( data['results'], record_path=["packaging"], meta=['product_ndc', 'brand_name', 'generic_name'] ) active_ingredients_data = pd.json_normalize( data['results'], record_path=["active_ingredients"], meta=['product_ndc', 'brand_name', 'generic_name'] ) combined_data = pd.merge( packaging_data, active_ingredients_data, on=['product_ndc', 'brand_name', 'generic_name'], how='outer' )
原因分析
完整的openFDA NDC数据中,部分条目缺失packaging、active_ingredients或者meta参数指定的字段(如product_ndc、brand_name),而测试用的片段数据所有字段都完整,因此未触发报错。pd.json_normalize默认会对缺失的record_path或元字段抛出KeyError。
解决办法
1. 直接添加errors='ignore'参数
这是最简单的解决方案,忽略缺失路径和元字段的条目,缺失字段会自动填充为NaN,不会中断程序运行:
import pandas as pd import json import requests, zipfile, io, os cwd = os.getcwd() zip_url = 'https://download.open.fda.gov/drug/ndc/drug-ndc-0001-of-0001.json.zip' r = requests.get(zip_url) z = zipfile.ZipFile(io.BytesIO(r.content)) z.extractall(cwd) with open('drug-ndc-0001-of-0001.json', 'r') as file: data = json.load(file) # 处理packaging数据,忽略缺失项 packaging_data = pd.json_normalize( data['results'], record_path=["packaging"], meta=['product_ndc', 'brand_name', 'generic_name'], errors='ignore' # 关键配置 ) # 处理active_ingredients数据,忽略缺失项 active_ingredients_data = pd.json_normalize( data['results'], record_path=["active_ingredients"], meta=['product_ndc', 'brand_name', 'generic_name'], errors='ignore' # 关键配置 ) combined_data = pd.merge( packaging_data, active_ingredients_data, on=['product_ndc', 'brand_name', 'generic_name'], how='outer' )
2. 提前过滤无效条目
如果需要保留完全有效的数据(排除缺失关键字段的条目),可以先过滤结果集:
import pandas as pd import json import requests, zipfile, io, os cwd = os.getcwd() zip_url = 'https://download.open.fda.gov/drug/ndc/drug-ndc-0001-of-0001.json.zip' r = requests.get(zip_url) z = zipfile.ZipFile(io.BytesIO(r.content)) z.extractall(cwd) with open('drug-ndc-0001-of-0001.json', 'r') as file: data = json.load(file) # 过滤出包含所有必要字段且子列表非空的条目 filtered_results = [ item for item in data['results'] if all(key in item for key in ['packaging', 'active_ingredients', 'product_ndc', 'brand_name', 'generic_name']) and len(item['packaging']) > 0 and len(item['active_ingredients']) > 0 ] # 用过滤后的结果处理 packaging_data = pd.json_normalize( filtered_results, record_path=["packaging"], meta=['product_ndc', 'brand_name', 'generic_name'] ) active_ingredients_data = pd.json_normalize( filtered_results, record_path=["active_ingredients"], meta=['product_ndc', 'brand_name', 'generic_name'] ) combined_data = pd.merge( packaging_data, active_ingredients_data, on=['product_ndc', 'brand_name', 'generic_name'], how='outer' )
内容的提问来源于stack exchange,提问作者Brad
相关产品推荐
相关产品推荐

