model训练中python基本数据类型的保存输出

发布于:2025-06-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

在Python中,如果希望透明地存储对象,而不丢失其身份和类型等信息,则需要某种形式的对象序列化,这是一个将任意复杂的对象转成对象的文本和二进制表示的过程。同样,必须能够将对象经过序列化后的形式恢复到原来的对象。这种序列化的过程称为pickle,可以将对象pickle成字符串、磁盘上的文件或者任何类似于文件的对象;反序列化的过程就是将这些字符串、文件或任何类似于文件的对象unpickle成原来的对象。

主要是字符串、列表、元组与集合等,这一部分数据相比字典格式的数据比较简单(非复合数据,字典一般都是复合型数据,里面可以再嵌套前面所提到的这些数据格式)。

下面以保存字典数据类型数据为例进行解释,

一,保存为json

在 Python 中,json 模块提供了 dumpdumpsloadloads 四个函数,它们用于处理 JSON 数据的序列化和反序列化。

一、dumpdumps

1. dump
  • 用途:将 Python 对象序列化为 JSON 格式的字节流,并将其写入文件或类文件对象。
  • 参数
    • 第一个参数是要序列化的 Python 对象。
    • 第二个参数是文件或类文件对象。
  • 特点:直接将序列化后的数据写入文件,适合将数据持久化到文件系统中。
示例
import json

# 创建一个 Python 字典
data = {"name": "Alice", "age": 25, "city": "New York"}

# 将数据序列化并写入文件
with open("data.json", "w") as file:
    json.dump(data, file)

# 文件 data.json 中的内容将是:
# {
#     "name": "Alice",
#     "age": 25,
#     "city": "New York"
# }

2. dumps
  • 用途:将 Python 对象序列化为 JSON 格式的字符串。
  • 参数:只接受一个参数,即要序列化的 Python 对象。
  • 特点:返回一个字符串,适合在程序中进行传递、存储或其他处理。
示例
import json

# 创建一个 Python 字典
data = {"name": "Bob", "age": 30, "city": "Los Angeles"}

# 将数据序列化为字符串
json_str = json.dumps(data)

# 打印字符串
print(json_str)
# 输出:
# {"name": "Bob", "age": 30, "city": "Los Angeles"}

# 可以将这个字符串用于其他操作,例如发送到网络、存储到内存等

详细比较,我们可以发现:

dumps是将python对象(比如说此处的dict)转换为json格式的str

而dump是将该对象转换为了json格式的字节流,并将其写入类文件对象

也就是说dump比dumps多了和文件操作结合起来的步骤

二、loadloads

1. load
  • 用途:从文件中读取 JSON 数据并将其解析为 Python 对象。
  • 参数:接受一个文件对象作为参数。
  • 特点:直接从文件中读取数据并解析,适合处理存储在文件中的 JSON 数据。
示例

此处我的示例数据如下:

import json

# 假设有一个文件 data.json,内容如下:
# {
#     "name": "Charlie",
#     "age": 35,
#     "city": "Chicago"
# }


# 从文件中读取 JSON 数据
with open("data.json", "r") as file:
    data = json.load(file)

# 打印解析后的 Python 对象
print(data)
# 输出:
# {'name': 'Charlie', 'age': 35, 'city': 'Chicago'}

2. loads
  • 用途:将 JSON 格式的字符串解析为 Python 对象。
  • 参数:接受一个包含 JSON 数据的字符串作为参数。
  • 特点:从字符串中解析数据,适合处理从网络、内存等地方获取的 JSON 字符串。
示例
import json

# JSON 字符串
json_str = '{"name": "David", "age": 40, "city": "Houston"}'

# 将 JSON 字符串解析为 Python 对象
data = json.loads(json_str)

# 打印解析后的 Python 对象
print(data)
# 输出:
# {'name': 'David', 'age': 40, 'city': 'Houston'}

三、总结

  • dump** 和 **dumps
    • dump 是将数据序列化后直接写入文件。
    • dumps 是将数据序列化为字符串,返回字符串。
  • load** 和 **loads
    • load 是从文件中读取 JSON 数据并解析为 Python 对象。
    • loads 是从字符串中解析 JSON 数据为 Python 对象。

简单来说:

  • 如果你需要将数据写入文件,就用 dump
  • 如果你需要将数据转换为字符串,就用 dumps
  • 如果你需要从文件中读取 JSON 数据,就用 load
  • 如果你需要从字符串中解析 JSON 数据,就用 loads
