Pandas JSON(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言

在数据分析与编程领域,Pandas JSON 是一个高频出现的关键词。Pandas 作为 Python 生态中处理结构化数据的核心工具,而 JSON(JavaScript Object Notation)因其轻量级、易读性及跨平台兼容性,成为数据交换的首选格式。两者的结合,为开发者提供了高效解析、转换和操作 JSON 数据的能力。无论是从 API 获取实时数据、处理嵌套结构复杂的配置文件,还是将分析结果导出为可共享的 JSON 格式,掌握这一技能链路都能显著提升工作效率。

本文将从基础概念讲起,逐步深入到实际案例与高级技巧,帮助读者系统性掌握 Pandas 处理 JSON 的方法。通过形象化的比喻和可复现的代码示例,即使是编程新手也能快速上手。


一、Pandas 与 JSON 的基础概念

1.1 Pandas 是什么?

Pandas 是 Python 中用于数据操作和分析的库,其核心数据结构是 DataFrame(二维表格)和 Series(一维数组)。它提供了一套高效且灵活的接口,支持数据清洗、聚合、合并等操作,是数据科学家和工程师的必备工具。

1.2 JSON 的结构与特点

JSON 是一种以键值对(Key-Value)存储数据的格式,其结构分为以下层级:

  • 标量类型:字符串、数字、布尔值等简单数据。
  • 对象(Object):用大括号 {} 包裹的键值对集合,例如:
    {  
      "name": "Alice",  
      "age": 30,  
      "is_student": false  
    }  
    
  • 数组(Array):用方括号 [] 包裹的多个元素,例如:
    [10, 20, 30]  
    
  • 嵌套结构:对象或数组可以包含其他对象或数组,形成多层结构。

JSON 的优势在于:

  • 人类可读性:格式简洁,易于编写和调试。
  • 跨语言兼容性:几乎所有编程语言都支持 JSON 解析。
  • 轻量级:相比 XML 等格式,JSON 的体积更小。

1.3 Pandas JSON 的核心作用

Pandas 的 json 模块提供了将 JSON 数据转化为 DataFrame 的功能,解决了以下痛点:

  1. 自动类型推断:将 JSON 的键值对映射为 DataFrame 的列与行。
  2. 处理嵌套结构:通过参数配置,可展开多层嵌套的 JSON 数据。
  3. 批量操作能力:利用 Pandas 的向量化操作,快速清洗或转换 JSON 数据。

二、从 JSON 到 DataFrame:基础读取与转换

2.1 直接读取简单 JSON 文件

假设有一个简单的 JSON 文件 data.json,内容如下:

[  
  {"id": 1, "name": "Apple", "price": 1.99},  
  {"id": 2, "name": "Banana", "price": 0.99}  
]  

使用 pd.read_json() 可直接加载:

import pandas as pd  

df = pd.read_json("data.json")  
print(df)  

   id    name  price  
0   1   Apple   1.99  
1   2  Banana   0.99  

注意:默认读取模式为 orient='columns',适用于一维或二维数据。


2.2 处理嵌套 JSON:展开多层结构

当 JSON 数据包含嵌套对象时(例如:每个元素是一个对象,内部有子对象),直接读取会得到 DataFrame 的列类型为 dict。此时需借助 json_normalize

案例:解析用户信息的嵌套 JSON

[  
  {  
    "user_id": 101,  
    "name": "Bob",  
    "address": {  
      "city": "New York",  
      "zip": "10001"  
    },  
    "orders": [  
      {"product": "Laptop", "price": 1000},  
      {"product": "Mouse", "price": 20}  
    ]  
  },  
  {  
    "user_id": 102,  
    "name": "Alice",  
    "address": {  
      "city": "London",  
      "zip": "SW1A 1AA"  
    },  
    "orders": [  
      {"product": "Book", "price": 15}  
    ]  
  }  
]  

解决方案:使用 pd.json_normalize()

from pandas import json_normalize  
import json  

json_str = """[...]"""  # 省略原始 JSON 内容  
data = json.loads(json_str)  

df = json_normalize(  
    data,  
    record_path=['orders'],  # 需要展开的数组字段  
    meta=[  
        'user_id',  
        'name',  
        ['address', 'city'],  # 嵌套字段的路径  
        ['address', 'zip']  
    ]  
)  

print(df)  

   product  price  user_id   name    address.city address.zip  
0   Laptop   1000      101    Bob     New York    10001  
1    Mouse     20      101    Bob     New York    10001  
2     Book     15      102  Alice      London    SW1A 1AA  

关键参数说明

  • record_path: 指定要展开的数组字段(如 orders)。
  • meta: 需要保留的顶层字段(如 user_id)或嵌套字段(如 address.city)。
  • 比喻:将嵌套的 JSON 比作俄罗斯套娃,json_normalize 就像一把“拆解工具”,一层层展开并平铺到表格中。

2.3 从 API 获取 JSON 数据并解析

实际开发中,常需要从 API 请求 JSON 数据。以下是一个完整流程示例:

案例:调用天气 API 获取数据

import requests  
import pandas as pd  

response = requests.get("https://api.weatherapi.com/v1/current.json", params={  
    "key": "YOUR_API_KEY",  
    "q": "London"  
})  

data = response.json()  
df = pd.json_normalize(data)  

print(df)  

       location.name  current.temp_c  ...  
0         London             15.6  ...  

关键步骤

  1. 使用 requests 发送请求并获取响应。
  2. 通过 .json() 方法将响应内容转换为 Python 字典。
  3. 使用 pd.json_normalize() 将字典结构化为 DataFrame。

三、从 DataFrame 到 JSON:导出与格式控制

3.1 基础导出:to_json() 方法

将 DataFrame 转换为 JSON 格式时,可通过 orient 参数控制输出格式:

示例:导出不同格式的 JSON

df = pd.DataFrame({  
    "id": [1, 2],  
    "name": ["Apple", "Banana"],  
    "price": [1.99, 0.99]  
})  

print(df.to_json(orient="records", force_ascii=False))  

[  
  {"id":1,"name":"Apple","price":1.99},  
  {"id":2,"name":"Banana","price":0.99}  
]  

print(df.to_json(orient="table", force_ascii=False))  

{  
  "schema": {...},  
  "data": [...]  
}  

常用 orient 参数
| 参数值 | 描述 |
|--------------|----------------------------------------|
| records | 将每一行转换为独立的 JSON 对象(数组形式)。 |
| index | 以索引为键,列值为值(对象形式)。 |
| columns | 列名作为键,列数据为值(对象形式)。 |
| split | 分割为 "index", "columns", "data" 三个部分。 |


3.2 高级导出:自定义嵌套结构

有时需要将 DataFrame 转换为特定嵌套格式,例如:

{  
  "users": [  
    {  
      "id": 101,  
      "orders": [  
        {"product": "Laptop", "price": 1000},  
        {"product": "Mouse", "price": 20}  
      ]  
    },  
    ...  
  ]  
}  

实现步骤:

  1. 分组聚合:按用户 ID 分组,将订单数据转化为列表。
  2. 自定义转换:通过 applyjson.dumps 构造嵌套结构。
df = pd.DataFrame({  
    "user_id": [101, 101, 102],  
    "product": ["Laptop", "Mouse", "Book"],  
    "price": [1000, 20, 15]  
})  

result = df.groupby("user_id").apply(lambda x: x[["product", "price"]].to_dict("records")).reset_index()  
result.columns = ["user_id", "orders"]  

output = {  
    "users": result.to_dict("records")  
}  

print(json.dumps(output, indent=2))  

{  
  "users": [  
    {  
      "user_id": 101,  
      "orders": [  
        {"product": "Laptop", "price": 1000},  
        {"product": "Mouse", "price": 20}  
      ]  
    },  
    ...  
  ]  
}  

四、进阶技巧与常见场景

4.1 处理动态键:未知或变化的 JSON 字段

当 JSON 数据的键不固定时(例如 API 返回的字段可能随版本变化),可以通过遍历或正则表达式提取关键信息。

案例:提取所有以 "price" 开头的列

df = pd.DataFrame({  
    "price_1": [10, 20],  
    "price_2": [5, 8],  
    "other": ["A", "B"]  
})  

price_cols = [col for col in df.columns if col.startswith("price")]  
price_data = df[price_cols]  

print(price_data)  

   price_1  price_2  
0       10        5  
1       20        8  

4.2 处理缺失值与类型转换

JSON 数据中常存在 null 或类型不一致的情况,需通过 Pandas 的方法进行清洗:

示例:填充缺失值并转换为数值类型

df = pd.DataFrame({  
    "id": [1, 2, 3],  
    "value": ["100", "200", None]  
})  

df["value"] = pd.to_numeric(df["value"], errors="coerce").fillna(0)  

print(df)  

   id   value  
0   1  100.0  
1   2  200.0  
2   3    0.0  

4.3 性能优化:处理大型 JSON 文件

对于超大规模的 JSON 文件(如 GB 级),直接读取可能因内存不足而崩溃。此时可采用以下策略:

方法 1:分块读取(Chunk Processing)

chunk_size = 1000  
for chunk in pd.read_json("large_data.json", lines=True, chunksize=chunk_size):  
    # 处理每个小块数据  
    process(chunk)  

方法 2:使用第三方库(如 ijson

ijson 库支持流式解析,避免一次性加载全部数据:

import ijson  

with open("large_data.json", "r") as f:  
    parser = ijson.parse(f)  
    for prefix, event, value in parser:  
        if (prefix, event) == ("item", "start_map"):  
            # 处理每个 JSON 对象  
            process_item(value)  

五、常见问题与解决方案

5.1 问题:JSON 数据读取后出现 Mixed Types 警告

现象:Pandas 提示列内数据类型不一致,例如字符串与数字混合。

原因:JSON 中某些字段可能包含 null 或非预期类型。

解决方案

df = pd.read_json("data.json", dtype={"price": float})  
df["price"].fillna(0, inplace=True)  

5.2 问题:嵌套层级过深导致 json_normalize 失败

现象:多层嵌套的 JSON 无法通过 json_normalize 完全展开。

解决方案

  1. 分步展开:先展开部分层级,再对子结构递归处理。
  2. 自定义函数:编写辅助函数逐层解析复杂结构。
def recursive_flatten(d, parent_key="", sep="_"):  
    items = []  
    for k, v in d.items():  
        new_key = f"{parent_key}{sep}{k}" if parent_key else k  
        if isinstance(v, dict):  
            items.extend(recursive_flatten(v, new_key, sep).items())  
        else:  
            items.append((new_key, v))  
    return dict(items)  

df = df.applymap(lambda x: recursive_flatten(x) if isinstance(x, dict) else x)  

六、结论与展望

通过本文的讲解,读者应能掌握 Pandas JSON 的核心操作:从读取简单数据到处理复杂嵌套结构,从数据清洗到导出定制化格式。关键要点总结如下:

  1. 基础工具链pd.read_jsonpd.json_normalize 是处理 JSON 的核心函数。
  2. 嵌套处理:通过 record_pathmeta 参数实现多层展开。
  3. 性能优化:分块读取或流式解析可应对大规模数据。

未来,随着数据工程的复杂化,熟练使用 Pandas 处理 JSON 将成为开发者必备技能。建议读者结合实际项目继续探索,例如:

  • 将 JSON 数据与数据库操作结合(如导出到 SQL)。
  • 结合可视化库(如 Plotly)直接从 JSON 数据生成图表。
  • 学习更复杂的 JSON Schema 验证与数据转换逻辑。

掌握 Pandas JSON,不仅能提升个人技术竞争力,更能为构建高效的数据处理流程打下坚实基础。

最新发布