単純なバイナリデータの効率的な圧縮


27

から2 n1の順序付けられた2進数を含むファイルがあります。02n1

0000000000
0000000001
0000000010
0000000011
0000000100
...
1111111111

7zはこのファイルを非常に効率的に圧縮しませんでした(n = 20の場合、22 MBは300 kBに圧縮されました)。

データの非常に単純な構造を認識し、ファイルを数バイトに圧縮できるアルゴリズムはありますか?また、CSや情報理論のどの分野がこのようなスマートアルゴリズムを研究しているかを知りたいです。「AI」は広すぎるため、より具体的なキーワードを提案してください。
対称性の概念はデータ圧縮で基本的な役割を果たすはずですが、検索クエリ「データ圧縮の対称性」と「データ圧縮の群論」は、驚くべきことにほとんど何も関連性を返しません。


11
コルモゴロフの複雑さを調べてください。これは、ある意味では最適な圧縮(追加の定数まで)です。残念ながら、コルモゴロフ複雑性は...計算ではありません
のYuval Filmus

12
なぜそのデータを圧縮する必要があるのですか?必要なときにいつでも再生することはできませんか?(@YuvalFilmusが言及したコルモゴロフの複雑さのアプローチと密接に関連しています。コルモゴロフの複雑さは、本質的に出力を生成する最短プログラムの長さです)。
デビッドリチャービー

7
20年前に高校でこのようなアルゴリズムを書きました。入力が与えられると、「数バイト」に圧縮されます(最適なシナリオでは約3,500,000:1)。ただし、データがこのようになることはめったにないため、このようなアルゴリズムを使用することは実用的ではありません。一般的な圧縮アルゴリズムは、単純なパターンではなく、複雑なパターンを処理する必要があります。誰でも線形データを保存するためのアルゴリズムを作成できますが、興味深いデータを保存することが課題です。
phyrfox

3
n = 20はどのように22MBを与えますか?4バイトの整数を使用すると4.2 MBが得られる
-njzk2

3
@JiKああ、わかった。これは、圧縮の最初の概念であり、単一ビットを表すために8ビットを使用しません。
njzk2

回答:


27

n

0
1
1
1
1
...

O(n)O(1)

nNn

DWの「オールオアナッシング」提案とは異なり、ランレングスエンコーディングを使用したデルタ圧縮は、低解像度オーディオなど、いくつかの単純な実世界の種類のコンテンツに対して実用的な圧縮率を実際に提供できます。(したがって、低品質、超低遅延、低電力のオーディオ圧縮に適しています。)


44

もちろん、アルゴリズムがあります。これが私のアルゴリズムです:

  1. 02n1nn

  2. そうでない場合は、1ビットを書き出してから、ファイルの7z圧縮を書き出します。

これは、その特定の構造のファイルに対して非常に効率的です。

要点は、データ圧縮に無料の昼食がないことです。1種類のファイルを適切に圧縮する圧縮アルゴリズムを構築できる場合がありますが、他の種類のファイルはさらに圧縮されます。ただし、圧縮するファイルの性質について事前に何かを知っている場合は、その特定の種類のファイルに対してアルゴリズムを最適化できます。

領域は「データ圧縮」です。タグを参照し、に関する教科書を読んでください。


5
コンプレッサーの仕事は、一般的なパターンを認識し、それらを活用することです。このパターンが一般的または不明瞭なわけではありません。したがって、なぜ悪用されないのかを尋ねるのは自然な質問です。トレードオフがあることを彼に伝えるか、パターンが完全な警戒である以外のすべてで失敗するアルゴリズムを彼に与えます。
-Mehrdad

17
確かに私には珍しいようです。これは、優れたコンプレッサーが探すパターンの種類と比較して、実際のデータでは非常にまれです。
アマロイ

17
@Mehrdadそれはこっけいな警官ではありません:それは全体のポイントです 単純に生成され、単純にチェックされるパターンXには、そのパターンを探して処理する圧縮アルゴリズムがあります。したがって、これは「そのようなXを扱う圧縮アルゴリズムはありますか?」という行に沿った質問に対する答えです。もちろん、常に少し複雑なパターンを探すアルゴリズムがあります。そして、無限よりも少し複雑なパターンを探すものもあります。あなたの反対は根拠がありません。
デビッドリチャービー

コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
ジル「SO-停止されて悪」

この原則の極端な応用は、任意のサイズのファイルまたはファイルのコレクションが固定の160ビットのデータに単純に表される(圧縮される)ビットトレントマグネットリンクです。もちろん、ハッシュの衝突が発生するリスクがあります。
-slebetman

17

BWT(Burrows–Wheeler変換)を使用するものはどれでも、かなりうまく圧縮できるはずです。

私の簡単なPythonテスト:

