Python 压缩此数据的更快方法是什么?

Python 压缩此数据的更快方法是什么?,python,compression,huffman-code,Python,Compression,Huffman Code,我有一个程序,可以计算大量数据并将其写入文件。我的数据只是一组从0到16的数字(17个不同的值),我计算了每个数字出现在数据中的频率。我需要使用尽可能少的磁盘空间和RAM,因此我用纯python编写了一个小的Huffman编码/解码模块,它一次用内存中尽可能少的编码符号写入/读取压缩数据。python中是否有一个模块可以做类似的事情?下面是一段代码,并举例说明如何使用它(警告这段代码的注释相当长): def生成树(数据): “”“数据是元组列表,谁的第一个条目是优先级/频率 第二个条目是包含要访

我有一个程序,可以计算大量数据并将其写入文件。我的数据只是一组从0到16的数字(17个不同的值),我计算了每个数字出现在数据中的频率。我需要使用尽可能少的磁盘空间和RAM,因此我用纯python编写了一个小的Huffman编码/解码模块,它一次用内存中尽可能少的编码符号写入/读取压缩数据。python中是否有一个模块可以做类似的事情?下面是一段代码,并举例说明如何使用它(警告这段代码的注释相当长):

def生成树(数据):
“”“数据是元组列表,谁的第一个条目是优先级/频率
第二个条目是包含要访问的数据的元组
树使用一个内部标记系统来告诉
分支结束。(结束节点以False结尾)
def标签(数据):
taggedData=[]
对于优先级,数据中的数据:
#所有初始数据都是末端分支
taggedData+=[(优先级,(基准,假))]
返回标记
#将标记的数据按优先级/频率的降序排列
树=已排序(标记(数据),反向=真)
而len(tree)>1:
#获取两个优先级最低的分支
bottomR,bottomL=tree.pop(),tree.pop()
#并将它们组合成一个新的分支,具有组合优先级
新元素=底部[0]+底部[0],((底部,底部),真)
#然后将它们添加回分支列表并排序
树+=[新元素]
tree.sort(reverse=True)
返回树[0]
def makeTable(树,代码=”):
“”“获取makeTree生成的树并返回字典
代码类型:值对。”“”
#如果这是结束分支,则返回代码:值对
如果树[1][1]==False:
返回{code:tree[1][0]}
#否则,请查找左分支和右分支的表格
#将它们添加到主表中,然后返回
表={}
table.update(makeTable(树[1][0][0],代码+'0'))#左
table.update(makeTable(树[1][0][1],代码+'1'))#右
返回表
类解码器:
“”“此类创建一个解码器对象,该对象用于解码压缩的
文件使用适当的解码表(duh)。它过去是一个函数,
但它是有缺陷的,如果我把它留作一个函数,它也会很难看
类是在Encdoer类之后编写的。)
"""
定义初始化(self,fname,table):
self.file=open(fname)
self.table=表格
self.byte=None
self.bit=7
self.newByte=True
def解码(自身,大小=1):
“”“解码并生成文件中符号的大小和数量。
大小默认为1“”
#读取了多少符号的计数器
读取=0
代码=“”
阅读时
  • 在内存中,相同值的不同出现只占用一个位置。不过,对它们的引用是重复的
  • 对于磁盘存储,我可能只是用压缩

如果您的数据有明显的重复性,那么您可能需要尝试对其进行运行长度编码,这可能是一种相对快速的操作。下面是一个作为生成器的实现,它可以帮助最小化总体内存使用。请注意,当一次运行非常短时,它只输出值,而不是(重复计数,值)元组,以避免输出膨胀,并可能使其比原来更长

from itertools import groupby

def run_length_encode(data):
    for value, igroup in groupby(data):
        repeat_count = len(list(igroup))
        yield value if repeat_count == 1 else repeat_count, value

if __name__ == '__main__':
    """ generate some random data with repeats and encode it """
    import random

    DATA_SIZE = 20
    MAX_VAL = 16
    MAX_REPEAT = 5
    data = []
    while len(data) < DATA_SIZE:
        val = random.randint(0, MAX_VAL)
        repeat = min(DATA_SIZE-len(data), random.randint(0, MAX_REPEAT))
        for _ in xrange(repeat): data.append(val)

    print data
    print [item for item in run_length_encode(data)]
如果运行时间很长,最好以迭代方式明确计算每个组中有多少次,而不是将它们转换为列表并计算其长度:

def ilen(iterable):
    """ return the number of items in an iterable """
    return sum(1 for _ in iterable)

def run_length_encode(data):
    for value, igroup in groupby(data):
#        repeat_count = len(list(igroup))
        repeat_count = ilen(igroup)
        yield value if repeat_count == 1 else repeat_count, value

由于数据值的范围相对较小,因此可以(也可以)将其编码为单字节字符值。

对于实际数据,必须计算每个值的出现频率才能进行哈夫曼编码将相对非常耗时。若你们可以预先计算,然后只使用一个数据的统计模型,这将大大加快这部分过程。或者,您可以根据数据的性质做一些非常简单的事情。如果许多值连续重复,您可能只需要对它们进行运行长度编码,这将非常快,并且可能会节省大量内存。换言之,你可能不得不在一个目标和另一个目标之间进行权衡。哦,天哪。你也许刚刚启发了我!我的数据中有大量重复的连续值(我认为前30万个值都是17:p!)全部是17?我记得你说数值在0-16之间。正确。zlib进行哈夫曼编码,并引用重复的字符串进行进一步压缩。只需将每个0..16值放在一个字节中,然后用zlib压缩字节序列。(但是请注意,zlib不是zip。)@MarkAdler zlib与gzip兼容,这对我来说已经足够zip了。说真的,我说的是压缩。答案已编辑。@cmd我最终使用pypng将所有临时文件制作成PNG,这基本上符合您的建议。我已经在用pypng制作mandelbrot图片了。
def ilen(iterable):
    """ return the number of items in an iterable """
    return sum(1 for _ in iterable)

def run_length_encode(data):
    for value, igroup in groupby(data):
#        repeat_count = len(list(igroup))
        repeat_count = ilen(igroup)
        yield value if repeat_count == 1 else repeat_count, value