有效地压缩numpy数组

问题描述 投票:11回答:6

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

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

我尝试使用HDF5(h5py):

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

但这很慢,压缩比不是我们所能期望的最好。

我也尝试过

numpy.savez_compressed()

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

你有什么选择在numpy array上获得更好的压缩率,有这样的数据?

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

python arrays numpy compression lossless-compression
6个回答
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]。

编辑插图:

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

11
投票

我现在应该做什么:

import gzip
import numpy

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

1
投票

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

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

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

请注意,这可能与它将获得的一样好。对于整数测量,具有简单zip压缩类型的shuffle过滤器的组合通常可以很好地工作。该过滤器非常有效地利用了最高端字节通常为0的常见情况,并且仅包括防止溢出。


1
投票

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

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

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


1
投票

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


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

© www.soinside.com 2019 - 2024. All rights reserved.