QZQ的小世界!

  • 首页
你好!
这里是QZQ的博客站!
  1. 首页
  2. 未分类
  3. 正文

Python的Pickle模块-数据处理加速器

2025年4月4日 92点热度 0人点赞 0条评论

引子

最近遇到了一个场景,如果一开始我就记起来用Pickle,至少会节省我三四小时的等待时间。这让我感慨一下书到用时方恨少,遂写文记录一下,防止我下次忘记了。如果想直接看用法就不用看我bb了,直接跳去用法那章。

任务大概是这样的,暂存一批数据:十万条左右的题目,和题目转化成的向量对象(np.array),向量是一维,长度768。

掏出我常用的pandas,新建了一个列来计算向量,存为csv文件,一气呵成。

然而这有一个巨大的问题,文件类型并没有被储存下来,所以本来应该是np.array类型的那个列,再被读出来之后,只是一个str类型的数据,如下所示:

import pandas
import numpy as np

data = {
    'brand': ['golang', 'Python', 'Java'],
    'C': [np.array([1, 2, 3, 1, 1]), np.array([4, 6, 8, 12, 10]), np.array([10, 2, 5, 20, 16])],
    }

df = pandas.DataFrame(data)
print(type(df.loc[0, 'C']), df.loc[0, 'C'])
"""  
查看储存在df中的数据,是numpy.ndarray类型
<class 'numpy.ndarray'> [1 2 3 1 1]
"""

df.to_csv('test.csv')
df = pandas.read_csv('test.csv')  # 储存文件后再读取
print(type(df.loc[0, 'C']), df.loc[0, 'C'])
"""  
查看储存在df中的数据,已经变成了str
<class 'str'> [1 2 3 1 1]
"""

这样的话想在算法中复用,只能再重新写一个转换脚本,将字符串列转换成numpy.ndarray类型,如下:

import pandas
import numpy as np


def _str2ary(s: str):
    s = s[1:-1]  # 去掉[]号
    l = [i for i in s.split(' ')]
    while '' in l:
        l.remove('')
    return np.array([int(i) for i in l])


data = {
    'brand': ['golang', 'Python', 'Java'],
    'C': [np.array([1, 2, 3, 1, 1]), np.array([4, 6, 8, 12, 10]), np.array([10, 2, 5, 20, 16])],
    }

df = pandas.DataFrame(data)

df.to_csv('test.csv')
df = pandas.read_csv('test.csv')  # 储存文件后再读取
df['C'] = df['C'].apply(_str2ary)
print(type(df.loc[0, 'C']), df.loc[0, 'C'])
"""
终于转化回来了...
<class 'numpy.ndarray'> [1 2 3 1 1]
"""

折磨,费劲,不优雅…

尤其是十万量级的数据,768的向量长度,每次执行算法,加载9g的csv文件大概5min,然后转化大概要半小时……

此时Pickle的意义就很明显了…


简介

Pickle的官网简介

pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化,但是这种数据几乎只能由python来再次使用。

简单来说,就是pickle能把python中的特殊对象以python的方式(二进制数据)直接存在本地,要的时候读出来就好,任意对象都可以序列化,包括跑AI的那些模型参数均可。


用法

常用的几个函数是

  • **pickle.dump(obj, file, protocol=None, *, fix_imports=True)**

  • **pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict')**

file参数就是open函数打开的一个文件流,其他参数意义不大,这里不详细介绍。

案例

import pickle
import pandas
import numpy as np

data = {
    'brand': ['golang', 'Python', 'Java'],
    'C': [np.array([1, 2, 3, 1, 1]), np.array([4, 6, 8, 12, 10]), np.array([10, 2, 5, 20, 16])],
    }

df = pandas.DataFrame(data)
print(type(df.loc[0, 'C']), df.loc[0, 'C'])
"""  
<class 'numpy.ndarray'> [1 2 3 1 1]
"""

# 这里wb不能写成w,w为写入模式,b为二进制写入模式(bit),pickle只支持二进制模式
with open("test.pkl", "wb") as f:
    pickle.dump(df, f)  # 储存为test.pkl
del df  # 删除原来的df对象

with open("test.pkl", "rb") as f:
    df = pickle.load(f)
print(type(df.loc[0, 'C']), df.loc[0, 'C'])
"""
还是原来的数据类型
<class 'numpy.ndarray'> [1 2 3 1 1]
"""

test.pkl会被储存在当前目录,后缀可以随意,如果感兴趣用记事本打开的话,可以看到一堆乱乱码,pickle基本没有可读性,就是给python复用的数据文件。

另外还有两个函数

  • **pickle.dumps(obj, protocol=None, *, fix_imports=True)**

  • **pickle.loads(data, *, fix_imports=True, encoding='ASCII', errors='strict')**

这里的obj和data是二进制的数据,因为不常用,所以就提一嘴。


注意事项

尽管pickle非常方便,但在使用它时需要注意一些事项:

  • 安全性:反序列化数据时要小心,因为pickle可以执行任意代码。不要从不受信任的来源加载pickle数据,以免遭受安全风险。

  • 版本兼容性:在不同版本的Python之间,pickle数据的兼容性可能会有问题。因此,确保在不同版本之间测试并验证pickle数据的兼容性。

  • 自定义对象:一些自定义对象的序列化和反序列化可能会受到限制,因此需要额外的配置。你可能需要实现特定的__reduce__方法来控制对象的序列化行为。

这个第三点是,如果你pickle了一个DataFrame对象到本地,然后copy到第二台电脑,如果第二个电脑环境并没有Pandas库,那么load的时候就会报错。


参考

https://blog.csdn.net/wuShiJingZuo/article/details/133978427

https://blog.csdn.net/m0_46223009/article/details/128086147

一文带你搞懂Python中pickle模块 - 知乎 (zhihu.com)

[文章导入自 http://qzq-go.notion.site/10b314ae54e0428183c36a0d0efa8c07 访问原文获取高清图片]

本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: IT技术 Python Python库介绍 Python标准库
最后更新:2025年4月3日

QZQ

一只涉猎广泛的技术爱好者,绝赞养猫中~

点赞
< 上一篇
下一篇 >

归档

  • 2025 年 4 月
  • 2025 年 3 月
  • 2025 年 2 月
  • 2025 年 1 月
  • 2024 年 12 月
  • 2024 年 11 月

分类

  • 技术
  • 未分类

COPYRIGHT © 2024 QZQ的小世界!. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang