Compression 对唯一数据流的压缩

Compression 对唯一数据流的压缩,compression,zlib,Compression,Zlib,我有很多整数数组。每一个都有几千个整数,每个整数通常与前面的整数相同,或者只相差一两位。我想缩小每个阵列,使其尽可能小,以减少磁盘IO Zlib将其缩小到原来大小的25%左右。这很好,但我不认为它的算法特别适合这个问题。是否有人知道一个压缩库或简单算法可以更好地处理这类信息 更新:zlib将其转换为一个xor增量数组后,会将其缩小到原始大小的20%左右 你试过bzip2吗? 对我来说,它总是比zlib更有效。你考虑过吗 或者试着这样做:不存储数字本身,而是存储数字之间的差异。1235变为101

我有很多整数数组。每一个都有几千个整数,每个整数通常与前面的整数相同,或者只相差一两位。我想缩小每个阵列,使其尽可能小,以减少磁盘IO

Zlib将其缩小到原来大小的25%左右。这很好,但我不认为它的算法特别适合这个问题。是否有人知道一个压缩库或简单算法可以更好地处理这类信息


更新:zlib将其转换为一个xor增量数组后,会将其缩小到原始大小的20%左右

你试过bzip2吗?

对我来说,它总是比zlib更有效。

你考虑过吗

或者试着这样做:不存储数字本身,而是存储数字之间的差异。1235变为101012。现在,大多数需要编码的数字都非常小。要存储小整数,请使用8位整数,而不是在大多数平台上编码的32位整数。这是4的因子。如果您确实需要为更大的间隙做好准备,请指定8位整数的高位,表示“此数字还需要下一个8位”

根据您的数据,您可以将其与运行长度编码相结合,以获得更好的压缩比


这两个选项都不是特别难实现的,它们都运行得非常快,内存非常少(与bzip相反)。

也许答案是以类似于bzip的方式预过滤阵列。下面是我脑海中的一些想法。我没有尝试过这些方法,但如果你想玩,它们可能会很有趣

  • 将整数分成4个字节,这样i0,i1,i2,…,in变成b0,0,b0,1,b0,2,b0,3,b1,0,b1,1,b1,1,b1,3,…,bn,0,bn,1,bn,2,bn,3。然后写出所有的bi,0,然后是bi,1,bi,2和bi,3。如果在大多数情况下,您的数字只相差一两位,那么您应该得到很好的重复字节长运行,使用运行长度编码或zlib之类的方法可以很好地压缩这些字节。这是我目前最喜欢的方法

  • 如果每个数组中的整数与前一个数组密切相关,您可以存储原始整数,然后与前一个条目进行差异-这将提供一组较小的值来提取,这通常会导致更压缩的形式

  • 如果您有不同的位,您仍然可能有较大的差异,但如果您更可能有对应于(通常)一个或两个不同位的较大数值差异,您最好使用创建一个字节数组的方案-使用前4个字节对第一个整数进行编码,然后,对于每个后续条目,使用0或更多字节来指示应该翻转哪些位-在字节中存储0、1、2、…、或31,并使用哨兵(比如32)来指示何时完成。这可能导致需要表示的原始字节数和整数平均接近2,这是大多数字节来自有限的集合(0-32)。通过zlib运行该流,也许您会感到惊喜


  • 您需要预处理数据——首先,可逆地将其转换为更适合后端数据压缩方法的某种形式。详细信息将取决于后端压缩方法,以及(更重要的是)所压缩数据的预期属性

    在您的例子中,zlib是一种字节压缩方法,但您的数据是(32位?)整数。您不需要自己重新实现zlib,但您确实需要阅读它的工作原理,这样您就可以找出如何使用易于压缩的数据来表示它,或者它是否适合您的目的


    Zlib实现了一种形式的Lempel-Ziv编码。JPG和许多其他人在后端使用哈夫曼编码。运行长度编码在许多特殊用途中很流行。等等……

    由于您关心的是减少磁盘IO,因此您需要独立压缩每个整数数组,而不参考其他整数数组

    场景中的一种常见技术是存储差异,因为少量差异可以用短码字编码。听起来您需要为差异制定自己的编码方案,因为它们是多位差异,可能需要使用8位字节作为起点:

    • 1位,表示后面是一个完整的新整数,或该字节编码了与上一个整数的差异
    • 1位表示后面有更多字节,记录同一整数的更多单位差异
    • 6位,记录要从上一个整数切换的位号
    如果有超过4位不同,则存储整数


    如果你也有很多完全不同的代码,这个方案可能不合适,因为它们现在每个需要5个字节,而不是4个。

    如果大多数整数真的与前面的相同,并且符号间的差异通常可以表示为单位翻转,这听起来像是异或的工作

    采用如下输入流:

    1101
    1101
    1110
    1110
    0110
    
    和输出:

    1101
    0000
    0010
    0000
    1000
    
    一点伪代码

    compressed[0] = uncompressed[0]
    loop
      compressed[i] = uncompressed[i-1] ^ uncompressed[i]
    
    我们现在已经将大部分输出减少到0,即使更改了高位。您使用的任何其他工具中的RLE压缩都将有一天与此相关。它可以更好地处理32位整数,并且它仍然可以对流中出现的完全不同的整数进行编码。您省去了自己处理比特打包的麻烦,因为所有东西都是整数大小的数量

    当您要解压缩时:

    uncompressed[0] = compressed[0]
    loop
      uncompressed[i] = uncompressed[i-1] ^ compressed[i]
    
    这也是一个简单的算法,运行速度非常非常快,因为它只是XOR