json的dump和dumps的区别
dumps是将dict转化成str格式,loads是将str转化成dict格式。
dump和load也是类似的功能,只是与文件操作结合起来了。

简单理解就是dump和load需要一个类似于文件指针的参数(并不是真的指针,可称之为类文件对象),可以与文件操作结合

总之,带s的dumps和loads都是涉及到str字符串,

不带s的dump和load都是直接字节流的文件操作

二,保存为pkl文件

一般使用joblib模块或者是pickle模块,也就是我们在机器学习保存最优model结果的同样操作。

python中的json模块(前面一种方法)和pickle、joblib模块,实际上都是用于数据的序列化和反序列化,所提供的方法也无非是一致的:dumps、dump以及loads、load。

总得来说:

  • dumps(obs):将对象序列化为str
  • dump(obj,fp):将对象序列化为str,并存入文件中
  • loads(s):将(序列化之后的)字符串反序列化为Python对象
  • load(fp):将文件中的(序列化后的)字符串反序列化为Python对象

所以操作逻辑上其实json和pkl是一样的,细节上有点差异:

  • 通用性:

json序列化后的字符串是通用的格式(普通的字符串)在不同的平台和语言都可以识别,而pickle序列化后的字符串只有Python可以识别(Python专用序列化模块)

  • 处理的数据类型:

json能序列化的对象只是Python中基础数据类型,而pickle能序列化Python中所有的数据类型(划重点,是所有数据类型,所以实际上所有中间变量或者是函数返回结果,都可以直接用pkl格式文件接住并复原)

  • 处理后的数据类型:

json序列化后的字符串是文本类型(记事本打开文件后或者print打印后,你也能看懂其中的内容),而pickle序列化后的字符串是二进制流数据(记事本打开后或者print打印后就完全看不懂里面的内容了)。所以在进行文件操作时注意使用的是哪个模块,是否需要以b的格式打开。

总之,如果是保存为pkl文件的话,一般而言要么使用joblib,或者是pickle模块。

实际使用的时候,个人推荐joblib(至少我一般内存缓存,或存储model结果的大型数组的时候,还是joblib使用的多),

相比pickle,joblib会

  • 内存缓存:自动缓存函数的输出结果,避免重复计算。
  • 高效存储:特别优化用于存储大型数组,使用joblib进行数据序列化和反序列化比Python标准的pickle更快。
  • 并行计算支持:简化了并行计算的实现,能够轻松地在Python代码中实现多核处理。
特性 Pickle Joblib
序列化算法 Python内置序列化 基于pickle,针对科学计算优化
numpy数组处理 标准序列化 高效处理,使用内存映射
压缩支持 需要额外模块(gzip等) 内置压缩支持
大文件处理 内存占用较高 内存友好,支持lazy loading
并行安全 不支持 支持并行读写
兼容性 标准Python 需要安装scikit-learn

比如说我手头上有这么一个字典数据:

如果我想要保存,使用pickle的话:

import pickle
# 保存为pickle文件
with open("dict1.pkl","wb") as f:
    pickle.dump(dict1,f)

# 读取pkl文件
with open("dict1.pkl","rb") as f:
    dict1_new = pickle.load(f)
dict1_new

同理使用joblib也是一样的:

import joblib
# 保存为pkl文件

with open("dict1_new.pkl","wb") as f:
    joblib.dump(dict1_new,f)

# 读取pkl文件
with open("dict1_new.pkl","rb") as f:
    dict1_new = joblib.load(f)

dict1_new

joblib还可以使用压缩参数,常用的压缩格式就是:level 3

另外在实际使用时joblib和pickle还是有点区别的:

import joblib
# 直接保存为pkl文件
joblib.dump(dict1,"dict1_new2.pkl")

dict2_new = joblib.load("dict1_new2.pkl")

dict2_new

这里应该就很明显了,pickle在dump还是load,都需要句柄,但是joblib可以直接处理。

如何理解句柄上的差异,在下面的小结中展示

三,小结

1,json和joblib/pickle存储格式的差异

为什么在json保存中使用dump或load,open中只要使用w或r模式就可以了,但是在joblib或者pickle中得使用wb或rb?

JSON存储格式:

  • 文本格式:JSON以纯文本形式存储数据
  • 人类可读:可以用任何文本编辑器打开查看
  • 编码方式:使用字符编码(如UTF-8)

Pickle/Joblib存储格式:

  • 二进制格式:以字节流形式存储数据
  • 机器可读:包含Python对象的完整序列化信息
  • 编码方式:直接的字节表示
# 演示不同文件模式的区别
import json
import pickle
import joblib

