一、JSON 是什么?
JSON(JavaScript Object Notation,JavaScript 对象表示法),是存储和交换文本信息的语法,类似 XML。
JSON 比 XML 更小、更快,更易解析。
Pandas 提供了强大的方法来处理 JSON 格式的数据,支持从 JSON 文件或字符串中读取数据并将其转换为 DataFrame,以及将 DataFrame 转换回 JSON 格式。
| 操作 | 方法 | 说明 |
|---|---|---|
| 从 JSON 文件/字符串读取数据 | pd.read_json() | 从 JSON 数据中读取并加载为 DataFrame |
| 将 DataFrame 转换为 JSON | DataFrame.to_json() | 将 DataFrame 转换为 JSON 格式的数据 |
| 支持 JSON 结构化方式 | orient 参数 | 支持多种结构化方式,如 split、records、columns |
本文示例数据 sites.json:
json
[ { "id": "A001", "name": "菜鸟教程", "url": "www.runoob.com", "likes": 61 }, { "id": "A002", "name": "Google", "url": "www.google.com", "likes": 124 }, { "id": "A003", "name": "淘宝", "url": "www.taobao.com", "likes": 45 } ]
二、pd.read_json() —— 读取 JSON 数据
read_json() 用于从 JSON 格式的数据中读取并加载为一个 DataFrame。它支持从 JSON 文件、JSON 字符串或 JSON 网址中加载数据。
语法格式:
python
import pandas as pd df = pd.read_json( path_or_buffer, # JSON 文件路径、JSON 字符串或 URL orient=None, # JSON 数据的结构方式,默认是 'columns' dtype=None, # 强制指定列的数据类型 convert_axes=True, # 是否转换行列索引 convert_dates=True, # 是否将日期解析为日期类型 keep_default_na=True # 是否保留默认的缺失值标记 )
参数说明:
| 参数 | 说明 | 默认值 |
|---|---|---|
path_or_buffer | JSON 文件的路径、JSON 字符串或 URL | 必需参数 |
orient | 定义 JSON 数据的格式方式 | None(根据文件自动推断) |
dtype | 强制指定列的数据类型 | None |
convert_axes | 是否将轴转换为合适的数据类型 | True |
convert_dates | 是否将日期解析为日期类型 | True |
keep_default_na | 是否保留默认的缺失值标记(如 NaN) | True |
orient 参数五种结构方式
| orient 值 | JSON 格式示例 | 描述 |
|---|---|---|
split | {"index":["a","b"],"columns":["A","B"],"data":[[1,2],[3,4]]} | 使用键 index、columns 和 data 结构 |
records | [{"A":1,"B":2},{"A":3,"B":4}] | 每个记录是一个字典,表示一行数据 |
index | {"a":{"A":1,"B":2},"b":{"A":3,"B":4}} | 使用索引为键,值为字典 |
columns | {"A":{"a":1,"b":3},"B":{"a":2,"b":4}} | 使用列名为键,值为字典 |
values | [[1,2],[3,4]] | 只返回数据,不包括索引和列名 |
1. 从 JSON 文件加载
python
import pandas as pd df = pd.read_json('sites.json') print(df.to_string())
to_string()用于返回完整的 DataFrame 数据,避免中间部分被...省略。
2. 直接处理 JSON 字符串
python
import pandas as pd data =[ {"id": "A001", "name": "菜鸟教程", "url": "www.runoob.com", "likes": 61}, {"id": "A002", "name": "Google", "url": "www.google.com", "likes": 124}, {"id": "A003", "name": "淘宝", "url": "www.taobao.com", "likes": 45} ] df = pd.DataFrame(data) print(df)
输出结果:
text
id name url likes 0 A001 菜鸟教程 www.runoob.com 61 1 A002 Google www.google.com 124 2 A003 淘宝 www.taobao.com 45
3. 从字典创建
JSON 对象与 Python 字典具有相同的格式,所以我们可以直接将 Python 字典转化为 DataFrame 数据:
python
import pandas as pd # 字典格式的 JSON s = { "col1":{"row1":1,"row2":2,"row3":3}, "col2":{"row1":"x","row2":"y","row3":"z"} } # 读取 JSON 转为 DataFrame df = pd.DataFrame(s) print(df)
输出结果:
text
col1 col2 row1 1 x row2 2 y row3 3 z
4. 从 URL 读取
python
import pandas as pd URL = 'https://static.jyshare.com/download/sites.json' df = pd.read_json(URL) print(df)
输出结果:
text
id name url likes 0 A001 菜鸟教程 www.runoob.com 61 1 A002 Google www.google.com 124 2 A003 淘宝 www.taobao.com 45
5. 从 JSON 字符串读取
python
import pandas as pd # JSON 字符串 json_data = ''' [ {"Name": "Alice", "Age": 25, "City": "New York"}, {"Name": "Bob", "Age": 30, "City": "Los Angeles"}, {"Name": "Charlie", "Age": 35, "City": "Chicago"} ] ''' # 从 JSON 字符串读取数据 df = pd.read_json(json_data) print(df)
输出:
text
Name Age City 0 Alice 25 New York 1 Bob 30 Los Angeles 2 Charlie 35 Chicago
6. 指定 orient='records'
python
import pandas as pd json_data = ''' [ {"Name": "Alice", "Age": 25, "City": "New York"}, {"Name": "Bob", "Age": 30, "City": "Los Angeles"}, {"Name": "Charlie", "Age": 35, "City": "Chicago"} ] ''' # 指定 orient='records' df = pd.read_json(json_data, orient='records') print(df)
输出结果与上面一致。 orient='records' 是最常见的 JSON 数组结构。
三、内嵌 JSON 数据的展平
1. 简单嵌套:students 列表
假设有一组内嵌的 JSON 数据文件 nested_list.json:
json
{ "school_name": "ABC primary school", "class": "Year 1", "students": [ { "id": "A001", "name": "Tom", "math": 60, "physics": 66, "chemistry": 61 }, { "id": "A002", "name": "James", "math": 89, "physics": 76, "chemistry": 51 }, { "id": "A003", "name": "Jenny", "math": 79, "physics": 90, "chemistry": 78 }] }
直接读取:
python
import pandas as pd df = pd.read_json('nested_list.json') print(df)
输出结果:
text
school_name class students 0 ABC primary school Year 1 {'id': 'A001', 'name': 'Tom', 'math': 60, 'phy... 1 ABC primary school Year 1 {'id': 'A002', 'name': 'James', 'math': 89, 'p... 2 ABC primary school Year 1 {'id': 'A003', 'name': 'Jenny', 'math': 79, 'p...
问题: students 列是嵌套的字典,没有被展开。
2. 使用 json_normalize 展平
这时我们就需要使用到 json_normalize() 方法将内嵌的数据完整的解析出来:
python
import pandas as pd import json # 使用 Python JSON 模块载入数据 with open('nested_list.json', 'r') as f: data = json.loads(f.read()) # 展平数据 df_nested_list = pd.json_normalize(data, record_path=['students']) print(df_nested_list)
输出结果:
text
id name math physics chemistry 0 A001 Tom 60 66 61 1 A002 James 89 76 51 2 A003 Jenny 79 90 78
关键参数:
-
record_path=['students']:指定要展开的内嵌列表路径。
3. 使用 meta 保留外层字段
显示结果还没有包含 school_name 和 class 元素,如果需要展示出来可以使用 meta 参数来显示这些元数据:
python
import pandas as pd import json with open('nested_list.json', 'r') as f: data = json.loads(f.read()) df_nested_list = pd.json_normalize( data, record_path=['students'], meta=['school_name', 'class'] ) print(df_nested_list)
输出结果:
text
id name math physics chemistry school_name class 0 A001 Tom 60 66 61 ABC primary school Year 1 1 A002 James 89 76 51 ABC primary school Year 1 2 A003 Jenny 79 90 78 ABC primary school Year 1
4. 更复杂的嵌套:字典 + 列表
接下来,让我们尝试读取更复杂的 JSON 数据,该数据嵌套了列表和字典,数据文件 nested_mix.json 如下:
json
{ "school_name": "local primary school", "class": "Year 1", "info": { "president": "John Kasich", "address": "ABC road, London, UK", "contacts": { "email": "[email protected]", "tel": "123456789" } }, "students": [ { "id": "A001", "name": "Tom", "math": 60, "physics": 66, "chemistry": 61 }, { "id": "A002", "name": "James", "math": 89, "physics": 76, "chemistry": 51 }, { "id": "A003", "name": "Jenny", "math": 79, "physics": 90, "chemistry": 78 }] }
转换为 DataFrame:
python
import pandas as pd import json with open('nested_mix.json', 'r') as f: data = json.loads(f.read()) df = pd.json_normalize( data, record_path=['students'], meta=[ 'class', ['info', 'president'], ['info', 'contacts', 'tel'] ] ) print(df)
输出结果:
text
id name math physics chemistry class info.president info.contacts.tel 0 A001 Tom 60 66 61 Year 1 John Kasich 123456789 1 A002 James 89 76 51 Year 1 John Kasich 123456789 2 A003 Jenny 79 90 78 Year 1 John Kasich 123456789
要点: meta 中的列表形式 ['info', 'president'] 用于指定嵌套路径,展平后列名为 info.president。
5. 读取内嵌数据中的一组数据
以下是实例文件 nested_deep.json,我们只读取内嵌中的 math 字段:
json
{ "school_name": "local primary school", "class": "Year 1", "students": [ { "id": "A001", "name": "Tom", "grade": { "math": 60, "physics": 66, "chemistry": 61 } }, { "id": "A002", "name": "James", "grade": { "math": 89, "physics": 76, "chemistry": 51 } }, { "id": "A003", "name": "Jenny", "grade": { "math": 79, "physics": 90, "chemistry": 78 } }] }
这里我们需要使用到 glom 模块来处理数据嵌套,glom 模块允许我们使用 . 来访问内嵌对象的属性。
第一次使用需要安装 glom:
bash
pip3 install glom
python
import pandas as pd from glom import glom df = pd.read_json('nested_deep.json') data = df['students'].apply(lambda row: glom(row, 'grade.math')) print(data)
输出结果:
text
0 60 1 89 2 79 Name: students, dtype: int64
四、to_json() —— 将 DataFrame 转换为 JSON
to_json() 方法用于将 DataFrame 转换为 JSON 格式的数据,可以指定 JSON 的结构化方式。
语法格式:
python
df.to_json( path_or_buffer=None, # 输出的文件路径或文件对象,如果是 None 则返回 JSON 字符串 orient=None, # JSON 格式方式 date_format=None, # 日期格式,支持 'epoch', 'iso' default_handler=None, # 自定义非标准类型的处理函数 lines=False, # 是否将每行数据作为一行 encoding='utf-8' # 编码格式 )
参数说明:
| 参数 | 说明 | 默认值 |
|---|---|---|
path_or_buffer | 输出文件路径或文件对象,若为 None 则返回 JSON 字符串 | None |
orient | 指定 JSON 格式结构 | None(默认是 columns) |
date_format | 日期格式,支持 'epoch' 或 'iso' | None |
default_handler | 自定义处理非标准类型的函数 | None |
lines | 是否将每行数据作为一行输出 | False |
encoding | 输出文件的编码格式 | 'utf-8' |
1. 转换为 JSON 字符串
python
import pandas as pd df = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago'] }) json_str = df.to_json() print(json_str)
2. 转换为 JSON 文件(orient='records')
python
import pandas as pd df = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago'] }) df.to_json('data.json', orient='records', lines=True)
生成的文件内容:
json
{"Name":"Alice","Age":25,"City":"New York"} {"Name":"Bob","Age":30,"City":"Los Angeles"} {"Name":"Charlie","Age":35,"City":"Chicago"}
注意:
lines=True时输出 JSON Lines 格式(每行一个对象),而不是标准 JSON 数组。
3. 指定日期格式
python
import pandas as pd df = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'Charlie'], 'Date': pd.to_datetime(['2021-01-01', '2022-02-01', '2023-03-01']), 'Age': [25, 30, 35] }) json_str = df.to_json(date_format='iso') print(json_str)
输出:
json
{"Name":{"0":"Alice","1":"Bob","2":"Charlie"},"Date":{"0":"2021-01-01T00:00:00.000Z","1":"2022-02-01T00:00:00.000Z","2":"2023-03-01T00:00:00.000Z"},"Age":{"0":25,"1":30,"2":35}}
五、JSON 处理流程图
六、orient 参数选择建议
| 场景 | 推荐 orient |
|---|---|
| Web API 返回数组 | 'records' |
| 需要保留索引 | 'index' |
| 按列组织数据 | 'columns' |
| 紧凑传输格式 | 'split' |
| 纯数据数组 | 'values' |
| JSON Lines 日志 | 'records' + lines=True |
七、常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
ValueError: Trailing data | JSON 格式不合法 | 用 json.loads 先校验 |
| 嵌套数据未展开 | 直接读取未处理嵌套 | 用 json_normalize |
record_path 报错 | 路径不存在 | 检查 JSON 结构层级 |
中文转义为 \uXXXX | 未设置 force_ascii | to_json(..., force_ascii=False) |
| 日期变成时间戳 | 未设置 date_format | date_format='iso' |
| JSON Lines 读取失败 | 缺少 lines=True | 添加 lines=True |
| 展平后列名带点号 | meta 嵌套路径 | 列名如 info.president 属正常 |
八、小结
本篇你掌握了 Pandas 处理 JSON 数据的完整能力:
-
读取 JSON:
pd.read_json()支持文件、字符串、URL 三种来源。 -
orient 参数:
split、records、index、columns、values五种结构。 -
嵌套展平:
pd.json_normalize()配合record_path展开列表,meta保留外层字段。 -
深层字段:
meta=[['info', 'president']]指定嵌套路径,或用glom提取。 -
导出 JSON:
to_json()配合orient、date_format、lines参数。 -
常用技巧:JSON Lines 用
lines=True,中文用force_ascii=False。
JSON 是 API 数据交互的主格式,掌握嵌套展平能力,就能应对绝大多数 Web 数据场景。下一篇我们将学习 Pandas 数据清洗,掌握缺失值、重复值、异常值的系统处理方法。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Smell_of_earth/article/details/168519650




