AdaBoost------Python实现二

来源:互联网 发布:中国大数据安全 编辑:程序博客网 时间:2024/06/14 06:28

我极度槽糕的心情!!!

今天早上我突然发现了一件让我很伤心的事情,前天写的一篇技术博文《统计学习方法笔记八—-提升方法》竟然没有发表成功!!!而且又被后来的草稿给覆盖了!!!What?!

前言

上一节我们已经讲过一次代码实现了,主要是调用sklearn中的接口,让大家有个整体上的认识。本节主要是利用Python一步一步的来实现。注意,这只是一个简单的实现,步骤还是相对清晰,有助于对算法的加深理解,但是本算法不保证效率。

代码实现

我们先引入两个Python 代码包:sign.py和weakclass.py。sign.py实现了符号函数,很简单。weakclass.py实现了弱分类器,在AdaBoost算法中没迭代一次就训练一个弱分类器,那么在这里就是没迭代一次,就需要调用一次WEAK类,并且在WEAK类中实现了一个train方法。train方法主要是用来训练每一个弱分类器:找到最小的误差分裂点以及分类属性、分裂类别。

#sign.py# -*- encoding:utf-8 -*-#符号函数import numpy as npimport scipy as spimport warningsdef sign(x):    q=np.zeros(np.array(x).shape)    q[x>=0]=1    q[x<0]=-1    return q
#weakclass.py# -*- encoding:utf-8 -*-#弱分类器from __future__ import divisionimport numpy as npimport scipy as spclass WEAKC:    def __init__(self,X,y):        '''        param X: N*M matrix        param y: is a length M vector        M is the number of traincase 训练样本个数        N is the number of feature  特征个数        this weak calssifier is a decision Stump        it's just a basic example from <统计学习方法>        '''        self.X=np.array(X)        #print self.X.shape        self.y=np.array(y)        self.N=self.X.shape[0]    def train(self,W,steps=100):        '''        W is a N length vector#权重向量        '''        min=10000000000.0        t_val=0        t_point=0        t_b=0        self.W=np.array(W)        for i in range(self.N):#对于每一个特征            q,err=self.findmin(i,1,steps)#1:类别为1            #判断划分后的错误率是否小于当前的错误率            if err<min:                min=err                t_val=q                t_point=i#分裂点为第i个特征                t_b=1        #按照类别-1进行划分        for i in range(self.N):            q,err=self.findmin(i,-1,steps)#;类别为-1            if err<min:                min=err                t_val=q                t_point=i                t_b=-1        self.t_val=t_val#得到最终决策树        self.t_point=t_point#得到最终的分裂特征为        self.t_b=t_b#最终的分裂类别        print self.t_val,self.t_point,self.t_b        return min    def findmin(self,i,b,steps):#第i个特征上切分,找到最小误差        t=0        now=self.predintrain(self.X,i,t,b).transpose()        err=np.sum((now!=self.y)*self.W)        pgd=0        buttom=np.min(self.X[i,:])        up=np.max(self.X[i,:])        mins=1000000        minst=0        st=(up-buttom)/steps        for t in np.arange(buttom,up,st):            now=self.predintrain(self.X,i,t,b).transpose()            err=np.sum((now!=self.y)*self.W)            if err<mins:                mins=err                minst=t        return minst,mins#寻找最小分裂,和最小分裂误差    def predintrain(self,test_set,i,t,b):        test_set=np.array(test_set).reshape(self.N,-1)#行数为:特征数。列数为:样本数        gt=np.ones((np.array(test_set).shape[1],1))#行数为:样本数,列数为:1        gt[test_set[i,:]*b<t*b]=-1        return gt    def pred(self,test_set):        test_set=np.array(test_set).reshape(self.N,-1)#行数为:特征数。列数为:样本数        t=np.ones((np.array(test_set).shape[1],1))#行数为:样本数,列数为:1        t[test_set[self.t_point,:]*self.t_b<self.t_val*self.t_b]=-1        return t

最后就是我们的集成算法:AdaBoost.

