我正在努力有效地存储大量(> 10亿)时间序列。每个值只能是1,0或-1,并且每分钟记录一次,持续40,000分钟。
我意识到每分钟值可以存储在2位中,但我认为有一种更简单的方法:任何时间段的排列数量都是有限的,所以我可以为每个排列分配一个数字而不是记录所有位。
例如,如果我需要16分钟的时间段:记录这些值需要(16 x 2位)= 32位= 4字节。但据推测,如果我只是为16个可能的排列中的每一个分配一个数字,我可以将该数字减半(或更多)。
我的问题:确定16个值的排列数的公式是什么?我知道如果值可以是任何数字,如何计算它,但是当只有3个值时,我知道怎么做。
答案 0 :(得分:2)
例如,您可以压缩文件,只需3个符号即可获得很好的压缩级别。
如果你想做艰苦的工作,你可以做基本的zip算法:
您有3个值-1,0和1。
然后你可以定义一个转换树,如:
bit sequence - symbol
0 - 0
10 - 1
110 - -1
1110 - End of data
因此,如果你读零,你知道它是一个0符号,如果你读一个1,你必须阅读下一位知道它是1还是你必须再读一个知道它是否是1 a -1。
因此,如果您有一个1,1,0,-1,0系列,它将翻译为:
101001100
如果这是您看到的所有数据都有9位,那么您需要完成一些事情才能达到16位。
然后只是放一个数据标记的结尾,之后就是任何一个。
10100110 01110000
为此,您需要使用位运算符。
如果您知道这些符号中的任何符号的出现率大于其余符号,则使用该符号的位数较少(例如,0应代表最常用的符号)。
答案 1 :(得分:2)
如果-1,0和1都具有相同的可能性,则 n 样本所需的位数公式为 ceiling(n log 2 3)。对于一个样本,你会得到两个比特,有效地浪费了其中一个状态,每个样本浪费了多于0.4比特。
事实证明,五个样本非常适合8位,其中3 5 = 243,每个符号只有大约0.015位浪费。
您可以使用额外状态作为流末尾符号。例如,您可以使用其余13个状态中的5个来表示流末尾,表示剩余0,1,2,3或4个样本。然后,如果它是1,2,3或4,那么这些样本还有一个字节。稍微好一点就是在1个案例中使用三种状态,在该字节中提供样本。然后使用13个状态中的7个,需要一个字节来结束0和1个案例的流,并且需要2个字节来结束流,以便剩余2,3或4个。
如果-1,0和1具有明显不同的概率,那么您可以对样本使用霍夫曼编码,以比上面的“平坦”情况更少的比特来表示结果。然而,对于三个符号的一个样本,只有一个霍夫曼代码,这通常不会提供良好的性能。因此,您将再次希望组合样本以获得更好的霍夫曼编码性能。 (或者使用算术编码,但这比在这种情况下可能需要的更多。)因此,您可以再次将五个样本分组到0..242范围内的一个整数中,并且Huffman将这些样本编码为一个整数,以及流末尾只发生一次的符号(称之为243)。