# 测试数据
test_data = {"name": "test", "values": [1, 2, 3]}

# 1. JSON - 文本模式
print("=== JSON文本模式 ===")
# 保存 - 使用文本模式 'w'
with open('test_json.json', 'w') as f:
    json.dump(test_data, f)

# 读取 - 使用文本模式 'r'  
with open('test_json.json', 'r') as f:
    data = json.load(f)
print(f"JSON读取结果: {data}")

# 查看JSON文件内容(文本格式)
with open('test_json.json', 'r') as f:
    content = f.read()
print(f"JSON文件内容: {content}")

# 2. Pickle - 二进制模式
print("\n=== Pickle二进制模式 ===")
# 保存 - 必须使用二进制模式 'wb'
with open('test_pickle.pkl', 'wb') as f:
    pickle.dump(test_data, f)

# 读取 - 必须使用二进制模式 'rb'
with open('test_pickle.pkl', 'rb') as f:
    data = pickle.load(f)
print(f"Pickle读取结果: {data}")

# 查看Pickle文件内容(二进制格式,不可读)
with open('test_pickle.pkl', 'rb') as f:
    content = f.read()
print(f"Pickle文件内容(前50字节): {content[:50]}")

JSON必须使用文本模式的原因:

import json

data = {"test": "value"}

# 正确方式 - 文本模式
with open('correct.json', 'w') as f:
    json.dump(data, f)

# 错误方式 - 二进制模式会报错
try:
    with open('wrong.json', 'wb') as f:
        json.dump(data, f)  # 这会报错
except TypeError as e:
    print(f"JSON使用二进制模式的错误: {e}")
    # 错误信息: a bytes-like object is required, not 'str'

Pickle/Joblib必须使用二进制模式的原因:

import pickle

data = {"test": "value"}

# 正确方式 - 二进制模式
with open('correct.pkl', 'wb') as f:
    pickle.dump(data, f)

# 错误方式 - 文本模式会报错
try:
    with open('wrong.pkl', 'w') as f:
        pickle.dump(data, f)  # 这会报错
except TypeError as e:
    print(f"Pickle使用文本模式的错误: {e}")
    # 错误信息: write() argument must be str, not bytes

2,关于文件句柄的使用

JSON - 必须使用文件句柄

import json

data = {"test": "data"}

# JSON必须通过文件句柄操作
# 这是因为json.dump/load设计为接受文件对象参数

# 保存方式1:使用文件句柄
with open('data.json', 'w') as f:
    json.dump(data, f)

# 保存方式2:直接转换为字符串再写入
json_string = json.dumps(data)  # 转换为JSON字符串
with open('data2.json', 'w') as f:
    f.write(json_string)

# 读取方式1:使用文件句柄
with open('data.json', 'r') as f:
    loaded_data = json.load(f)

# 读取方式2:先读取字符串再解析
with open('data.json', 'r') as f:
    json_string = f.read()
loaded_data = json.loads(json_string)  # 从字符串解析

print(f"JSON加载的数据: {loaded_data}")

Pickle/Joblib - 支持直接文件路径否?

import pickle
import joblib

data = {"test": "data"}

# Pickle的两种使用方式
print("=== Pickle使用方式 ===")

# 方式1:使用文件句柄(传统方式)
with open('data_pickle_handle.pkl', 'wb') as f:
    pickle.dump(data, f)

with open('data_pickle_handle.pkl', 'rb') as f:
    loaded_data = pickle.load(f)
print(f"Pickle句柄方式: {loaded_data}")

# 方式2:pickle不支持直接文件路径
pickle.dump(data, 'file.pkl')  # 这样是错误的

# Joblib的两种使用方式
print("\n=== Joblib使用方式 ===")

# 方式1:直接使用文件路径(推荐)
joblib.dump(data, 'data_joblib_direct.pkl')
loaded_data = joblib.load('data_joblib_direct.pkl')
print(f"Joblib直接路径方式: {loaded_data}")

# 方式2:使用文件句柄
with open('data_joblib_handle.pkl', 'wb') as f:
    joblib.dump(data, f)

with open('data_joblib_handle.pkl', 'rb') as f:
    loaded_data = joblib.load(f)
print(f"Joblib句柄方式: {loaded_data}")

所以在实际使用的时候,比如说model训练的时候,对于要保存的model,以及要保存的重要数据变量(比如某个dict),

我最常用的其实就是joblib,而且不使用文件句柄,直接dump、直接load


网站公告

今日签到

点亮在社区的每一天
去签到