用例:Python类在一个有用的结构中存储大型numpy数组(很大,但足够小,在内存中使用它们很容易)。这是一幅关于这种情况的漫画:
主类:Environment
;存储与所有球相关的有用信息
"child"类:Ball
;存储与该特定球相关的信息
Environment
成员变量:balls_in_environment
(Ball
s列表)
Ball
成员变量:large_numpy_array
(NxN numpy数组很大,但在内存中仍然很容易使用)
我想最好把Environment
作为一个整体来坚持。
一些选项:
-
pickle
:太慢,它产生的输出占用了硬盘上的大量空间 -
数据库:工作量太大;我可以将类中的重要信息存储在数据库中(需要我编写函数来从类中获取信息,并将其放入数据库),然后通过创建一个新实例来重建类,并用数据库中的数据重新填充它(需要我写函数来进行重建)
-
JSON:我对JSON不是很熟悉,但Python有一个标准库来处理它,这是本文推荐的解决方案——不过我不认为JSON会比
pickle
更紧凑;更重要的是,不能很好地处理numpy
-
MessagePack:上面提到的同一篇文章推荐的另一个包;然而,我从来没有听说过它,也不想用的标准问题来打击未知
-
numpy.save
+其他东西:使用numpy.save
功能存储与每个Ball
关联的numpy数组,并以某种方式单独存储非numpy内容(乏味)?
我的用例的最佳选项是什么?
正如我在评论中提到的,joblib.dump
可能是一个不错的选择。它使用np.save
来有效地存储numpy数组,并使用cPickle
来存储其他所有内容:
import numpy as np
import cPickle
import joblib
import os
class SerializationTest(object):
def __init__(self):
self.array = np.random.randn(1000, 1000)
st = SerializationTest()
fnames = ['cpickle.pkl', 'numpy_save.npy', 'joblib.pkl']
# using cPickle
with open(fnames[0], 'w') as f:
cPickle.dump(st, f)
# using np.save
np.save(fnames[1], st)
# using joblib.dump (without compression)
joblib.dump(st, fnames[2])
# check file sizes
for fname in fnames:
print('%15s: %8.2f KB' % (fname, os.stat(fname).st_size / 1E3))
# cpickle.pkl: 23695.56 KB
# numpy_save.npy: 8000.33 KB
# joblib.pkl: 0.18 KB
一个潜在的缺点是,由于joblib.dump
使用cPickle
序列化Python对象,因此生成的文件无法从Python 2移植到Python 3。为了获得更好的可移植性,您可以考虑使用HDF5,例如在这里。