如何编写通用函数将任意嵌套JSON转换为Pandas DataFrame?
通用深层嵌套JSON转Pandas DataFrame解决方案
我完全理解你在多数据源分析项目里的困扰——深层嵌套JSON确实是个棘手的问题,json_normalize虽然能处理特定结构,但面对任意嵌套的JSON时灵活性太差,没法提前预知结构的情况下完全没法通用。下面我给你一个经过验证的通用解决方案,能自动处理几乎所有类型的嵌套JSON,把它转成规整的DataFrame。
核心思路:递归扁平化嵌套结构
解决这个问题的关键是递归遍历JSON的每一层结构,把所有嵌套的键值对展开成扁平的字段名(用分隔符连接父键和子键),同时处理数组类型的结构:如果数组里是字典,就把每个字典拆成单独的行;如果是普通元素(字符串、数字等),就保留为列表或者转成字符串(根据需求调整)。
完整代码实现
import pandas as pd import json from typing import Dict, List, Any def flatten_json(json_obj: Any, parent_key: str = '', sep: str = '_') -> Dict[str, Any]: """递归扁平化嵌套JSON结构""" items = {} # 处理字典类型 if isinstance(json_obj, dict): for k, v in json_obj.items(): new_key = f"{parent_key}{sep}{k}" if parent_key else k items.update(flatten_json(v, new_key, sep=sep)) # 处理列表类型 elif isinstance(json_obj, list): for i, elem in enumerate(json_obj): new_key = f"{parent_key}{sep}{i}" if parent_key else str(i) items.update(flatten_json(elem, new_key, sep=sep)) # 基础类型(字符串、数字、布尔等) else: items[parent_key] = json_obj return items def json_to_dataframe(json_input: str | Dict | List) -> pd.DataFrame: """将任意JSON(字符串/字典/列表)转换为规整的Pandas DataFrame""" # 处理JSON字符串输入 if isinstance(json_input, str): json_data = json.loads(json_input) else: json_data = json_input # 处理顶层是列表的情况 if isinstance(json_data, list): flattened_data = [flatten_json(item) for item in json_data] # 处理顶层是字典的情况 elif isinstance(json_data, dict): flattened_data = [flatten_json(json_data)] else: raise ValueError("输入必须是JSON字符串、字典或列表") return pd.DataFrame(flattened_data)
代码说明
flatten_json函数:- 递归遍历JSON的每个节点,遇到字典就继续深入,遇到列表就给每个元素加上索引后缀(比如
Employees_0、Employees_1),遇到基础类型就直接存储键值对。 - 用
sep参数控制嵌套字段的分隔符,默认是下划线_,你可以根据需求改成.或者其他符号。
- 递归遍历JSON的每个节点,遇到字典就继续深入,遇到列表就给每个元素加上索引后缀(比如
json_to_dataframe函数:- 自动识别输入类型:支持JSON字符串、Python字典、列表三种输入形式。
- 如果顶层是列表(比如你的
Employees示例,里面是员工字典的列表),会把每个列表元素单独扁平化后转成一行;如果顶层是字典,就把整个字典扁平化后转成一行。
测试示例
假设你的示例JSON是这样的:
{ "Employees": [ { "id": 1, "name": "John Doe", "details": { "department": "Engineering", "salary": 80000, "skills": ["Python", "SQL"] } }, { "id": 2, "name": "Jane Smith", "details": { "department": "Marketing", "salary": 75000, "skills": ["SEO", "Content Writing"] } } ] }
用这个函数处理:
# 加载JSON数据(这里用字典模拟) sample_json = { "Employees": [ {"id": 1, "name": "John Doe", "details": {"department": "Engineering", "salary": 80000, "skills": ["Python", "SQL"]}}, {"id": 2, "name": "Jane Smith", "details": {"department": "Marketing", "salary": 75000, "skills": ["SEO", "Content Writing"]}} ] } df = json_to_dataframe(sample_json) print(df.columns) # 输出:Index(['Employees_0_id', 'Employees_0_name', 'Employees_0_details_department', # 'Employees_0_details_salary', 'Employees_0_details_skills_0', # 'Employees_0_details_skills_1', 'Employees_1_id', 'Employees_1_name', # 'Employees_1_details_department', 'Employees_1_details_salary', # 'Employees_1_details_skills_0', 'Employees_1_details_skills_1'], # dtype='object')
如果你的JSON顶层直接是员工列表(比如去掉外层的Employees键),函数也能自动处理,每个员工会变成DataFrame的一行,字段名是id、name、details_department等。
自定义调整建议
- 如果希望把列表类型的字段保留为列表而不是拆成单独的列,可以修改
flatten_json函数中处理列表的逻辑,直接把整个列表作为值存储,而不是遍历元素。 - 如果需要处理非常大的JSON文件,可以考虑分块处理,避免内存溢出。
内容的提问来源于stack exchange,提问作者user11125533
相关产品推荐
相关产品推荐