>>> import gzip
>>> import lzma
>>> import zlib
>>> import bz2
>>> import time
>>> dLen = 16
>>> inputData = '\n'.join('{:0{}b}'.format(x, dLen) for x in range(2**dLen))
>>> inputData[:100]
'0000000000000000\n0000000000000001\n0000000000000010\n0000000000000011\n0000000000000100\n000000000000010'
>>> inputData[-100:]
'111111111111010\n1111111111111011\n1111111111111100\n1111111111111101\n1111111111111110\n1111111111111111'
>>> def bwt(text):
    N = len(text)
    text2 = text * 2
    class K:
        def __init__(self, i):
            self.i = i
        def __lt__(a, b):
            i, j = a.i, b.i
            for k in range(N): # use `range()` in Python 3
                if text2[i+k] < text2[j+k]:
                    return True
                elif text2[i+k] > text2[j+k]:
                    return False
            return False # they're equal

    inorder = sorted(range(N), key=K)
    return "".join(text2[i+N-1] for i in inorder)

>>> class nothing:
    def compress(x):
        return x

>>> class bwt_c:
    def compress(x):
        return bwt(x.decode('latin_1')).encode('latin_1')

>>> for first in ('bwt_c', 'nothing', 'lzma', 'zlib', 'gzip', 'bz2'):
    fTime = -time.process_time()
    fOut = eval(first).compress(inputData)
    fTime += time.process_time()
    print(first, fTime)
    for second in ('nothing', 'lzma', 'zlib', 'gzip', 'bz2'):
        print(first, second, end=' ')
        sTime = -time.process_time()
        sOut = eval(second).compress(fOut)
        sTime += time.process_time()
        print(fTime + sTime, len(sOut))

bwt_c 53.76768319200005
bwt_c nothing 53.767727423000224 1114111
bwt_c lzma 53.83853460699993 2344
bwt_c zlib 53.7767307470001 5930
bwt_c gzip 53.782549449000044 4024
bwt_c bz2 54.15730512699997 237
nothing 6.357100005516259e-05
nothing nothing 0.0001084830000763759 1114111
nothing lzma 0.6671195740000258 27264
nothing zlib 0.05987233699988792 118206
nothing gzip 2.307255977000068 147743
nothing bz2 0.07741139000017938 187906
lzma 0.6767229399999906
lzma nothing 0.6767684639999061 27264
lzma lzma 0.6843232409999018 27324
lzma zlib 0.6774435929999072 27280
lzma gzip 0.6774431810001715 27292
lzma bz2 0.6821310499999527 27741
zlib 0.05984937799985346
zlib nothing 0.05989508399989063 118206
zlib lzma 0.09543156799986718 22800
zlib zlib 0.06264000899977873 24854
zlib gzip 0.0639041649999399 24611
zlib bz2 0.07275534999985211 21283
gzip 2.303239570000187
gzip nothing 2.303286251000145 147743
gzip lzma 2.309592880000082 1312
gzip zlib 2.3042639900002087 2088
gzip gzip 2.304663197000309 1996
gzip bz2 2.344431411000187 1670
bz2 0.07537686600016968
bz2 nothing 0.07542737000017041 187906
bz2 lzma 0.11371452700018381 22940
bz2 zlib 0.0785322910001014 24719
bz2 gzip 0.07945505000020603 24605
bz2 bz2 0.09332576600013454 27138

(ここの数字は「first_compressor second_compressor time_taken bytes_out」です)

ここから取られ BWT )

これはまだ「数バイトだけではありません」が、それでもgzipのみを使用するよりはるかに優れています。たとえば、16ビット入力の場合、BWT + bz2は1114111から237バイトになります。

残念ながら、BWTは非常に遅く、多くのアプリケーションにとってメモリを大量に消費します。特に、これはPythonの素朴な実装です。私のマシンでは、2 ** 20より前にRAMが不足しています。

Pypyを使用すると、2 ** 20の完全な入力を実行でき、BWTに続いてbz2を使用して2611バイトに圧縮しました。しかし、3分以上かかり、4GB以上のRAMを使用してピークに達しました...

また、残念ながら、このアプローチはまだO(2 ^ n)出力スペースであり、少なくとも曲線近似1..20からは表示されます。


次のようにして削除できますevalfor first in (bwt_c, nothing, lzma, zlib, gzip, bz2):およびfOut = first.compress(inputData)
カスペルド

@kasperd-その場合の名前の印刷方法は?個人的には、名前と参照の同期を維持しようとするよりも、evalを実行する方が簡単です(エラーが発生しにくくなります)。
TLW

