压缩率

表示数据压缩效果的指标。日语中多指"从原始大小减少了多少"的比例,而英语的 compression ratio 指"原始大小与压缩后大小之比",因此同一个词,数值的含义也会改变。

压缩率 (compression ratio) 是表示数据压缩效率的指标。设原始数据大小为 D、压缩后的大小为 C,日语中说"压缩率 75%"时,有一种用法指的是 (1 - C/D) × 100%,本文也按这个意思使用。一个 100KB 的文本文件被压缩到 25KB,压缩率就是 75%。压缩率越高,就能用更少的存储或网络带宽来处理数据。

稍微麻烦的是,这个词有两种用法。英语的 compression ratio 指 D/C 之比,同一个例子会被表述为"4:1"或"4 倍"。而 (1 - C/D) 在英语中则被区分称作 space savings (削减率)。在日语的文章和设置界面上,两者都混在"压缩率"这一个说法里,因此"压缩率 25%"这样的写法有时意思是"变成了四分之一 (减少了 75%)"。只看数值来比较会把位数搞错,所以在做判断之前先确认"是减少的比例,还是大小之比"才可靠。压缩工具的设置里的"压缩级别"又是另外一根轴,指的是要不要花更多时间压得更小的程度。

文本数据相比图片和视频,压缩率倾向于更高。这是因为自然语言的文本中包含大量冗余:字符出现频率的偏差 (英语中"e"最频繁)、单词的重复、固定的说法等等。日语的场合,UTF-8 中汉字和假名每个字符为 3 字节,因此原始的字节数会膨胀,但同样的 3 字节序列会反复出现,压缩也就容易见效,压缩后的大小并不一定比英语差很多。左右效果的与其说是语言,不如说是内容,同样的词句和固定的格式重复到什么程度,几乎就直接反映为结果。需要数值的场合,用实际要分发的数据去测量是唯一可靠的方法。

在 Web 领域,HTTP 响应的 gzip、Brotli 压缩能大幅削减文本数据的传输量。HTML、CSS、JavaScript 全都是文本数据,是压缩收益很大的文件格式。Brotli 倾向于压得比 gzip 更小,主流浏览器也都已支持。不过差距的大小会随对象数据和压缩级别而变,所以究竟能缩多少,只能用自己要分发的文件把两者都试一遍再比较。一个 10KB 的 HTML 文件变成 2.5KB,传输的字节数就是四分之一。传输时的压缩通过 Content-Encoding 头来告知,由收到的浏览器一侧展开,因此这与把保存着的文件本身变小的作业是两回事。

文本压缩的算法大致分为两类。哈夫曼编码是根据字符出现频率分配可变长度比特序列的方式,越是频繁出现的字符就用越短的比特序列来表示。LZ77、LZ78 系的算法则检测文本中的重复模式,用"之前出现过的位置和长度"来引用。gzip 使用的是把两者结合起来的 DEFLATE 算法。

字符数与压缩率的关系有着有趣的性质。即使是字符数相同的文本,压缩率也会因内容而大不相同。"啊啊啊啊啊啊啊啊啊啊" (同一字符的重复) 会得到极高的压缩率,而随机的字符串则几乎无法压缩。这与信息论中熵 (信息量) 的概念直接相连,冗余度越高的文本,压缩率越高。

在实务中,压缩率直接关系到存储容量与网络带宽的估算。日志文件和聊天记录会把同样的格式一直重复下去,因此在文本之中也属于压缩特别容易见效的一类。反过来,分辨出"压缩了也是白费"的场合同样重要。JPEG、PNG、视频、zip 等已经压缩过了,再压一次几乎缩不了,甚至还会稍微变大。几个字节这样的短数据也一样,会按压缩格式本身所带的头部的份量膨胀 (把 2 个字节的字符串做成 gzip 格式,会变成 20 多个字节)。见效的是"长、重复多、且尚未被压缩"的数据,长篇文本的分发很好地满足这些条件。

分享这篇文章