# -*- encoding:utf-8 -*-from __future__ import divisionimport numpy as npimport scipy as cpfrom weakclassify import WEAKCfrom sign import *class ADABST:    def __init__(self,X,y,Weaker=WEAKC):        '''        :param X: 是一个N*M的矩阵,N:代表feature_numbers  M:代表sample_numbers        :param y:        :param Weaker:一个弱分类器        :return:        '''        #初始化数据        #X是样本点        self.X=np.array(X)        #列优先排列 Y是样本对应的类别 排成一个行向量        self.y=np.array(y).flatten(1)        #print self.y        #判断数据维度的列数是否一样(数据是否对应)        assert self.X.shape[1]==self.y.size        self.Weaker=Weaker        self.sums=np.zeros(self.y.shape)        #print self.sums        #初始化权值,每个样本的权值为1/样本数        self.W=np.ones((self.X.shape[1],1)).flatten(1)/self.X.shape[1]        #print self.W        self.Q=0#统计迭代次数    def train(self,M=4):        '''        M是最大类别(第M个)弱分类器的下标,其实就是迭代的次数        '''        #初始化弱分类器字典(空)        self.G={}        #弱分类器的话语权        self.alpha={}        print '总共迭代次数为:',M        for i in range(M):            self.G.setdefault(i)#{0:None,...,i:None}            self.alpha.setdefault(i)#{0:None,...,i:none}        for i in range(M):            print '第%d次迭代:'%i            #用样本初始化弱分类器            self.G[i]=self.Weaker(self.X,self.y)            #调用train方法,训练弱分类器,同时计算最小误差率            e=self.G[i].train(self.W)            print '第%d次迭代的错误率为:%.2f'%(i,e)            #计算弱分类器Gi的话语权(根据公式)            self.alpha[i]=1/2*np.log((1-e)/e)#求得第i个分类器的系数            #计算弱分类器Gi对样本的分类结果            sg=self.G[i].pred(self.X)            #计算归一化因子(计算样本权值时,保证权值之和为1)            Z=self.W*np.exp(-self.alpha[i]*self.y*sg.transpose())            #更新样本的权重            self.W=(Z/Z.sum()).flatten(1)            #记录迭代次数(从0开始)            self.Q=i            #判断组合起来的强分类器的效果,如果没有分错,不再迭代            if self.finalclassifer(i)==0:                print i+1,"weak classifier is enough to make the error to 0"                break    def finalclassifer(self,t):        '''        将第1个到第t个弱分类器组合起来(跟踪adaboost强分类器组合公式)        '''        #组合成强分类器,并直接计算出其对样本的分类结果(没有用sign函数计算前)        self.sums=self.sums+self.G[t].pred(self.X).flatten(1)*self.alpha[t]        #用sign对分类器计算出的值进行判别        pre_y=sign(self.sums)         t=(pre_y!=self.y).sum()        return t    def pred(self,test_set):        test_set=np.array(test_set)        #判断数据大小是否一样        assert test_set.shape[0]==self.X.shape[0]        sums=np.zeros((test_set.shape[1],1)).flatten(1)        #计算分类器训练样本的结果        for i in range(self.Q+1):            sums=sums+self.G[i].pred(test_set).flatten(1)*self.alpha[i]            #print sums        #甩sign函数判断类别        pre_y=sign(sums)        return pre_yif __name__ == '__main__':    #我们利用书上的例子来试一下    X = np.array([0,1,2,3,4,5,6,7,8,9]).reshape(1,-1)#1行10列    #print X    #print X.shape    y = np.array([1,1,1,-1,-1,-1,1,1,1,-1]).transpose()#10行    #print y    #print y.shape    a= ADABST(X,y)    a.train(5)    print a.G    print a.pred([[0.55,4.5]])

参考文献:
http://blog.csdn.net/zxc024000/article/details/51577324
http://blog.csdn.net/Best_Coder/article/details/42127033
http://blog.csdn.net/google19890102/article/details/46376603