Python序列化操作

一. 前言

在使用sklearnCalifornia_housing数据集进行测试时发现数据无法下载.

from sklearn.datasets import fetch_california_housing

housing = fetch_california_housing(download_if_missing=True)
urllib.error.URLError: <urlopen error [Errno 11001] getaddrinfo failed>

二. 问题

使用vscode跳转源码查看实现细节, 习惯性使用菜单这个declaration, 跳转的是pyi

关于pyi

在 Python 中, .pyi 文件是类型存根文件( Type Stub Files)

img

img

正确的跳转应该是ctrl + click即可

看到文件头上的文件地址:

https://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz

发现可以下载, 并不在意, 将文件放到目录之下

C:\Users\user_name\scikit_learn_data

结果运行还是报错, 重新调试, 源码调用这个文件时, 并不是直接使用tgz这个压缩包格式

filepath = _pkl_filepath(data_home, "cal_housing.pkz")

关于pkz

在 Python 里, 并没有特定内建支持的 " pkz" 标准文件格式. 不过, " pkz" 可能是经过压缩处理后存储数据的文件, 其本质或许是 ZIP 格式文件, 这种文件往往会使用 " .pkz" 作为扩展名

继续看源码

archive_path = _fetch_remote(ARCHIVE, dirname=data_home)

with tarfile.open(mode="r:gz", name=archive_path) as f:
    cal_housing = np.loadtxt(
        f.extractfile("CaliforniaHousing/cal_housing.data"), delimiter=","
    )
    # Columns are not in the same order compared to the previous
    # URL resource on lib.stat.cmu.edu
    columns_index = [8, 7, 2, 3, 4, 5, 6, 1, 0]
    cal_housing = cal_housing[:, columns_index]

    joblib.dump(cal_housing, filepath, compress=6)
remove(archive_path)

可以看到返回的数据经过二次处理, 对数据文件进行了序列化操作.

import tarfile
import joblib
import numpy as np

def tgz_to_pkz(tgz_file_path, pkz_file_path):
    # 打开tgz文件
    with tarfile.open(tgz_file_path, 'r:gz') as tar:
        cal_housing = np.loadtxt(
            tar.extractfile("CaliforniaHousing/cal_housing.data"), delimiter=","
        )
        # Columns are not in the same order compared to the previous
        # URL resource on lib.stat.cmu.edu
        columns_index = [8, 7, 2, 3, 4, 5, 6, 1, 0]
        cal_housing = cal_housing[:, columns_index]

        joblib.dump(cal_housing, pkz_file_path, compress=6)

tgz_file = r"C:\Users\Lian\scikit_learn_data\cal_housing.tgz"
pkz_file = r"C:\Users\Lian\scikit_learn_data\cal_housing_py3.pkz"
tgz_to_pkz(tgz_file, pkz_file)

按照上面的源码, 稍微改动一下, 生成需要的文件即可.

经过处理后的文件从432k压缩为359k.

三. 序列化操作

在机器学习中, 训练好的模型一般进行序列化操作, 使用的时候就不需要重复训练这个步骤.

这段内容豆包直接生成:

序列化操作是将对象转换为一种可以存储或传输的格式( 如字节流) 的过程, 反序列化则是将序列化后的格式恢复为原始对象. 以下为你详细介绍序列化操作的目的, 优点和缺点.

3.1 目的

  • 数据持久化: 在很多应用场景中, 需要将程序运行过程中的对象保存到磁盘上, 以便在程序下次启动时能够恢复这些对象的状态. 例如, 一个游戏在玩家退出时, 需要将玩家的角色信息, 游戏进度等对象序列化保存到文件中, 下次玩家进入游戏时, 再通过反序列化将这些信息恢复, 使游戏能够继续进行.
  • 数据传输: 在网络通信中, 不同的计算机之间需要交换数据. 由于网络传输的数据格式通常是字节流, 因此需要将对象序列化为字节流后才能在网络上传输. 例如, 在分布式系统中, 各个节点之间需要相互通信, 传递对象信息, 这时就需要对对象进行序列化. 常见的 Web 服务中, 客户端和服务器之间传递的数据( 如 JSON 格式, 本质上也是一种序列化形式) , 也是序列化操作的应用.
  • 对象复制: 通过序列化和反序列化可以实现对象的深度复制. 深度复制会创建一个新的对象, 并且递归地复制对象的所有属性, 新对象和原对象在内存中是完全独立的. 这在需要创建对象副本而又不影响原对象的情况下非常有用, 比如在多线程编程中, 为了避免多个线程对同一个对象进行修改而产生冲突, 可以使用序列化和反序列化来创建对象的副本供不同线程使用.

