如何从Python嵌套字典列表提取指定键高效生成DataFrame?
高效解析嵌套字典生成DataFrame的方法
问题背景
我有如下嵌套结构的字典:
from decimal import Decimal data_dict = {'Company': [ { 'Date': [{'L_End': {'@value': '2013-03-31'}, 'L_Start': {'@value': '2006-10-01'}, 'Type': {'@value': 'L'}}, {'O_Start': {'@value': '2006-10-01'}, 'Type': {'@value': 'O'}}], 'GeoLoc': {'Location': {'AddrLn1': 'HIGHLAND ROAD', 'Country': 'ENGLAND', 'County': 'HAMPSHIRE', 'PostCode': 'PO49HU', 'Town': 'SOUTHSEA', 'UPRN': Decimal('1775')}}, 'Name': 'Courtney', 'OrgId': {'@assigningAuthorityName': 'ABCDE', '@extension': 'a12cde', '@root': '2.16.840.1.1'}, 'Status': {'@value': 'Active'}, }, { 'Date': [{'L_End': {'@value': '2013-03-31'}, 'L_Start': {'@value': '2006-10-01'}, 'Type': {'@value': 'L'}}, {'O_Start': {'@value': '2006-10-01'}, 'Type': {'@value': 'O'}}], 'GeoLoc': {'Location': {'AddrLn1': 'VILLIERS ROAD', 'Country': 'ENGLAND', 'County': 'HAMPSHIRE', 'PostCode': 'PO52HG', 'Town': 'SOUTHSEA'}}, 'Name': 'MERLIN', 'OrgId': {'@assigningAuthorityName': 'ABCDE', '@extension': 'b12cde', '@root': '2.16.840.1.1'}, 'Status': {'@value': 'Active'} } ] }
需要将其转换为指定结构的DataFrame,目前的实现需要多次拆分、拼接列,步骤繁琐:
import pandas as pd df = pd.DataFrame.from_dict(data_dict) df1 = pd.DataFrame(df.Company.values.tolist()) df2 = pd.concat([df1, df1.OrgId.apply(lambda x: pd.Series(x))], axis=1) df2 = df2.drop(['OrgId', '@root', '@assigningAuthorityName'], axis=1) df2 = df2.rename(columns={"@extension": "OrgId"}) df3 = pd.concat([df2, df2.Date.apply(lambda x: pd.Series(x))], axis=1) df3 = df3.drop('Date', axis=1) df4 = pd.concat([df3, df3[0].apply(lambda x: pd.Series(x))], axis=1) df4 = df4.drop([0, 'Type'], axis=1) # ...后续重复类似操作直到提取所有所需列 df11 = pd.concat([df10, df10.Location.apply(lambda x: pd.Series(x))], axis=1) df11 = df11.drop('Location', axis=1) final_df = df11.copy() print(final_df)
高效实现方案
方法一:利用pd.json_normalize快速展开+列整理
pd.json_normalize是Pandas专门用于处理嵌套JSON/字典的工具,能直接生成带层级分隔的列,再配合简单的列处理即可得到目标结构:
import pandas as pd from decimal import Decimal # 1. 直接展开Company列表生成初始DataFrame df = pd.json_normalize(data_dict['Company']) # 2. 处理Date列的嵌套列表,提取所有日期字段 def flatten_date(date_list): date_info = {} for item in date_list: # 跳过Type字段,提取其他日期字段的@value值 for key, val in item.items(): if key != 'Type': date_info[key] = val['@value'] return pd.Series(date_info) date_df = df['Date'].apply(flatten_date) # 3. 合并所需列并整理命名 final_df = pd.concat([ # 保留基础字段 df[['Name']], # 提取OrgId的有效字段并重命名 df['OrgId.@extension'].rename('OrgId'), # 提取Status字段 df['Status.@value'].rename('Status'), # 合并处理后的日期字段 date_df, # 提取地址字段并去掉前缀 df.filter(like='GeoLoc.Location.').rename(columns=lambda x: x.replace('GeoLoc.Location.', '')) ], axis=1) print(final_df)
方法二:预处理字典扁平化后再生成DataFrame
先递归处理嵌套字典,提取所有@value并合并Date列表,再用pd.json_normalize直接生成扁平DataFrame,代码更简洁:
import pandas as pd from decimal import Decimal def preprocess_item(item): # 递归提取@value字段,简化嵌套层级 def extract_value(obj): if isinstance(obj, dict): if '@value' in obj: return obj['@value'] return {k: extract_value(v) for k, v in obj.items()} elif isinstance(obj, list): return [extract_value(i) for i in obj] return obj processed = extract_value(item) # 合并Date列表中的多个字典为单个字典 if 'Date' in processed: date_combined = {} for date_item in processed['Date']: # 移除Type字段,合并日期字段 date_item.pop('Type') date_combined.update(date_item) processed['Date'] = date_combined return processed # 预处理所有Company条目 processed_companies = [preprocess_item(comp) for comp in data_dict['Company']] # 直接生成扁平DataFrame final_df = pd.json_normalize(processed_companies) # 按需调整列顺序(可选) final_df = final_df[['Name', 'OrgId', 'Status', 'L_Start', 'L_End', 'O_Start', 'AddrLn1', 'Town', 'County', 'PostCode', 'Country', 'UPRN']] print(final_df)
两种方法都能避免多次拆分拼接的繁琐操作,方法二更适合结构复杂或后续可能变化的场景,扩展性更强。
内容的提问来源于stack exchange,提问作者emma thompson
相关产品推荐
相关产品推荐

