压缩序列化 Python 数据最节省空间的方法是什么?



来自 Python 文档:

默认情况下,pickle 数据格式使用相对紧凑的二进制表示形式。如果需要最佳大小特征,可以有效地压缩酸洗数据。

我将在运行几个小时的进程结束时序列化几千兆字节的数据,我希望结果在磁盘上尽可能小。但是,Python提供了几种不同的方法来压缩数据。

其中是否有一种对腌制文件特别有效?我正在腌制的数据主要由嵌套字典和字符串组成,所以如果有更有效的压缩方法,例如 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。根据他们的文档,这是一个"高性能压缩机"。我从这个问题的答案中被引导到它。

安装后,例如pip install bloscconda install python-blosc,您可以非常轻松地压缩酸洗数据,如下所示:

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是一种协议,而不是一种格式本身。可以通过在自定义类上实现__reduce__方法来使 pickle 发出压缩字节字符串。试图进一步压缩这些不会很好地工作。

在标准库压缩器中,LZMA 倾向于为您提供典型数据流的最佳比率,但它也是最慢的。你可能使用ZPAQ做得更好(比如说通过pyzpaq(,但这甚至更慢。

mgzip 是一个更快的解决方案。 LZMA非常慢,尽管它的压缩比MGZzip高出约25%。

with mgzip.open(pathname, 'wb') as f:
pickle.dump(data, f)

对于加载:

with mgzip.open(pathname, 'rb') as f:
data = pickle.load(f)

相关内容

最新更新