いくつかのnumpy arrays
をディスクに保存するときに、さまざまな方法でデータ圧縮を試みました。
これらの1Dアレイには、特定のサンプリングレートでサンプリングされたデータが含まれています(マイクで録音したり、センサーでその他の測定を行うことができます):データは本質的に連続的です(数学的な意味で;もちろんサンプリング後は離散データになります)。
私はHDF5
(h5py)で試しました:
f.create_dataset("myarray1", myarray, compression="gzip", compression_opts=9)
しかし、これはかなり遅く、圧縮率は私たちが期待できる最高ではありません。
私も試しました
numpy.savez_compressed()
ただし、繰り返しになりますが、そのようなデータ(前述)には最適な圧縮アルゴリズムではない可能性があります。
このようなデータを使用して、numpy array
の圧縮率を向上させるために何を選択しますか?
(私はロスレスFLAC(当初はオーディオ用に設計された)のようなものについて考えましたが、そのようなアルゴリズムをnumpyデータに適用する簡単な方法はありますか?)
私が今していること:
import gzip
import numpy
f = gzip.GzipFile("my_array.npy.gz", "w")
numpy.save(file=f, arr=my_array)
f.close()
ノイズは非圧縮性です。したがって、ノイズを含むデータの一部は、何らかの方法で破棄しない限り(非可逆圧縮)、圧縮アルゴリズムに関係なく1:1の圧縮データになります。有効ビット数(ENOB)が16ビットに等しい24ビット/サンプルの場合、残りの24-16 = 8ビットのノイズにより、(ノイズのない)データであっても、最大のロスレス圧縮比が3:1に制限されます。 完全に圧縮可能です。不均一なノイズは、不均一な程度まで圧縮可能です。おそらく、ノイズの有効エントロピーを調べて、どれだけ圧縮可能かを判断する必要があります。
データの圧縮は、データのモデリングに基づいています(一部は冗長性を削除するためですが、一部はノイズから分離してノイズを破棄できるようにするためでもあります)。たとえば、データの帯域幅が10MHzに制限されていて、200MHzでサンプリングしていることがわかっている場合、FFTを実行して高周波数をゼロにし、低周波数のみの係数を保存できます(この例では10:1)。圧縮)。これに関連する「圧縮センシング」と呼ばれる分野全体があります。
多くの種類の合理的な連続データに適した実用的な提案:ノイズ除去->帯域幅制限->デルタ圧縮-> gzip(またはxzなど)。ノイズ除去は、帯域幅制限、または実行中の中央値のような非線形フィルターと同じである場合があります。帯域幅制限はFIR/IIRで実装できます。デルタ圧縮は、y [n] = x [n]-x [n-1]です。
[〜#〜] edit [〜#〜]イラスト:
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
圧縮を使用したHDF5ファイルの保存は、非常に迅速かつ効率的に行うことができます。すべて、圧縮アルゴリズムと、保存中、または読み取り中、またはその両方で高速にするかどうかに依存します。そして当然、上記で説明したように、データ自体についてです。 GZIPはその中間にある傾向がありますが、圧縮率は低くなります。 BZIP2は両側で低速ですが、比率は優れています。 BLOSCは、圧縮率が高く、両端で高速であることがわかったアルゴリズムの1つです。 BLOSCの欠点は、HDF5のすべての実装に実装されていないことです。したがって、プログラムは移植できない場合があります。常に、少なくともいくつかのテストを行って、ニーズに最適な構成を選択する必要があります。
まず、一般的なデータセットの場合、shuffle=True
のcreate_dataset
引数を使用すると、大まかに連続したデータセットで圧縮が大幅に向上します。 (連続データの場合)ビットの変化がゆっくりとなるように、圧縮するビットを非常に巧妙に再配置します。つまり、ビットをより適切に圧縮できます。私の経験では圧縮が少し遅くなりますが、私の経験では圧縮率を大幅に改善できます。これは不可不可逆なので、実際に入力したのと同じデータが出力されます。
精度をそれほど気にしない場合は、scaleoffset
引数を使用して、格納するビット数を制限することもできます。ただし、これは実際のサウンドとは異なるため、注意してください。特に、それはrelative精度ではなく、absolute精度です。たとえば、scaleoffset=8
を渡しても、データポイントが1e-8
より少ない場合は、ゼロが取得されます。もちろん、データを最大で1にスケールアウトし、100万分の1未満の違いが聞こえないと思われる場合は、scaleoffset=6
を渡して、多くの作業をせずに優れた圧縮を得ることができます。
しかし、特にオーディオに関しては、FLACを使いたいと思うのは当然だと思います。FLACの開発者は、圧縮と区別可能な詳細の保持とのバランスをとって、膨大な量の検討を重ねてきたからです。 scipyを使用してWAVに変換する 、および FLACに変換する を使用できます。
最適な圧縮(ある場合)を構成するものは、データの性質に大きく依存します。ロスのない圧縮が本当に必要な場合、多くの種類の測定データは事実上完全に非圧縮です。
Pytablesのドキュメントには、データ圧縮に関する多くの有用なガイドラインが含まれています。また、速度のトレードオフなどについても詳しく説明します。結局のところ、圧縮レベルを高くすると、時間の無駄になります。
http://pytables.github.io/usersguide/optimization.html
これはおそらくそれが得られるのと同じくらい良いことに注意してください。整数測定の場合、シャッフルフィルターと単純なZipタイプの圧縮の組み合わせは、通常、かなりうまく機能します。このフィルターは、最上位エンディアンバイトが通常0であり、オーバーフローを防ぐためにのみ含まれているという一般的な状況を非常に効率的に活用します。