前言:学习信息论与编码时想实现费诺编码,遇到点困难,上网搜索无果,却突然开窍,所以写一篇仅供各位朋友参考。
基于Python实现的费诺编码
(一)费诺编码原理及过程
1.原理
费诺码是按照累加概率(如不知参考下列例子就一目了然)尽可能相等的原则对信源符号进行分组,对于二元码,每次分为两组;对于n元码,则每次分为n组,并且给不同的组分配一个不同地码元符号。
注:本文章过程叙述、例子及具体实现代码为二元码
2.过程
若采用二元码,则编码步骤为:
(1)将信源符号按其出现的概率大小从大到小依次排列。
(2)将依次排列的信源符号分为两组,使两个组的概率之和尽可能近似相等,并将各组分别赋予一个二进制码元“0”和“1”。
(3)将每一组的信源符号再分为两组,使划分后的两个组的概率之和尽可能近似相等,并将各组分别赋予一个二进制码元“0”和“1”。
(4)如此重复,直至每个组只剩下一个信源符号为止。
Talk is cheap. Show me the code.
import math
def Group(probabilitySpace,encodeSpaceDictionary):
if(len(probabilitySpace)==1):#当分组只有一个时不应再继续分组和编码,退出
return
#通过累加概率尽可能相等原则找到分组最佳位置
groupProbability=1
findPosition=-1
for i in range(len(probabilitySpace)):
tempSum1=0
tempSum2=0
for j in range(i):
tempSum1=tempSum1+probabilitySpace[j]
for j in range(i,len(probabilitySpace)):
tempSum2=tempSum2+probabilitySpace[j]
if(abs(tempSum1-tempSum2)<groupProbability):
groupProbability=abs(tempSum1-tempSum2)
findPosition=i
#通过累加概率尽可能相等原则找到分组最佳位置
#编码
str0,str1="0","1"
for i in range(len(probabilitySpace)):
if(i<findPosition):
tempDictionaryElement={probabilitySpace[i]:encodeSpaceDictionary[probabilitySpace[i]]+str0}
encodeSpaceDictionary.update(tempDictionaryElement)
else:
tempDictionaryElement={probabilitySpace[i]:encodeSpaceDictionary[probabilitySpace[i]]+str1}
encodeSpaceDictionary.update(tempDictionaryElement)
#编码
#分组
leftGroup=[]
rightGroup=[]
for j in range(findPosition):
leftGroup.append(probabilitySpace[j])
for j in range(findPosition,len(probabilitySpace)):
rightGroup.append(probabilitySpace[j])
#分组
#递归分组编码
Group(leftGroup,encodeSpaceDictionary)
Group(rightGroup,encodeSpaceDictionary)
#递归分组编码
return(encodeSpaceDictionary)#返回编码空间
def Fano(probabilitySpace=[0.2,0.19,0.18,0.17,0.15,0.1,0.01]):
probabilitySpace.sort()
probabilitySpace.reverse()
encodeSpaceDictionary={}#编码空间
#初始化编码空间
for i in range(len(probabilitySpace)):
tempDictionaryElement={probabilitySpace[i]:""}
encodeSpaceDictionary.update(tempDictionaryElement)
#初始化编码空间
Result=Group(probabilitySpace,encodeSpaceDictionary)
i=1
for p in Result:
print("消息符号a{}对应码字为:{}".format(i,Result[p]))
i+=1
#求平均码长
averageL=0
listResult=list(Result)
for p in listResult:
averageL=averageL+len(Result[p])*p
print("平均码长为:{:.3}比特/符号".format(averageL))
#求平均码长
#求编码效率
H=0
for i in range(len(probabilitySpace)):
H=H+probabilitySpace[i]*math.log2(probabilitySpace[i])
H=-H
print("编码效率为:{:.3%}".format(H/averageL))
#求编码效率
return(Group(probabilitySpace,encodeSpaceDictionary))
def typeInFano():
while(True):
try:
mode=eval(input("是否输入概率空间?(否为默认概率空间)->({}:是 or {}:否):".format(1,2)))
if mode==1 or mode==2:
break
else:
print("!!!请按格式输入.")
except:print("!!!请按格式输入.")
if(mode==1):
print("!!!输入'.'结束")
i=1
typeIn=[]
while(True):
while(True):
try:
tempTypeIn=input("请输入第{}个参数:".format(i))
if(tempTypeIn=="."):
break
typeIn.append(eval(tempTypeIn))
i=i+1
except:
print("!!!请输入数字或'.'")
sum=0
for i in range(len(typeIn)):
sum=sum+typeIn[i]
if(sum!=1):
print("!!!概率空间和不为1请重新输入.")
i=1
else:
Fano(typeIn)
break
if(mode==2):
Fano()
if __name__=="__main__":
typeInFano()