信息论概论,数据压缩,编码
数据压缩:信息的有效编码
在许多压缩方法中,输入符号被映射到码字(bit sequences)。该码字集称为编码(code)。如果所有码字的长度相等,则称其为定长的编码;否则,为可变长度的编码。最重要的代码是前缀编码,即其中没有编码字是另一个编码字的前缀的编码。
如果将码字映射到二进制树(0对应于左边缘,1对应于右边缘),则可以将前缀编码中的每个符号与唯一的叶子相关联。值得注意的是,压缩(编码的)序列可以通过重复下降到树上直到到达叶子而被解码以产生输入。
信息论
信息理论是对信息以及如何处理和传达信息的研究。人们通常将香农于1948年10月发表于《贝尔系统技术学报》上的论文《A Mathematical Theory of Communication》(通信的数学理论)作为现代信息论研究的开端。
本文主要对信息沟通方面进行理论与现实情况下的探讨,并基于
Introduction to Information Theory, Data Compression, Coding Mehdi Ibm Brahim, Laura Minkova April 15, 2018
一文的理论成果进行相应的总结概括,方便一起学习信息论的小白同学一起进步,也方便我日后查找积累。理论与现实情况两者之间的最大区别在于,在现实生活中,经常会出现噪音,干扰到信息的传输方式,出于概论学习与研究我们考虑不存在噪声的通信系统。
香农的理论
克劳德·香农(Claude Shannon)开发了描述通讯系统基本方面的数学理论。它涉及利用概率论建立和研究数学模型。香农假定对于每一个可能的输入语句,都有一个对应的概率
p
i
p_i
pi,
p
i
p_i
pi的和为1,这些我们会在接下来的熵内容中进行介绍。
香农最关注的问题是怎样进行信息传输而不是什么是信息传输。但是他的确也指出,在压缩数据时的效率同样取决于输入的内容。话虽如此,它却依旧认为这些无关紧要(’’…these semantic aspects of communication are irrelevant to the engineering problem")。
压缩比率C定义为
C
=
n
u
m
b
e
r
o
f
s
y
m
b
o
l
s
i
n
o
u
t
p
u
t
n
u
m
b
e
r
o
f
s
y
m
b
o
l
s
i
n
i
n
p
u
t
C = \frac{number of symbols in output}{number of symbols in input}
C=numberofsymbolsininputnumberofsymbolsinoutput
为了确定输出序列的预期长度,Shannon考虑了所有可能的输入.他假设可能需要压缩的每个输入序列都具有给定的概率pi,其中pi的总和为1。如果给第i个输入提供了一些长度为li位的编码,则输出位序列的预期长度w为
w
=
∑
i
n
p
i
∗
l
i
w = \sum_{i}^{n}{p_i*l_i}
w=i∑npi∗li
二叉树被证明在表示信息编码中非常有用。该树的内部节点将没有值,但是每个叶将代表一个可能的输入。每个左边缘用0表示,每个右边缘用1表示。
也就是AABA 000,BAAA 001,ABAB 01,ABAA 1
Entropy(熵)
在信息论中,熵是衡量随机变量中信息量的量。因此,熵为任何可能编码的效率提供了理论上的限制(有时是无法优化到下限的)。
二进制熵定义如下:
ε
=
∑
i
n
p
i
log
2
1
p
i
\varepsilon = \sum_{i}^{n}{p_i\log_2{\frac{1}{p_i}}}
ε=i∑npilog2pi1
p
i
p_i
pi是不同输入序列的概率。
香农面临三个问题:
- 1 找到一个使预期长度最小的二叉树(David Huffman解决)
- 2 证明 E ≤ m i n ∑ i p i l i E≤min\sum_{i}{p_il_i} E≤min∑ipili即最短预期长度均大于Entropy
- 3 对于某些二叉树,证明 E ≤ m i n ∑ i p i l i + 1 E≤min\sum_{i}{p_il_i}+1 E≤min∑ipili+1
我们将首先证明
E
≤
m
i
n
∑
i
p
i
l
i
E≤min\sum_{i}{p_il_i}
E≤min∑ipili:
证明如下:
依据卡夫不等式:
∑
1
2
l
i
≤
1
\sum\frac{1}{2^{l_i}}\leq1
∑2li1≤1
它对所有二叉树均有效。
依据泰勒展开式易知
l
o
g
e
x
≤
x
−
1
log_{e}{x}\leq{x-1}
logex≤x−1
∑
i
p
i
l
i
=
∑
i
p
i
log
2
2
l
i
=
∑
i
p
i
log
2
2
l
i
p
i
1
p
i
=
∑
i
p
i
log
2
1
p
i
+
∑
i
p
i
log
2
(
p
i
2
l
i
)
=
ε
−
(
log
2
e
)
∑
i
p
i
log
e
1
p
i
2
l
i
≥
ε
−
(
log
2
e
)
∑
i
p
i
(
1
p
i
2
l
i
−
1
)
=
ε
\begin{aligned} \sum_{i}{p_il_i}&=\sum_{i}{p_i\log_{2}{2^{l_i}}}\\ &=\sum_{i}{p_i\log_{2}{2^{l_i}p_i\frac{1}{p_i}}}\\ &=\sum_{i}{p_i\log_{2}{\frac{1}{p_i}}}+\sum_{i}{p_i\log_{2}{({p_i}2^{l_i})}}\\ &=\varepsilon-(\log_{2}{e})\sum_{i}{p_i\log_{e}{\frac{1}{p_i2^{l_i}}}}\\ &\geq\varepsilon-(\log_{2}{e})\sum_{i}{p_i(\frac{1}{p_i2^{l_i}}-1)}\\ &=\varepsilon \end{aligned}
i∑pili=i∑pilog22li=i∑pilog22lipipi1=i∑pilog2pi1+i∑pilog2(pi2li)=ε−(log2e)i∑pilogepi2li1≥ε−(log2e)i∑pi(pi2li1−1)=ε
我们已经成功证明结论2,现在我们继续证明结论3
令
l
i
=
[
log
2
1
p
i
]
则
∑
i
1
2
l
i
≤
∑
i
1
2
log
2
1
p
i
≤
∑
p
i
≤
1
令l_i=[\log_{2}{\frac{1}{p_i}}]\\ 则\sum_{i}\frac{1}{2^{l_i}}\leq\sum_{i}\frac{1}{2^{\log_{2}{\frac{1}{p_i}}}}\leq\sum{p_i}\leq1
令li=[log2pi1]则i∑2li1≤i∑2log2pi11≤∑pi≤1
因此,依据卡夫的不等式,通过将长度li从小到大排序,并将li的叶子从左到右分配给二叉树中的叶子,可以找到具有给定li的编码。此编码称为Shannon-Fano code。
进而:
∑
i
p
i
l
i
≤
∑
i
p
i
(
1
−
log
2
p
i
)
=
ε
+
1
\sum_{i}{p_il_i}\leq\sum_{i}{p_i(1-\log_{2}{p_i}})=\varepsilon+1
i∑pili≤i∑pi(1−log2pi)=ε+1
结论3证毕。
例题:一串二进制文件,每个字节1出现概率为三分之一,其余为0。
问:二进制文件的熵
熵的求解代码:python
from scipy.special import comb
import math
def pi(k, n):
return math.pow(1 / 3, k) * math.pow(2 / 3, n - k)
def fun(n):
frst = 0
for i in range(1, n + 1):
frst = frst + pi(i, n) * comb(n, i) * math.log(1 / pi(i, n), 2)
return frst
实践压缩的问题
在实践中,我们在压缩时压缩成不同的符号,在接收方面存在着分离这些符号的问题。在一堆压缩后的字符中,我们如何去将他们分离开来呢?事实上,当我们发送一串压缩后的编码字符串,即一些“编码组”的串联,接收方可能无法正确对该字符串进行划分,来对每个字符串进行正确的解码。
Example
假设我们想发一串数字,如18 23,他们的标准二进制位10010和10111,那么如果我们发送以穿1001010111,意义是不大的。他们从何处开始又从何处结束?我们无法判断。于是我们考虑到,二进制数总是以1开头的,因而我们给他们加前缀,比如00,并在接下来接上代码的字节长,比如5(101),那么这串数字可以理解为(00101)10010(00101)10111。抑或是,我们使用前缀代码,比如我们连续5个0、或是更多作为前缀编码,这个编码出现的概率极低,那么可以表示为(00000)10010(00000)10111,然而这种做法显然是低效、且极为不方便的。
解决方案
固定编码
固定宽度编码,例如以每个字符标准的8位编码,提供了另一种解决方案,具有极大的提升空间。一个关于这种改进最著名的例子是(可变宽度)前缀编码。码字将一个位序列分配给一个符号。编码是一组编码集,我们将一段编码构造成一个TRIE,每个前缀有其特殊符号,便很好的解决了分割编码的问题。
TRIES
TRIE(发音为“ try”)是一种基于树的数据结构以支持快速模式匹配的存储字符串方式。TRIE的主要应用是信息检索,所以显然,名称“ trie”来自“ retrieval”一词。在二进TRIE种,每个边沿代表一个码字中的一个比特,左边孩子的边缘代表“0”,右边孩子的边缘
代表“ 1”。每个叶子都与一个特定字符相关联。
trie树的使用为我们编码器和解码器开发提供了策略。可以先搜索一个字符,记录路径时回归根节点。
解码其实并不需要trie,它只需要执行从叶子节点回溯到根节点的过程,但通常为了效率我们一般将trie与编码结果一起发送。
前缀编码
前缀编码需要一个关于前缀的树,这个树用一些特殊方式来记录不同的前缀符号,在加密时或是用字母表或是树的父节点来完成加密。只要有了这棵关于前缀的树,任何人都可以轻松地完成编码解码。这里简单谈一下。
定义
前缀编码是一种编码系统,他们由编码前缀部分进行区分。
例子
某个trie的字符为a,b,c,d,e,每个字符有个前缀,我们不妨假设前缀为P:
P = a:00,b:01,c:10,d:110,e:111.
我们清楚地看到P是有效的前缀代码,因为P种没有哪个二进制序列是另一个的前缀。
在这里,abbba被翻译成0001010100,这串字符根据P可以轻松翻译出abbba,换句话说,解决了分割问题。
哈夫曼树
霍夫曼树是将 ∑ i p i l i \sum_{i}{p_il_i} ∑ipili最小化的二叉树,其中 p i p_i pi是叶子i的权重, l i l_i li是从叶子i到根的距离。它具有以下属性:
- p i p_i pi值最小的两个输入距根最远。
- 每个内部节点都有2个子节点。
- p i p_i pi值最小的两个输入可以安全地成为同级。
- 重要的是要注意,哈夫曼树不是唯一的!
Hu-Tucker算法是一种贪婪算法,旨在在给定一组输入及其pi的情况下输出霍夫曼树。它具有时间复杂度O(nlogn),出于本文主要介绍的目的,这里只简单介绍,有兴趣的朋友可以自行搜索哈夫曼有关知识技术。
- 设置:
将PQ设为一个二进制堆,其中包含对 ( i , p i ) (i,p_i) (i,pi),其对根附近的密钥 p i pi pi最小。假设有n个叶子,我们可以在总大小为2n-1的数组中保留n-1个间隔节点。让我们使用left [i]和right [i]表示节点i的子代。节点1是根。
伪代码如下:
1 MAKENULL(PQ)
2 for i = n to 2n−1 do
3 left[i]=right[i]= nil;
4 INSERT((i,pi),PQ);
5 for i = n down to 1 do
6 (a,pa) = DELETEMIN(PQ);
7 (b,pb) = DELETEMIN(PQ);
8 left[i]= a;
9 right[i]= b;
10 INSERT((i,(pa + pb)),PQ);
- 哈夫曼编码的例子:
现在,我们将展示不同的编码方法,并比较它们与Shannon的下限的比较。
假设我们的输入是
x
1
,
x
2
,
.
.
.
,
x
n
x_1,x_2,...,x_n
x1,x2,...,xn,其中
x
i
x_i
xi是[1,2,3]中的等概率随机元素。
因此,存在
3
n
3^n
3n个同样可能的长度为n的输入序列。
令
ε
=
log
2
3
n
=
n
log
2
3
=
1.57
n
\varepsilon = \log_{2}{3^n} =n\log_{2}{3} = 1.57n
ε=log23n=nlog23=1.57n
- 固定宽度长度
我们使用固定宽度代码在每个输入符号中使用两位: 1 → 01 , 2 → 10 , 3 → 11 1→01,2→10,3→11 1→01,2→10,3→11
因此输出的长度为2n,这不是最佳的,有更小的预期输出长度的空间。 - 哈夫曼树法:
考虑霍夫曼代码,其中使用霍夫曼树前缀编码逐个符号对符号进行编码:
1 → 0 , 2 → 10 , 3 → 11 1→0,2→10,3→11 1→0,2→10,3→11.
预期长度为 ∑ i p i l i = 1 3 ( 1 ) + 1 3 ( 2 ) + 1 3 ( 3 ) = 5 3 \sum_{i}{p_il_i}=\frac{1}{3}(1)+\frac{1}{3}(2)+\frac{1}{3}(3)=\frac{5}{3} ∑ipili=31(1)+31(2)+31(3)=35
因此,预期输出长度为 5 3 n \frac{5}{3}n 35n,远大于E≈1.57n。
现在,让我们将固定长度d: d的每组是由霍夫曼码编码的输入符号
预期的输出长度(以位数为单位)
将是一组霍夫曼树代码的预期长度的 n d 倍 \frac{n}{d}倍 dn倍
我们知道 w ≤ 1 + log 2 3 d w\leq1+\log_{2}{3^d} w≤1+log23d
所以总长 w ≤ n d [ log 2 3 d ] ≤ n d [ 1 + d log 2 3 ] = n ( log 2 3 + 1 d ) w\leq\frac{n}{d}[\log_{2}{3^d}]\leq\frac{n}{d}[1+d\log_{2}{3}]=n(\log_{2}{3}+\frac{1}{d}) w≤dn[log23d]≤dn[1+dlog23]=n(log23+d1)
最后,通过选择足够大的d,我们可以任意接近E。
但是,我们不能将d设置得太大,因为计算霍夫曼代码将需要太多空间
因为霍夫曼树上有 3 d 3^d 3d叶子。
总结
希望上文的论述,能够帮助你解决相应的数据压缩的编码解码问题,欢迎大家关注收藏。
相关文献
[1] Charles E. Leiserson, Thomas H. Cormen, and Ronald L. Rivest. Introduction to Algorithms. Cambridge, MA, 2009.
[2] Claude E. Shannon. A mathematical theory of communication. The Bell System Technical Journal, 1948.
[3] Inrene Woo Adel Magra, Emma Goune. Information theory. http://luc.devroye.org/Magra-Goune-Woo–Shannon+ InformationTheory-LectureNotes-McGillUniversity-2017.pdf, March 2017. Accessed on 2018-03-20.
[4] George Markowsky. Information theory. https://www. [5]britannica.com/science/information-theory, June 2017. Accessed on 2018-03-11.
Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest.
Introduction to Algorithms. 2009. Cambridge, MA.
[6]Claude E. Shannon. A mathematical theory of communication. The
Bell System Technical Journal, 27:379–423, 623–656, 1948.
[7]Joy A. Thomas and Thomas M. Cover. Elements of Information Theory.
Wiley Series, 2nd edition, 2006. New York.