机器学习—最大熵模型_改进迭代尺度法IIS_python实现

代码及数据集下载Max Entropy

最大熵原理

最大熵原理是概率学习模型的一个准则。最大熵原理认为,学习概率模型时,在所有可能的概率模型中,上最大的模型是最好的模型,保留了最大的不确定性,从投资角度讲就是风险最小,将鸡蛋放在多个篮子里。通常用约束条件来确定概率模型的集合,因此,最大熵原理可以表述为在满足约束条件的模型集合中选取熵最大的模型。
假设离散随机变量X的概率分布为P(X),则其熵为

H(P)=xP(x)logP(x)

特征函数

f(x,y) 描述输入x与输出y之间的某一个事实。

f(x,y)={1,xy0,                   

这里写图片描述
通常实现时将一个样本 x=[x1,x2,x3] 拆分为 f(x1,y),f(x2,y),f(x3,y)


最大熵模型

最大熵模型是利用最大熵原理得到分类模型。
对于给定数据集

T={(x1,y1),(x2,y2),...,(xN,yN)}

根据训练数据集,可以确定联合分布 P(X,Y) 的经验分布,与边缘分布 P(X) 的经验分布,分别表示如下
P~(X=x,Y=y)=v(X=x,Y=y)NP~(X=x)=v(X=x)N

v(X=x,Y=y) 表示在样本中出现的次数。

约束条件

约束条件是指根据给出的样本数据,确定的满足样本数据的约束。在约束下利用最大熵原理确定分类模型。在最大熵模型中,对于任意一个特征函数 f ,记 EP~(f) 表示 f 在训练数据 T 上关于 P~(x,y) 的数学期望, EP(f) 表示 f 在模型上关于 P(y|x) 的数学期望。

EP~(f)=x,yP~(x,y)f(x,y)EP(f)=x,yP~(x)P(y|x)f(x,y)

根据训练数据的信息,约束为这两个期望相等。
EP(f)=EP~(f)

模型

最大熵模型可以表示为,满足所有约束条件的模型集合

C{R|EP(fi)=EP~(fi),i=1,2,...,n}

定义在条件概率分布 P(Y|X) 上的条件熵为
H(P)=x,yP~(x)P(y|x)logP(y|x)

则模型集合 C 中条件熵 H(P) 最大的模型称为最大熵模型。式中为自然对数。

对偶结果

通过对偶问题可以将模型化为

Pw(y|x)=1Zw(x)exp(i=1nwifi(x,y))Zw(x)=yexp(i=1nwifi(x,y))

wi,i=1,2,...,n 为参数,n为特征函数的个数。
特征函数 fi,i=1,2,...,n ,经验分布 P~(x),P~(x,y) ,模型 Pw(y|x)
具体推到可以看 推导过程

改进的迭代尺度方法

算法:
输入:训练数据集
输出:最优参数 wi ,最优模型 Pw(y|x)
1. 选取特征函数 fi,i=1,2,...,n ,计算经验分布 P~(x),P~(x,y) ,初始化 w=[0,0,...,0]
2. 计算特征函数关于经验分布的期望 EP~(f)
3. 对每一个 i{1,2,...,n}
a. 计算 EP(f)
b.令 ηi ηi=1MlogEP~(f)EP(fi)
c.更新 wi=wi+ηi
4. 如果不是所有 wi 都收敛,重复3

改进的迭代尺度法IIS与迭代尺度法GIS的区别为,每次更新完 wi 后,用新的 wi 计算 P(y|x) ,再进一步计算新的 EP(fi+1)

import collections
import math

class MaxEntropy():
    def __init__(self):
        self._samples = []   #样本集,元素是[y,x1,x2,...]的样本
        self._Y = set([])  #标签集合,相当去去重后的y
        self._numXY = collections.defaultdict(int)   #key为(x,y),value为出现次数
        self._N = 0  #样本数
        self._ep_ = []   #样本分布的特征期望值
        self._xyID = {}   #key记录(x,y),value记录id号
        self._n = 0  #特征的个数
        self._C = 0   #最大特征数
        self._IDxy = {}    #key为(x,y),value为对应的id号  
        self._w = []
        self._EPS = 0.005   #收敛条件
        self._lastw = []    #上一次w参数值
    def loadData(self,filename):
        with open(filename) as fp:
            self._samples = [item.strip().split('\t') for item in fp.readlines()]
        for items in self._samples:
                y = items[0]
                X = items[1:]
                self._Y.add(y)
                for x in X:
                    self._numXY[(x,y)] += 1
    def _sample_ep(self):   #计算特征函数fi关于经验分布的期望
        self._ep_ = [0] * self._n
        for i,xy in enumerate(self._numXY):
            self._ep_[i] = self._numXY[xy]/self._N
            self._xyID[xy] = i
            self._IDxy[i] = xy



    def _initparams(self):  #初始化参数
        self._N = len(self._samples)
        self._n = len(self._numXY)
        self._C = max([len(sample)-1 for sample in self._samples])
        self._w = [0]*self._n
        self._lastw = self._w[:]

        self._sample_ep()                 #计算每个特征关于经验分布的期望
    def _Zx(self,X):    #计算每个x的Z值
        zx = 0
        for y in self._Y:
            ss = 0
            for x in X:
                if (x,y) in self._numXY:
                    ss += self._w[self._xyID[(x,y)]]
            zx += math.exp(ss)
        return zx

    def _model_pyx(self,y,X):   #计算每个P(y|x)
        Z = self._Zx(X)
        ss = 0
        for x in X:
            if (x,y) in self._numXY:
                ss += self._w[self._xyID[(x,y)]]
        pyx = math.exp(ss)/Z
        return pyx

    def _model_ep(self,index):   #计算特征函数fi关于模型的期望
        x,y = self._IDxy[index]
        ep = 0
        for sample in self._samples:
            if x not in sample:
                continue
            pyx = self._model_pyx(y,sample)
            ep += pyx/self._N
        return ep

    def _convergence(self):
        for last,now in zip(self._lastw,self._w):
            if abs(last - now) >=self._EPS:
                return False
        return True

    def predict(self,X):   #计算预测概率
        Z = self._Zx(X)
        result = {}
        for y in self._Y:
            ss = 0
            for x in X:
                if (x,y) in self._numXY:
                    ss += self._w[self._xyID[(x,y)]]
            pyx = math.exp(ss)/Z
            result[y] = pyx
        return result

    def train(self,maxiter = 1000):   #训练数据
        self._initparams()
        for loop in range(0,maxiter):  #最大训练次数
            print ("iter:%d"%loop)
            self._lastw = self._w[:]
            for i in range(self._n):
                ep = self._model_ep(i)    #计算第i个特征的模型期望
                self._w[i] += math.log(self._ep_[i]/ep)/self._C   #更新参数
            print("w:",self._w)
            if self._convergence():   #判断是否收敛
                break



maxent = MaxEntropy()
x = ['sunny','hot','high','FALSE']
maxent.loadData('dataset.txt')
maxent.train()
print('predict::::::::::::::::::',maxent.predict(x))

猜你喜欢

转载自blog.csdn.net/weixin_37895339/article/details/78858308