AdaBoost------Python实现二

我极度槽糕的心情!!!

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

def 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 division
import numpy as np
import scipy as sp

class 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 division
import numpy as np
import scipy as cp
from weakclassify import WEAKC
from 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_y

if __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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱科研的徐博士

请各位看官赏赐,小仙女笔芯笔芯

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值