Python实现最大熵模型

最大熵模型

这里先贴上书上的算法

算法

 

 

 

这里写图片描述

这里写图片描述

我们的f(x,y)f(x,y)如下所示,根据其定义可知f#(x,y)f#(x,y)必然为常数,因此采用公式6.34更新迭代即可 
f(x,y)={10(x,y)∈ train setelse
f(x,y)={1(x,y)∈ train set0else

还要注意一下,公式6.34中的M值可以理解成学习速率,最好直接设置成一个比较小的值,防止指数爆炸。

数据集

数据集和朴素贝叶斯那个博文用的是同样的数据集。 
数据地址:https://github.com/WenDesi/lihang_book_algorithm/blob/master/data/train.csv

特征

将这个图作为特征,但需要先经过二值化处理 
还有一点,与其他分类器不同的是,最大熵模型中的f(x,y)f(x,y)中的x是单独的一个特征,不是一个n维特征向量,而经过二值化处理过的特征都是0与1,因此我们需要对每个维度特征加一个区分标签 
如X=(x0,x1,x2,...)X=(x0,x1,x2,...)变为X=(0_x0,1_x1,2_x2,...)

实现代码

# encoding: utf-8
'''
Created on 2017-8-7
根据李航<<统计学习方法>>实现
'''
 
from collections import defaultdict
import math
 
class MaxEnt(object):
    def __init__(self):
        self.feats = defaultdict(int)
        self.trainset = []
        self.labels = set()  
      
    def load_data(self, file):
        for line in open(file):
            fields = line.strip().split()
            
            # 数据共3列。第一列为标签,二三列为特征
            if len(fields) < 2: continue
            label = fields[0]
            self.labels.add(label)
            for f in set(fields[1:]):
                # (label,f) tuple is feature 
                self.feats[(label, f)] += 1
            self.trainset.append(fields)
            
    def _initparams(self):
        self.size = len(self.trainset)
        
        self.M = max([len(record) - 1 for record in self.trainset]) # P91中的M
        
        # 计算P82页最下面的期望
        self.ep_ = [0.0] * len(self.feats)  # 保存期望值
        for i, f in enumerate(self.feats):
            self.ep_[i] = float(self.feats[f]) / float(self.size)
            # each feature function correspond to id
            self.feats[f] = i
 
        # 初始化需要学习的参数的值
        self.w = [0.0] * len(self.feats)
        self.lastw = self.w
        
        
    def probwgt(self, features, label):
        '''
                        辅助函数:计算P85中的公式6.22中的分子
        '''
        wgt = 0.0
        for f in features:
            print (self.feats[(label, f)])
            if (label, f)in self.feats:
                wgt += self.w[self.feats[(label, f)]]
        return math.exp(wgt)
 
 
    
    def calprob(self, features):
        '''
                        计算P85中的公式6.22的条件概率P(y|x)
        '''
        wgts = [(self.probwgt(features, label), label) for label in self.labels]
        Z = sum([ w for w, label in wgts])
        prob = [ (w / Z, label) for w, label in wgts]
        return prob 
    
                       
    def Ep(self):
        '''
                        计算P83页最上面的期望
        '''
        eps = [0.0] * len(self.feats)
        for record in self.trainset:
            features = record[1:]
            
            # 计算 p(y|x)
            probs = self.calprob(features)
            for f in features:
                for prob, label in probs:
                    if (label, f) in self.feats:     # only focus on features from training data.
                        idx = self.feats[(label, f)]
                        eps[idx] += prob * (1.0 / self.size) # 计算期望 sum(P(x) * P(y|x) * f(x,y))。 其中P(x) = 1 / N
        return eps
    
    def _convergence(self, lastw, w):
        for w1, w2 in zip(lastw, w):
            if abs(w1 - w2) >= 0.01:
                return False
        return True
                
    def train(self, max_iter=1000):
        self._initparams()
        for i in range(max_iter):
            print ('iter %d ...' % (i + 1))
            self.ep = self.Ep()           
            self.lastw = self.w[:]  
            for i, w in enumerate(self.w):
                delta = 1.0 / self.M * math.log(self.ep_[i] / self.ep[i])   # P91 公式6.34
                self.w[i] += delta
            
            # 是否满足收敛条件    
            if self._convergence(self.lastw, self.w):
                break
 
            
    def predict(self, input):
        features = input.strip().split()
        prob = self.calprob(features)
        prob.sort(reverse=True)
        return prob 
 
if __name__ == "__main__":
    maxent = MaxEnt()
    maxent.load_data("input.data")
    maxent.train(100)
    prob = maxent.predict("Sunny  Sad")
    print (prob)
 


 

你可能感兴趣的:(python,机器学习)