5
最初にbwt、次にbz2がこの極度の圧縮を行います。これは非常に奇妙な動作であり、おそらくこの正確なパターンによるものです。あなたはBWTをやっていることに注意(BZ2はBWTに基づいています)がusallyになり悪化した圧縮。また、今日のbwtは通常、4 times block sizeメモリ(たとえば、このために最大4MB)および>10 MB/s(多くのアプリケーションで非常に使用可能な(このようなbwtライブラリ/圧縮アルゴリズムの作成者です)の速度で)実行されます。gzipでさえ非常に良い圧縮可能な結果を​​生成することに注意してください。共有してくれてありがとう、bwtを2回使用することについての研究を知りません。
クリストフ

3
@Christoph-bz2はBWTに基づいていることを知っています...私は実際に「ちょうどbz2を使用する」という効果に対する答えを書き始めましたが、予想したほど圧縮されなかったことがわかりました'そして、自分のBWTの方が良いかどうかを確認することにしました。出力にコンプレッサーが必要だったのは、「別のコンプレッサーを試して何が起こるか見てみよう」ということだけでした。
TLW

1
@Christoph-もう一度見てみました。このデータの2 bwtsは、RLEエンコーディングに非常に適したものを生成します。同様に、16ビット入力で0、1、2、...ネストされたBWTに必要なRLEペアの数をカウントすると、622591 1081343 83 ...-
TLW

10

PNGエンコードはまさにあなたが望むことをします。極端に組織化されたデータだけでなく、実際のデータでも機能します。

PNGでは、各行はフィルターでエンコードされ、そのうち4つが指定されます。これらの1つは、「このピクセルをその値とその上のピクセルの値の差としてエンコードする」です。フィルタリング後、データはDEFLATEを使用して圧縮されます。

このフィルタリングは、leftaroundaboutの回答で言及されたデルタエンコーディングの特定の例です。ただし、Run Length Encodingで追跡する代わりに、より強力なDEFLATEアルゴリズムで追跡します。同じ目標を達成します。望ましい圧縮率を提供しながら、DEFLATEのみがより多くの種類の入力を処理します。

単純なfilter + DEFLATEがあまり効果的ではない科学データでよく使用される別のツールは、RICEエンコーディングです。RICEでは、値のブロックを取得して、最初に最上位ビットをすべて出力し、次に最上位から2番目のビットをすべて出力し、最下位ビットまで出力します。次に、結果を圧縮します。PNGスタイルのフィルター処理ほど効果的ではないデータ(データはPNGフィルター処理に最適であるため)に対しては、多くの科学データに対しては良い結果をもたらす傾向があります。多くの科学データでは、最上位ビットはゆっくりと変化する傾向がありますが、最下位ビットはほとんどランダムです。これは、高度にエントロピーなデータから高度に予測可能なデータを区別します。

0000000000       00000  most significant bits
0000000001       00000
0000000010  =>   00000
0000000011       00000
0000000100       00000
                 00000
                 00000
                 00001
                 00110
                 01010 least significant bits

5

特定の構造を検索する実用的なアルゴリズムは、その中にハードコーディングされた構造だけに制限されます。この特定のシーケンスを認識するために7zにパッチを当てることができますが、この特定の構造は実際にどのくらいの頻度で発生しますか?この入力の入力をチェックするのに要する時間を保証するのに十分ではありません。

実用性は別として、与えられた出力を生成する最短のプログラムを構築しようとするアルゴリズムとして完璧なコンプレッサーを考えることができます。言うまでもなく、これを行う実用的な方法はありません。可能性のあるすべてのプログラムの総当たり攻撃を試みて、それらが目的の出力を生成したかどうかを確認しても(完全に正気でないアイデアではありません)、停止の問題が発生します。このプログラムが確実に目的の出力を生成できないかどうかを知る前に、実行ステップの

このようなブルー​​トフォースアプローチの検索ツリーは、プログラムの長さとともに指数関数的に成長し、最も単純なプログラム(5〜7命令の長さのようなもの)以外のすべてに対して実用的ではありません。


n

1
nnn+1n1

まあ、Mathematicaのようなツールをするための関数を見つける多くの ...シーケンス
ラファエル

3

圧縮率は、ターゲットとする圧縮解除プログラムに完全に依存します。圧縮解除プログラムが、数字ごとの4バイトよりもコンパクトに連続した4バイトの数字をデコードできない場合、SOLです。

連番のエンコードを可能にするさまざまなものがあります。たとえば、差分エンコーディング。一度にnバイトを取得し、ビットの差またはxorを取得して、結果を圧縮します。これにより、すべてのバイトカウントを試行する4つのオプションがここに追加されますa'[i] = a[i]。違いa'[i] = a[i-1]-a[i]; 逆違いa'[i] = a[i]-a[i-1]; およびxor a'[i] = a[i]^a[i-1]。つまり、2ビットを追加してメソッドを選択し、4つのオプションのうち3つに対してバイトカウントを選択します。

ただし、すべてのデータが固定長レコードのシーケンスではありません。差分エンコーディングは、それに対して意味がありません(圧縮機が、少しのデータに対して機能することを経験的に証明できる場合を除く)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.