有效地压缩numpy数组

时间:2014-03-14 09:18:17

标签: python arrays numpy compression lossless-compression

在将某些numpy arrays保存到磁盘时,我尝试了各种方法进行数据压缩。

这些一维数组包含一定采样率的采样数据(可以使用麦克风录制声音,或使用任何传感器进行任何其他测量):数据基本上是连续的(在数学意义上;当然,在采样之后它现在是离散数据)。

我尝试使用HDF5(h5py):

f.create_dataset("myarray1", myarray, compression="gzip", compression_opts=9)

但速度很慢,压缩率并不是我们所期望的最佳值。

我也试过

numpy.savez_compressed()

但是再一次,它可能不是这种数据的最佳压缩算法(如前所述)。

您会在numpy array上选择具有此类数据的更高压缩比率,

(我考虑过无损FLAC(最初是为音频而设计),但是有一种简单的方法可以在numpy数据上应用这样的算法吗?)

6 个答案:

答案 0 :(得分:12)

  1. 噪音是不可压缩的。因此,无论压缩算法如何,您拥有的任何噪声数据都将以1:1的比例进入压缩数据,除非您以某种方式丢弃它(有损压缩)。如果每个样本的24位有效位数(ENOB)等于16位,则剩余的24-16 = 8位噪声将使您的最大无损压缩率达到3:1,即使您的(无噪声)数据也是如此完全可压缩。非均匀噪声可压缩到不均匀的程度;你可能想看一下噪音的有效熵,以确定它是如何可压缩的。

  2. 压缩数据基于对其进行建模(部分是为了消除冗余,但也部分是为了将噪声分离并丢弃噪声)。例如,如果您知道数据带宽限制在10MHz并且您在200MHz采样,则可以进行FFT,将高频归零,并仅存储低频系数(在此示例中:10 :1压缩)。有一个称为"压缩传感的整个领域"这与此有关。

  3. 一个实用的建议,适用于多种合理连续的数据:去噪 - >带宽限制 - > delta压缩 - > gzip(或xz等)。降噪可以与带宽限制相同,也可以像运行中位数那样使用非线性滤波器。使用FIR / IIR可以实现带宽限制。 Delta压缩只是y [n] = x [n] - x [n-1]。

  4. 编辑插图:

    from pylab import *
    import numpy
    import numpy.random
    import os.path
    import subprocess
    
    # create 1M data points of a 24-bit sine wave with 8 bits of gaussian noise (ENOB=16)
    N = 1000000
    data = (sin( 2 * pi * linspace(0,N,N) / 100 ) * (1<<23) + \
        numpy.random.randn(N) * (1<<7)).astype(int32)
    
    numpy.save('data.npy', data)
    print os.path.getsize('data.npy')
    # 4000080 uncompressed size
    
    subprocess.call('xz -9 data.npy', shell=True)
    print os.path.getsize('data.npy.xz')
    # 1484192 compressed size
    # 11.87 bits per sample, ~8 bits of that is noise
    
    data_quantized = data / (1<<8)
    numpy.save('data_quantized.npy', data_quantized)
    subprocess.call('xz -9 data_quantized.npy', shell=True)
    print os.path.getsize('data_quantized.npy.xz')
    # 318380
    # still have 16 bits of signal, but only takes 2.55 bits per sample to store it
    

答案 1 :(得分:11)

我现在做的事情:

import gzip
import numpy

f = gzip.GzipFile("my_array.npy.gz", "w")
numpy.save(file=f, arr=my_array)
f.close()

答案 2 :(得分:1)

什么构成最佳压缩(如果有的话)高度取决于数据的性质。如果确实需要无损压缩,多种测量数据几乎是完全不可压缩的。

pytables文档包含许多有关数据压缩的有用指南。它还详细说明了速度权衡等等;事实证明,更高的压缩水平通常是浪费时间。

http://pytables.github.io/usersguide/optimization.html

请注意,这可能会达到最佳效果。对于整数测量,具有简单zip压缩类型的shuffle过滤器的组合通常可以很好地工作。此过滤器非常有效地利用了最高端字节通常为0的常见情况,并且仅包含以防止溢出。

答案 3 :(得分:1)

首先,对于一般数据集,shuffle=True create_dataset参数可以通过大致连续的数据集显着改善压缩。它非常巧妙地重新排列要压缩的位,以便(对于连续数据)位变化缓慢,这意味着它们可以被更好地压缩。根据我的经验,它可以减慢压缩速度,但在我的经验中可以显着提高压缩率。 有损,所以你确实得到了与你输入相同的数据。

如果您不太关心准确性,您还可以使用scaleoffset参数来限制存储的位数。但要小心,因为这听起来不像。特别是,它是绝对精度,而不是相对精度。例如,如果您通过了scaleoffset=8,但是您的数据点少于1e-8,那么您只会得到零。当然,如果您将数据缩放到大约1,并且不要认为您可以听到小于百万分之一的差异,那么您可以通过scaleoffset=6并获得更好的压缩很多工作。

但对于音频而言,我希望你是正确的想要使用FLAC,因为它的开发人员已经投入了大量的思想,平衡压缩与保存可区分的细节。您可以convert to WAV with scipythence to FLAC

答案 4 :(得分:1)

使用压缩保存的HDF5文件可以非常快速有效:这一切都取决于压缩算法,以及您是希望在保存时还是在读取时快速,或两者兼而有之。当然,正如上面所解释的那样,数据本身也是如此。 GZIP往往介于两者之间,但压缩率较低。 BZIP2两侧都很慢,但比例较高。 BLOSC是我发现的压缩程序之一,并且两端都很快。 BLOSC的缺点是它并未在HDF5的所有实现中实现。因此,您的程序可能无法移植。 您始终需要进行至少一些测试,以根据需要选择最佳配置。

答案 5 :(得分:0)

您可能想尝试blz。它可以非常有效地压缩二进制数据。

import blz
# this stores the array in memory
blz.barray(myarray) 
# this stores the array on disk
blz.barray(myarray, rootdir='arrays') 

stores数组在文件中或压缩在内存中。压缩基于blosc。 有关上下文,请参阅scipy video