joblib和pickle有哪些不同的用例?

140

背景:我刚开始接触scikit-learn,阅读了页面底部关于 joblib与pickle的对比

也许更有趣的是使用joblib替代pickle(joblib.dump和joblib.load),它在处理大数据时更加高效,但只能将数据保存到磁盘而不能保存到字符串中

我看到了这篇有关Pickle的常见用例,想知道社区是否能分享一下joblib和pickle之间的区别?在什么情况下应该使用其中之一?

4个回答

178
  • joblib通常在大型numpy数组上运行更快,因为它对numpy数据结构的数组缓冲区有特殊处理。要了解实现细节,可以查看源代码。它还可以在 pickling 时使用 zlib 或 lz4 实时压缩数据。
  • joblib还可以使非压缩joblib-pickled numpy数组的数据缓冲区进行内存映射,从而实现进程间共享内存。
  • 如果不对大型numpy数组进行pickle,则通常使用正常pickle会更快,特别是在大量小Python对象(例如大字典的str对象)的情况下,因为标准库的pickle模块是用C实现的,而joblib则是纯python。
  • 自从PEP 574(Pickle protocol 5)合并到Python 3.8之后,使用标准库pickle来pickle大型numpy数组现在更加高效(在内存和CPU方面)。在这种情况下,大数组的大小为4GB或更大。
  • 但是对于具有嵌套numpy数组的对象,使用Python 3.8仍然可以使用joblib以内存映射模式加载,使用mmap_mode="r"

2
这是否意味着我们应该使用Joblib而不是Pickle?我们应该考虑Joblib的任何缺点吗?我最近才听说过Joblib,它听起来很有趣。 - Chau Pham
3
我已经更新了我的答案,包括标准库中的缺点和新内容。 - ogrisel
2
joblib在反序列化期间是否也执行任意代码?(不安全) - Mr-Programs
2
这段内容很难通过所有的“请注意…”来阅读并获取一行总结:在3.8中,joblib写入大型numpy数组的速度是X倍,大约是多少?读取速度呢?而pickle写入大量小Python对象的速度大约是Y倍,读取速度呢? 另外,相对压缩比/文件大小是多少? - smci
默认情况下,joblib和pickle都不会压缩数据。因此文件大小与内存中的数组大小大致相同。但是您可以在两种情况下将其转储到压缩文件对象中(例如https://docs.python.org/3/library/gzip.html#gzip.GzipFile)。 joblib还有一种高级方法来实现:https://joblib.readthedocs.io/en/latest/persistence.html#compressed-joblib-pickles 压缩比取决于数组中的数据(随机=>低压缩,规则/恒定=>高)。 - ogrisel
2
我想知道这个答案在10年后是否仍然有效。scikit-learn仍然建议使用joblib。一定有原因,对吧? - Dr_Zaszuś

12

感谢Gunjan提供这个脚本!我对其进行了修改以适用于Python3结果

#comapare pickle loaders
from time import time
import pickle
import os
import _pickle as cPickle
from sklearn.externals import joblib

file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'database.clf')
t1 = time()
lis = []
d = pickle.load(open(file,"rb"))
print("time for loading file size with pickle", os.path.getsize(file),"KB =>", time()-t1)

t1 = time()
cPickle.load(open(file,"rb"))
print("time for loading file size with cpickle", os.path.getsize(file),"KB =>", time()-t1)

t1 = time()
joblib.load(file)
print("time for loading file size joblib", os.path.getsize(file),"KB =>", time()-t1)

time for loading file size with pickle 79708 KB => 0.16768312454223633
time for loading file size with cpickle 79708 KB => 0.0002372264862060547
time for loading file size joblib 79708 KB => 0.0006849765777587891

Gunjan使用了一个1154320653 KB的pickle文件。一个更大的文件会对joblib有利吗? - guiferviz
4
请在展示性能数字时始终注明Python版本,2.6?2.7?3.6?3.7?更好的做法是报告相对数字:joblib vs pickle vs cPickle。此外,纠正Gunjan的错误,应为1.1 GB而非1.1 TB。 - smci
1
只是一些问题:(1)需要lis = []这行吗?(2)如何复制代码?也就是说,我们应该如何构建“database”文件?谢谢。 - RMurphy

9

我遇到了同样的问题,所以尝试了这个解决方案(使用Python 2.7),因为我需要加载一个大型的pickle文件。

#comapare pickle loaders
from time import time
import pickle
import os
try:
   import cPickle
except:
   print "Cannot import cPickle"
import joblib

t1 = time()
lis = []
d = pickle.load(open("classi.pickle","r"))
print "time for loading file size with pickle", os.path.getsize("classi.pickle"),"KB =>", time()-t1

t1 = time()
cPickle.load(open("classi.pickle","r"))
print "time for loading file size with cpickle", os.path.getsize("classi.pickle"),"KB =>", time()-t1

t1 = time()
joblib.load("classi.pickle")
print "time for loading file size joblib", os.path.getsize("classi.pickle"),"KB =>", time()-t1

这个的输出结果是

time for loading file size with pickle 1154320653 KB => 6.75876188278
time for loading file size with cpickle 1154320653 KB => 52.6876490116
time for loading file size joblib 1154320653 KB => 6.27503800392

根据这个,joblib比这3个模块中的cPickle和Pickle模块表现更好。谢谢。

2
我认为cpickle应该比pickle更快吧? - Echo
这个基准测试是使用Python 3完成的吗?Python 3默认使用pickle(protocol = 3)(比Python 2中的默认值更快)? - LearnOPhile
4
os.path.getsize返回的是字节而不是千字节,因此我们讨论的是大约1.1 GB大小的文件(而不像输出中看起来的1.1 TB)。 - Vlad Iliescu
这很好,但请修正输出以反映它是1.1 GB而不是1.1 TB。更好的做法是绘制1KB到10GB的大小文件的10次幂的比较数字,针对Python版本3.6、3.7、3.8和2.7,以及joblib、pickle和cPickle。 - smci

-2

仅作一份谦逊的说明... 对于已拟合的scikit-learn估算器/训练模型,Pickle更好。在机器学习应用中,训练好的模型主要是为了进行预测而保存和加载。


这并没有回答楼主的问题,更适合作为一条评论。 - mishsx
4
为什么在这种情况下泡菜更好? - Blake F.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接