代码及数据集下载Max Entropy
最大熵原理是概率学习模型的一个准则。最大熵原理认为,学习概率模型时,在所有可能的概率模型中,上最大的模型是最好的模型,保留了最大的不确定性,从投资角度讲就是风险最小,将鸡蛋放在多个篮子里。通常用约束条件来确定概率模型的集合,因此,最大熵原理可以表述为在满足约束条件的模型集合中选取熵最大的模型。
假设离散随机变量X的概率分布为P(X),则其熵为
f(x,y) 描述输入x与输出y之间的某一个事实。
最大熵模型是利用最大熵原理得到分类模型。
对于给定数据集
约束条件是指根据给出的样本数据,确定的满足样本数据的约束。在约束下利用最大熵原理确定分类模型。在最大熵模型中,对于任意一个特征函数 f ,记 EP~(f) 表示 f 在训练数据 T 上关于 P~(x,y) 的数学期望, EP(f) 表示 f 在模型上关于 P(y|x) 的数学期望。
最大熵模型可以表示为,满足所有约束条件的模型集合
通过对偶问题可以将模型化为
算法:
输入:训练数据集
输出:最优参数 w∗i ,最优模型 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))