压缩序列化 Python 数据的最 space 效率最高的方法是什么?
What's the most space-efficient way to compress serialized Python data?
By default, the pickle data format uses a relatively compact binary representation. If you need optimal size characteristics, you can efficiently compress pickled data.
我将在运行数小时的进程结束时序列化数 GB 的数据,我希望结果在磁盘上尽可能小。然而,Python offers several different ways to compress data.
是否有其中一种对腌制文件特别有效?我正在 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 lmza_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("lmza_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))
我认为 "efficiently compress pickled data" 是指通用压缩器往往运行良好。但是 Pickle 是一种协议,而不是一种格式本身。通过在自定义 类 上实现 __reduce__
方法,可以使 pickle 发出压缩字节串。尝试进一步压缩它们效果不佳。
在标准库压缩器中,LZMA 往往会为您提供典型数据流的最佳比率,但它也是最慢的。使用 ZPAQ(例如 pyzpaq
,您可能会做得更好),但速度会更慢。
只需添加一个替代方案,即可轻松为我提供最高压缩比,而且速度如此之快,我确信我在某处犯了错误(我没有)。真正的好处是解压缩也非常快,因此任何读取大量预处理数据的程序都将从中受益匪浅。一个潜在的警告是提到了“小型阵列 (<2GB)”,但看起来有解决方法。或者,如果您像我一样懒惰,通常可以选择拆分数据。
一些智能 cookie 想出了 python-blosc. It's a "high performance compressor", according to their docs. I was lead to it from an answer to 。
一旦安装通过,例如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
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)
By default, the pickle data format uses a relatively compact binary representation. If you need optimal size characteristics, you can efficiently compress pickled data.
我将在运行数小时的进程结束时序列化数 GB 的数据,我希望结果在磁盘上尽可能小。然而,Python offers several different ways to compress data.
是否有其中一种对腌制文件特别有效?我正在 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 lmza_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("lmza_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))
我认为 "efficiently compress pickled data" 是指通用压缩器往往运行良好。但是 Pickle 是一种协议,而不是一种格式本身。通过在自定义 类 上实现 __reduce__
方法,可以使 pickle 发出压缩字节串。尝试进一步压缩它们效果不佳。
在标准库压缩器中,LZMA 往往会为您提供典型数据流的最佳比率,但它也是最慢的。使用 ZPAQ(例如 pyzpaq
,您可能会做得更好),但速度会更慢。
只需添加一个替代方案,即可轻松为我提供最高压缩比,而且速度如此之快,我确信我在某处犯了错误(我没有)。真正的好处是解压缩也非常快,因此任何读取大量预处理数据的程序都将从中受益匪浅。一个潜在的警告是提到了“小型阵列 (<2GB)”
一些智能 cookie 想出了 python-blosc. It's a "high performance compressor", according to their docs. I was lead to it from an answer to
一旦安装通过,例如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
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)