一. 前言
在使用sklearn
的California_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)
正确的跳转应该是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 中, 使用
pickle
或json
库可以轻松地对对象进行序列化和反序列化操作. - 数据一致性: 序列化后的对象在存储或传输过程中能够保持数据的一致性. 反序列化后得到的对象与原对象在内容上是相同的, 保证了数据的准确性. 这对于需要精确恢复对象状态的应用场景( 如数据库备份和恢复, 分布式系统中的数据同步) 非常重要.
3.3 缺点
- 性能开销: 序列化和反序列化操作通常需要一定的计算资源和时间, 尤其是对于复杂的对象或大规模的数据. 在序列化过程中, 需要遍历对象的所有属性, 并将其转换为序列化格式; 反序列化时则需要将序列化数据解析并恢复为对象. 这些操作会增加程序的运行时间和 CPU 负载. 例如, 在处理大量数据的实时系统中, 频繁的序列化和反序列化操作可能会成为性能瓶颈.
- 兼容性问题: 不同的序列化格式和版本之间可能存在兼容性问题. 如果在序列化和反序列化过程中使用的格式或版本不一致, 可能会导致反序列化失败或数据丢失. 例如, 当程序升级后, 使用了新的序列化格式, 但旧版本的程序无法识别该格式, 就会出现兼容性问题. 另外, 不同编程语言实现的序列化机制也可能存在差异, 这会给跨语言的数据交换带来困难.
- 安全风险: 某些序列化机制存在安全风险, 特别是在反序列化过程中. 如果反序列化的数据来自不可信的源, 可能会执行恶意代码, 导致系统受到攻击. 例如, Python 的
pickle
模块在反序列化时会执行对象的构造函数和其他方法, 如果加载的pickle
文件包含恶意代码, 就可能会对系统造成损害.
四. 常用相关包
机器学习模型保存pickle, joblib, pmml等三种方式的优缺点_pmml 与 pickle-CSDN博客
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:
- transparent disk-caching of functions and lazy re-evaluation (memoize pattern)
- 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
开源协议, 也是相对宽松的协议, 对于商业应用也是非常自由的.
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" .
五. 小结
无, 仅作为简单记录.