3.2 优点

  • 通用性: 序列化提供了一种通用的方式来处理对象的存储和传输, 无论对象的类型多么复杂, 都可以将其转换为统一的序列化格式. 例如, 无论是简单的整数, 字符串, 还是复杂的自定义类对象, 嵌套的数据结构( 如包含列表, 字典的对象) , 都可以进行序列化. 这种通用性使得不同的系统和组件之间可以方便地交换和共享数据.
  • 方便性: 序列化操作通常由编程语言提供的库或框架来实现, 使用起来非常方便. 开发者只需要调用相应的序列化和反序列化函数, 就可以完成对象的转换, 无需手动处理对象的存储和传输细节. 例如, 在 Python 中, 使用 picklejson 库可以轻松地对对象进行序列化和反序列化操作.
  • 数据一致性: 序列化后的对象在存储或传输过程中能够保持数据的一致性. 反序列化后得到的对象与原对象在内容上是相同的, 保证了数据的准确性. 这对于需要精确恢复对象状态的应用场景( 如数据库备份和恢复, 分布式系统中的数据同步) 非常重要.

3.3 缺点

  • 性能开销: 序列化和反序列化操作通常需要一定的计算资源和时间, 尤其是对于复杂的对象或大规模的数据. 在序列化过程中, 需要遍历对象的所有属性, 并将其转换为序列化格式; 反序列化时则需要将序列化数据解析并恢复为对象. 这些操作会增加程序的运行时间和 CPU 负载. 例如, 在处理大量数据的实时系统中, 频繁的序列化和反序列化操作可能会成为性能瓶颈.
  • 兼容性问题: 不同的序列化格式和版本之间可能存在兼容性问题. 如果在序列化和反序列化过程中使用的格式或版本不一致, 可能会导致反序列化失败或数据丢失. 例如, 当程序升级后, 使用了新的序列化格式, 但旧版本的程序无法识别该格式, 就会出现兼容性问题. 另外, 不同编程语言实现的序列化机制也可能存在差异, 这会给跨语言的数据交换带来困难.
  • 安全风险: 某些序列化机制存在安全风险, 特别是在反序列化过程中. 如果反序列化的数据来自不可信的源, 可能会执行恶意代码, 导致系统受到攻击. 例如, Python 的 pickle 模块在反序列化时会执行对象的构造函数和其他方法, 如果加载的 pickle 文件包含恶意代码, 就可能会对系统造成损害.

四. 常用相关包

机器学习模型保存pickle, joblib, pmml等三种方式的优缺点_pmml 与 pickle-CSDN博客

Comparing Use Cases: joblib vs pickle in Python 3 - DNMTechs - Sharing and Storing Technology Knowledge

4.1 Joblib

Joblib: running Python functions as pipeline jobs - joblib 1.4.2 documentation

Joblib is a set of tools to provide lightweight pipelining in Python. In particular:

  1. transparent disk-caching of functions and lazy re-evaluation (memoize pattern)
  2. easy simple parallel computing

Joblib is optimized to be fast and robust on large data in particular and has specific optimizations for numpy arrays. It is BSD-licensed.

需要注意的是, joblib声称的专门针对np数组做了专门的优化, 这是非常实用的, 同时其bsd开源协议, 也是相对宽松的协议, 对于商业应用也是非常自由的.

bsd协议

4.2 Pickle

pickle - Python object serialization - Python 3.13.2 documentation

The pickle module implements binary protocols for serializing and de-serializing a Python object structure. *" Pickling" * is the process whereby a Python object hierarchy is converted into a byte stream, and *" unpickling" * is the inverse operation, whereby a byte stream (from a binary file or bytes-like object) is converted back into an object hierarchy. Pickling (and unpickling) is alternatively known as " serialization" , " marshalling," [1] or " flattening" ; however, to avoid confusion, the terms used here are " pickling" and " unpickling" .

五. 小结

无, 仅作为简单记录.