烂蜻蜓头像
Pandas入门教程(九):JSON 数据处理——read_json、orient 参数与 json_normalize 嵌套展开封面图

Pandas入门教程(九):JSON 数据处理——read_json、orient 参数与 json_normalize 嵌套展开

一、JSON 是什么?

JSON(JavaScript Object Notation,JavaScript 对象表示法),是存储和交换文本信息的语法,类似 XML。

JSON 比 XML 更小、更快,更易解析。

Pandas 提供了强大的方法来处理 JSON 格式的数据,支持从 JSON 文件或字符串中读取数据并将其转换为 DataFrame,以及将 DataFrame 转换回 JSON 格式。

操作方法说明
从 JSON 文件/字符串读取数据pd.read_json()从 JSON 数据中读取并加载为 DataFrame
将 DataFrame 转换为 JSONDataFrame.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_bufferJSON 文件的路径、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 dataJSON 格式不合法用 json.loads 先校验
嵌套数据未展开直接读取未处理嵌套用 json_normalize
record_path 报错路径不存在检查 JSON 结构层级
中文转义为 \uXXXX未设置 force_asciito_json(..., force_ascii=False)
日期变成时间戳未设置 date_formatdate_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

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--