在将某些numpy arrays
保存到磁盘时,我尝试了各种方法进行数据压缩。
这些一维数组包含一定采样率的采样数据(可以使用麦克风录制声音,或使用任何传感器进行任何其他测量):数据基本上是连续的(在数学意义上;当然,在采样之后它现在是离散数据)。
我尝试使用HDF5
(h5py):
f.create_dataset("myarray1", myarray, compression="gzip", compression_opts=9)
但速度很慢,压缩率并不是我们所期望的最佳值。
我也试过
numpy.savez_compressed()
但是再一次,它可能不是这种数据的最佳压缩算法(如前所述)。
您会在numpy array
上选择具有此类数据的更高压缩比率,
(我考虑过无损FLAC(最初是为音频而设计),但是有一种简单的方法可以在numpy数据上应用这样的算法吗?)
答案 0 :(得分:12)
噪音是不可压缩的。因此,无论压缩算法如何,您拥有的任何噪声数据都将以1:1的比例进入压缩数据,除非您以某种方式丢弃它(有损压缩)。如果每个样本的24位有效位数(ENOB)等于16位,则剩余的24-16 = 8位噪声将使您的最大无损压缩率达到3:1,即使您的(无噪声)数据也是如此完全可压缩。非均匀噪声可压缩到不均匀的程度;你可能想看一下噪音的有效熵,以确定它是如何可压缩的。
压缩数据基于对其进行建模(部分是为了消除冗余,但也部分是为了将噪声分离并丢弃噪声)。例如,如果您知道数据带宽限制在10MHz并且您在200MHz采样,则可以进行FFT,将高频归零,并仅存储低频系数(在此示例中:10 :1压缩)。有一个称为"压缩传感的整个领域"这与此有关。
一个实用的建议,适用于多种合理连续的数据:去噪 - >带宽限制 - > delta压缩 - > gzip(或xz等)。降噪可以与带宽限制相同,也可以像运行中位数那样使用非线性滤波器。使用FIR / IIR可以实现带宽限制。 Delta压缩只是y [n] = x [n] - x [n-1]。
编辑插图:
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 scipy和thence 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。