【问题标题】:Compressing a list of integers in Python在 Python 中压缩整数列表
【发布时间】:2016-07-16 00:43:06
【问题描述】:

我有一个具有以下属性的正(随机)整数列表:

元素数量:78495

元素最大值:999982

转换为字符串时的列表长度:517115(字符串看起来像“6,79384,238956,...”)

磁盘上文本文件中列表的大小:520 kb

我正在尝试将此列表用作在线判断问题的预计算列表,因为实际生成此列表需要很长时间。但是,如果我直接粘贴到源代码中,则太大而无法接受,其上限为 50 kb。

我研究了 zlib 作为一种压缩字符串的方法,但它似乎只是将大小减半。

有没有办法真正缩小它,以便我可以解压缩它/在源代码中使用它?

【问题讨论】:

  • 你说这些是随机整数。为什么需要这些特定的随机整数,为什么要花这么长时间重新运行 RNG?
  • @user2357112 出于本次讨论的目的,随机 - 进入实际的数学问题是不可能的。
  • 我认为顺序很重要?如果不是,那么值之间的平均差异只有 13,因此您可以尝试对它们进行排序并压缩增量。
  • 是的,顺序很重要(具体来说,它是一个最小 k 值的列表,其中 10^k = 1 mod p for primes p > 5)。列表的第 i 个位置对应于第 (i+3) 个素数
  • 您的程序是否需要完整列表,或者它可以在输入的数字流上运行?换句话说,你能不能设置两个线程:1)一个产生最小-k值的线程;并且,2)在生成这些值时消耗/使用这些值的线程?

标签: python list memory compression


【解决方案1】:

根据你的定义...

这是一个最小 k 值的列表,其中 10^k = 1 mod p for primes p > 5

...我错误地认为您的值是(p - 1) / x 的形式,其中 x 是一个明显小于 p 的整数?

例如,对于 p

p = 7  : 10^6  = 1 (mod 7)  => k = 6  = (p - 1) / 1  => x = 1
p = 11 : 10^2  = 1 (mod 11) => k = 2  = (p - 1) / 5  => x = 5
p = 13 : 10^6  = 1 (mod 13) => k = 6  = (p - 1) / 2  => x = 2
p = 17 : 10^16 = 1 (mod 17) => k = 16 = (p - 1) / 1  => x = 1
p = 19 : 10^18 = 1 (mod 19) => k = 18 = (p - 1) / 1  => x = 1
p = 23 : 10^22 = 1 (mod 23) => k = 22 = (p - 1) / 1  => x = 1
p = 29 : 10^28 = 1 (mod 29) => k = 28 = (p - 1) / 1  => x = 1
p = 31 : 10^15 = 1 (mod 31) => k = 15 = (p - 1) / 2  => x = 2
p = 37 : 10^3  = 1 (mod 37) => k = 3  = (p - 1) / 12 => x = 12
p = 41 : 10^5  = 1 (mod 41) => k = 5  = (p - 1) / 8  => x = 8
p = 43 : 10^21 = 1 (mod 43) => k = 21 = (p - 1) / 2  => x = 2
p = 47 : 10^46 = 1 (mod 47) => k = 46 = (p - 1) / 1  => x = 1

x 值列表应该比 k 值列表压缩得更好。 (例如,我愿意打赌 x 的最常见值将是 '1'。)

而且因为计算高达 100 万的素数(我认为这是您的上限)相当容易和快速,您可以根据 x 值的压缩列表和实数快速重建 k 值列表-时间计算的素数列表。

您可能应该从一开始就解释您究竟要压缩什么以获得更准确的答案。

【讨论】:

  • 这是一个很好的点...我忘了订单必须除phi(p) = p-1
【解决方案2】:

简而言之,没有。

log(2, 999982) ~= 20

所以最大的数字需要 20 位来存储。假设平均而言,每个数字需要 10 位来存储(均匀分布在 0 和最大值之间)。

~80,000 numbers * 10 bits per number = 800,000 bits = 100,000 bytes

因此,尽可能高效地存储这些数字将占用大约 100KB 的空间。

仅当数字存在一些非随机性时,压缩才会起作用。如果它们真的是随机的,如您所说,那么一般的压缩算法将无法将其缩小,因此 100KB 大约是您希望做到的最佳值。

编辑

请注意,情况更糟,因为您想将这些粘贴到源代码中,因此您不能只使用任意二进制数据。你需要一些对文本友好的东西,比如 base64 编码,这会增加大约 33% 的开销。此外,您不能真正根据所需的平均位数来存储数字,因为您需要某种方法来了解每个单独的数字使用了多少位。有可能的编码方案,但都会带来一些额外的开销。

第二次编辑

根据上面的 cmets,数据实际上不是如最初所述的那样是随机的。因此,一个通用的压缩算法可能可以工作,如果不行,可能还有其他解决方案(例如,只发送最初生成数字的代码,它可能小于 50KB)。

【讨论】:

  • 如何将数字转换为其他基数等?
  • 您的 base-10 数字已经以二进制形式存储。任何其他表示都使用相同数量的信息。
  • @user6596353 你的问题真的没有意义。计算机以二进制(以 2 为基数)存储数据,我已经假设了这种表示形式。例如。数字 255(十进制)是二进制的 11111111,需要 7 位来存储。这已经是在计算机中存储数字的最有效方式了。
  • 我说的是文本存储(首先是这个问题的重点)。如果我有“12345”,那就是 5 个字符。但是如果我将它转换为(例如)十六进制,它会变成“3039”(少一个字符)
  • @user6596353 是的,但我已经在谈论将其直接存储为二进制文件。我给出了它需要多少存储空间的理论下限。
【解决方案3】:

可用的best text compression 提供(大约)12-17% 的压缩比 (62.4-90 kB),因此您不会达到阈值。您的数据也是随机的,这通常会使压缩算法的性能更差。

看看另一种方法,例如让您的 RNG 过程更快,或者如果您不需要完整列表(只是一些整数),则创建一个单独的“生产者”线程来生成随机整数(涉及您的任何实际数学正在使用) 和一个“消费者”线程,在这些整数进入时对其进行处理。这样,您的程序可能仍然可以工作,即使生成完整列表需要很长时间。

【讨论】:

    【解决方案4】:

    在这里,我在两个字符串上测试了 python 中易于使用的算法:一个是随机生成的,分布不均匀,另一个有一些结构。看来,lzma 做得更好

    # check the compression ratio
    import lzma
    import zlib
    import gzip
    import bz2
    import zipfile
    import tarfile
    compressors = ['lzma','zlib','gzip','bz2'] 
    a = np.exp(np.random.rand(1024))
    b = np.arange(1024)
    b[32] = -10
    b[96] = 20000
    a = bytes(a)
    b = bytes(b)
    
    for i in range(len(compressors)):
        print("{} compression ratio: ".format(compressors[i]))
        a_lzma = eval(compressors[i]).compress(a)
        b_lzma = eval(compressors[i]).compress(b)
        print(float(len(a_lzma))/len(a),float(len(b_lzma))/len(b))
        print("\n")
    

    输出:

    lzma 压缩比: 0.93115234375 0.08984375

    zlib 压缩比: 0.95068359375 0.1944580078125

    gzip 压缩比: 0.9521484375 0.196533203125

    bz2 压缩比: 0.9925537109375 0.1268310546875

    【讨论】:

      猜你喜欢
      • 2013-11-09
      • 1970-01-01
      • 2011-11-20
      • 1970-01-01
      • 2018-06-03
      • 2010-11-07
      • 2015-08-07
      • 2012-08-26
      • 1970-01-01
      相关资源
      最近更新 更多