Hayami Kaito
← Apps

データ圧縮の可視化

ランレングス・ハフマン符号・LZ77・LZW が文字列を縮めていく様子を 1 手ずつ見せます。ハフマン木や辞書ができていく様子と、方式ごとの圧縮率やエントロピーとの関係を確かめられます。

例

LZW の説明でよく使われる例です。辞書に登録した語句が、後半で繰り返し使われます。

出てきた文字列を辞書に登録しながら、辞書の番号で表します。GIF や昔の Unix の compress で使われました。

16 / 16辞書にある一番長い語句「OT」の番号 13 を 5 ビットで出力(最後)

  1. T
  2. O
  3. B
  4. E
  5. O
  6. R
  7. N
  8. O
  9. T
  10. T
  11. O
  12. B
  13. E
  14. O
  15. R
  16. T
  17. O
  18. B
  19. E
  20. O
  21. R
  22. N
  23. O
  24. T
  • 符号にした
  • 今回出力する語句
  • 辞書に足す次の文字

出力

番号のビット数は、そのとき辞書にある語句の数を区別できるだけの長さです。辞書が大きくなるにつれて増えます。

#語句番号ビット
1T53
2O33
3B03
4E14
5O34
6R44
7N24
8O34
9T54
10TO64
11BE84
12OR105
13TOB155
14EO95
15RN115
16OT135

ここまでで 16 個・66 ビット

辞書

最初の辞書は、入力に出てくる文字を文字コードの順に並べたものです(本来の LZW は 256 通りのバイトから始めます)。

番号語句
0B
1E
2N
3O
4R
5T
6TO
7OB
8BE
9EO
10OR
11RN
12NO
13OT出力した
14TT
15TOB
16BEO
17ORT
18TOBE
19EOR
20RNO

方式の比べ方

大きさは、元の文字列を UTF-8 で表したときとの比です。ハフマン符号と LZW は、復号に必要な符号表・最初の辞書を送る分の目安(項目の数 8 ビット、ハフマン符号は文字ごとに文字と符号の長さ 8 ビット、LZW は文字の並び)も足しています。

方式本体符号表・辞書合計元との比復号
元の文字列192—192100%
—
ランレングス368—368191.7%
✓ 元どおり
ハフマン符号5910416384.9%
✓ 元どおり
LZ77162—16284.4%
✓ 元どおり
LZW665612263.5%
✓ 元どおり

単位はビット。24 文字のエントロピーは 1 文字 2.424 ビットで、文字を 1 つずつ符号にする方式(ハフマン符号など)では本体を 59 ビットより小さくできません。LZ77 や LZW は繰り返し出てくる文字列をまとめて表すので、この下限より小さくなることがあります。

使い方

  • 例を選ぶか、圧縮する文字列(200 文字まで)を入力します。日本語や絵文字も使えます。
  • 「ランレングス」「ハフマン符号」「LZ77」「LZW」で方式を切り替えます。「再生」や「◀」「▶」で、1 つずつ符号にしていく様子を確かめられます。
  • LZ77 では、振り返る範囲(窓)と、1 回に一致させる最大の長さを変えられます。
  • 下の表で、4 つの方式の大きさと、元どおりに戻せることを確かめられます。
  • キーボードでは ← → で 1 コマ、Home / End で最初 / 最後に移ります(入力欄にカーソルがないとき)。

偏りを使う圧縮

ふつうの文字コードは、どの文字にも同じ長さ(英数字なら 8 ビット、日本語の UTF-8 なら 24 ビット)を使います。ハフマン符号は、よく出る文字ほど短い符号を割り当てて全体を短くします。重みの一番小さい 2 つの木をまとめることを繰り返して作った木は、どの符号も別の符号の頭の部分にならない(接頭符号)ので、区切りなしで並べても一意に戻せます。文字を 1 つずつ符号にする方式では、平均の長さをエントロピー(出現の偏りから決まる情報量)より短くできないことが知られており、ハフマン符号はその中で最も短い符号になります。

ランレングス圧縮は、同じ文字が続く「ラン」を回数と文字の組にします。しくみは単純ですが、同じ文字が続かないデータでは組の分だけかえって大きくなります。

繰り返しを使う圧縮

LZ77 は、少し前に出てきた文字列と同じところを「何文字前から何文字」で表します。振り返る範囲を窓と呼び、窓が大きいほど遠くの繰り返しを見つけられますが、位置を表すビット数が増えます。一致はこれから読む部分に重なってもよく、「aaaaaa」のような繰り返しも 1 つの出力で表せます。ZIP や gzip、PNG で使われる Deflate は、LZ77 の出力をさらにハフマン符号で縮めています。

LZW は、読んだ文字列を辞書に登録しながら、辞書の番号で表します。辞書は送らなくても、復号する側が同じ手順で作り直せます(このアプリでは最初の辞書だけは送る分を数えています)。長い文章ほど辞書が育ち、長い語句を 1 つの番号で表せるようになります。

このアプリのビット数は、しくみを比べるための単純な数え方です。実際の形式は、符号表の送り方や数の表し方を工夫して、さらに小さくしています。