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

来源:互联网 发布:帝国时代2蛮王崛起mac 编辑:程序博客网 时间:2024/04/29 14:04

代码及数据集下载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 collectionsimport mathclass 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():   #判断是否收敛                breakmaxent = MaxEntropy()x = ['sunny','hot','high','FALSE']maxent.loadData('dataset.txt')maxent.train()print('predict::::::::::::::::::',maxent.predict(x))
阅读全文
0 0
原创粉丝点击