来自 Python 文档:
默认情况下,pickle 数据格式使用相对紧凑的二进制表示。如果您需要最佳尺寸特性,您可以有效地压缩 pickled 数据。
我将在运行数小时的进程结束时序列化数 GB 的数据,我希望结果在磁盘上尽可能小。然而,Python 提供了几种不同的方式来压缩数据。
是否有其中一种对腌制文件特别有效?我正在 pickle 的数据主要由嵌套的字典和字符串组成,所以如果有更有效的压缩方法,例如JSON,那也行。
压缩和解压的时间并不重要,但是这个过程生成数据所花费的时间使得试错不方便。
我使用 Pickled 对象做了一些测试,
lzma
给出了最好的压缩。
但是您的结果可能会根据您的数据而有所不同,我建议您使用自己的一些样本数据对其进行测试。
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 9/17/2019 10:05 PM 23869925 no_compression.pickle
-a---- 9/17/2019 10:06 PM 6050027 gzip_test.gz
-a---- 9/17/2019 10:06 PM 3083128 bz2_test.pbz2
-a---- 9/17/2019 10:07 PM 1295013 brotli_test.bt
-a---- 9/17/2019 10:06 PM 1077136 lzma_test.xz
使用的测试文件(您需要
pip install brotli
或删除该算法):
import bz2
import gzip
import lzma
import pickle
import brotli
class SomeObject():
a = 'some data'
b = 123
c = 'more data'
def __init__(self, i):
self.i = i
data = [SomeObject(i) for i in range(1, 1000000)]
with open('no_compression.pickle', 'wb') as f:
pickle.dump(data, f)
with gzip.open("gzip_test.gz", "wb") as f:
pickle.dump(data, f)
with bz2.BZ2File('bz2_test.pbz2', 'wb') as f:
pickle.dump(data, f)
with lzma.open("lzma_test.xz", "wb") as f:
pickle.dump(data, f)
with open('no_compression.pickle', 'rb') as f:
pdata = f.read()
with open('brotli_test.bt', 'wb') as b:
b.write(brotli.compress(pdata))
只需添加一个可以轻松为我提供最高压缩比的替代方案,而且速度如此之快,我确信我在某个地方犯了错误(我没有)。真正的好处是解压缩也非常快,因此任何读取大量预处理数据的程序都将从中受益匪浅。一个潜在的警告是提到“小数组(<2GB)" 这里的某个地方,但看起来有解决方法。或者,如果你像我一样懒惰,通常可以选择分解数据。
一些智能饼干想出了python-blosc。根据他们的文档,这是一个“高性能压缩器”。我是从对this question.
的回答中得到的。一旦安装通过,例如
pip install blosc
或 conda install python-blosc
,您可以很容易地压缩 pickled 数据,如下所示:
import blosc
import numpy as np
import pickle
data = np.random.rand(3, 3, 1e7)
pickled_data = pickle.dumps(data) # returns data as a bytes object
compressed_pickle = blosc.compress(pickled_data)
with open("path/to/file/test.dat", "wb") as f:
f.write(compressed_pickle)
阅读它:
with open("path/to/file/test.dat", "rb") as f:
compressed_pickle = f.read()
depressed_pickle = blosc.decompress(compressed_pickle)
data = pickle.loads(depressed_pickle) # turn bytes object back into data
我使用的是 Python 3.7,甚至没有查看所有不同的压缩选项,我得到的压缩比约为 12,读取 + 解压 + 加载压缩的 pickle 文件比加载未压缩的 pickle 文件花费的时间长几分之一秒。
我写这个更多是为了给自己参考,但我希望其他人会觉得这有用。
和平oot
我把“有效压缩腌制数据”的意思是通用压缩器往往工作良好。但是 Pickle 是一种协议,而不是一种格式本身。通过在您的自定义类上实现
__reduce__
方法,可以使 pickle 发出压缩的字节串。试图进一步压缩这些效果不会很好。
在标准库压缩器中,LZMA 往往会为您提供典型数据流的最佳比率,但它也是最慢的。您可能可以使用 ZPAQ 做得更好(例如,通过
pyzpaq
),但这甚至更慢。
mgzip 是一个更快的解决方案。 lzma 慢得令人痛苦,尽管它的压缩率比 mgzip 好 25%。
with mgzip.open(pathname, 'wb') as f:
pickle.dump(data, f)
装载:
with mgzip.open(pathname, 'rb') as f:
data = pickle.load(f)