ハフマン符号化(完)

ハフマン符号化できた

前に断念していた、ハフマン符号化 - なんというていたらくが完成。
まぁ、これは明日提出の講義の宿題なんだけどもw


別に言語はなんでもよかったんだけど、Pythonの練習がてら書いてみた。
少しだけどPythonさんとの距離が縮まった気がする。

課題

適当なテキストファイル(事象数25個以上、データ量500事象以上程度)をハフマン符号化し、固定長符号による符号化と比較した圧縮率を求めよ。

今回はOfficial Google Blog: New search ad formatsから文章のみコピペして、
全て大文字に置換 && 改行、スペース、コンマ、ピリオドを除いてハフマン符号化してみた。


圧縮まではできてません。
時間あればやってみたい。

回答ソース
# coding: UTF-8
# Python --version: 2.6.5
#

from heapq import *
from math import *
import re

class Node:
    def __init__(self, code, count = 0, left = None, right = None):
        self.code = code
        self.count = count
        self.left = left
        self.right = right

    def __cmp__(x, y):
        return x.count - y.count


#ハフマン木を作成
def make_tree(sym_table):
    q = []  #ヒープ
    for x in sym_table:
        if x.count > 0: heappush(q, x)
    while True:
        n1 = heappop(q)
        if len(q) == 0:
            if n1.code is not None: #奇数だった場合
                for x in sym_table:
                    if x.count == 0: return Node(None, 0, n1, x)
            return n1
        n2 = heappop(q)
        heappush(q, (Node(None, n1.count + n2.count, n1, n2)))


#符号化
def make_code(s, node):
    if node.code:
        if not s:
            codes[node.code] = "0"
        else:
            codes[node.code] = s
    else:
        make_code(s+"0", node.left)
        make_code(s+"1", node.right)


#ハフマン符号化
def huffman(words, wordsCount):
    #ノードを生成
    sym_table = [Node(c, n) for (c, n) in wordsCount.items()]

    root = make_tree(sym_table)
    make_code("", root)
    print wordsCount
    print codes

    #ハフマン符号長
    huffmanLen = 0
    for (x, y) in codes.items():
        huffmanLen += wordsCount[x]*len(y)

    print "%s: %f %s" % (u"ハフマン符号化", float(huffmanLen), "bit")

    #固定符号長
    fixedLen = (ceil(log(len(wordsCount),2)))*len(words)
    print "%s: %f %s" % (u"固定長符号化", float(fixedLen), "bit")

    #圧縮率
    print "------------------------------------------------"
    print "%s: %f %s" % (u"圧縮率", float(huffmanLen)/float(fixedLen)*100, "%")



#ファイルを開いて文字列を分解
f = open("googleBlog.txt", 'r')
filter = re.compile(r'[\s*\,\.]')
text = filter.sub("", f.read().upper())
print text
words =[]
for x in text:
    words.append(x)


#単語の出現回数をカウントしソート
wordsCount = {}
for word in words:
    if word in wordsCount:
        wordsCount[word] += 1
    else:
        wordsCount[word] = 1


codes = {}
huffman(words, wordsCount)


こんな感じ?
まだまだ無駄な書き方がいっぱいで萎える。
きれいに書けるようになりたいなー