adaboost算法

参考文章:http://blog.csdn.net/haidao2009/article/details/7514787

                   http://baidutech.blog.51cto.com/4114344/743809

                   http://blog.csdn.net/u013207865/article/details/52728944

参考代码:https://github.com/zengkui/machine-learning/tree/master/Adaboost

参考教材: 《统计学习方法》 李航

算法原理:三个臭皮匠顶个诸葛亮

         历史上,Kearns和Valiant首先提出了“强可学习”(strongly learnable)和“弱可学习”(weakly learnable):在概率近似正确(probably approximately correct,PAC)学习框架下,一个概念如果存在多项式的学习算法学习它,并且正确率很高,那么这个概念就被称为强可学习的;一个概念,如果存在多项式的学习算法学习它,并且正确率只比随机猜测好一点,那么这个概念称为弱可学习的。非常有趣的是后来Scphaire证明,强可学习和若可学习是等价的。也就是说,在PAC学习的框架下,一个概念是强可学习的充分必要条件是这个概念是弱可学习的。

        这样一来,如果已经发现了“弱学习算法”,可将其提升为“强学习算法”,Adaboost算法就是一种最具代表性的提升算法。

        提升方法就是从弱学习算法出发,反复学习,得到一系列基本分类器,然后组合这些基本分类器,构成一个强分类器。大多数的提升方法都是改变训练数据的权值分布,针对不同的训练数据分布调用弱学习算法学习一系列基本分类器。

         这样对于提升方法来说,需要考虑两个问题:一是在每一轮如何改变数据的权值分布;二是如何将这些基本分类器组合成一个强分类器。

         关于第一个问题,Adaboost的做法是,提高那些被本轮基本分类器错误分类样本的权值,而降低哪些被正确分类样本的权值。这样一来,那些本轮没有得到正确分类的样本,由于其权值的增大而受到下一轮的基本分类器的更大关注。

        关于第二个问题,Adaboost的做法是采取加权多数表决的方法,具体地,加大分类误差率小的基本分类器的权值,使其在表决中起较大作用,减小分类误差率大的基本分类器的权值,使其在表决中起较小的作用

 算法(Adaboost)






下面根据一个例子介绍Adaboost具体实现


                          图  1

上图可以看成是坐标系中的点集,“+”代表一类,“-”代表一类。这是一种分类问题,即给定一个点p的坐标(x,y)判断点p属于哪一类。

首选应该构造弱学习算法,这里构造的弱学习算法为:通过利用水平和垂直线将样本分类,如下图所示


这里用的弱学习算法就是设置阈值v,比如说x<v 的样本数据为一类,x>v的样本数据为另一类,或者y<v的样本数据为一类,y>v的样本数据为另一类。


阈值v的选取通过设置任意两个不同横坐标或者不同纵坐标的均值作为阈值

比如如下一组数据(对应图1中的十个样本点,1代表"+"类,-1代表"-"类)

1,5,1
2,3,1
3,1,-1
4,5,-1
5,6,1
6,4,-1
6,7,1
7,6,1
8,7,-1
8,2,-1

上述十个样本点的横坐标为1,2,3,4,5,6,6,7,8,8

所以设置一组x对应的阈值 1.5  2.5 3.5  4.5 5.5 6.5 7.5   共七个

上述十个样本点的纵坐标(递增排序后)为 1,2,3,4,5,5,6,6,7,7

所以设置另外一组y对应的阈值 1.5 2.5 3.5 4.5 5.5 6.5   共六个

因此上述十个样本点需要设置 13个阈值

然后在每一轮迭代中,根据样本数据的权值分布,计算每一个弱学习算法的误差率(只在第一轮迭代的时候指代 分错的样本数占总样本数的比率  ),选取误差率最小的弱学习算法作为本轮的基本分类器。

最后将每一轮选取出的基本分类器组合成为最终的强分类器。



下面给出了具体的程序:

步骤:
第一步:读取训练数据
第二步:基于训练数据构造弱分类器
构造方法:先将所有数据的横标坐标从小到大排序,设置阈值,阈值分别设置为任意两个相邻横坐标的均值,若两相邻横坐标相同,则此处不设置阈值
         然后将所有数据的纵坐标从小到大排序,设置阈值,阈值分别设置为任意两个相邻纵坐标的均值,若两相邻纵坐标相同,则此处不设置阈值
         每一个阈值v对应两个弱分类器:(v,inf) (-inf,v)
第三步:进行M轮迭代。每一轮,在权值分布为Di的训练数据上,根据弱分类器的分类误差率确定基本分类器
第四步:计算基本分类器的系数
第五步:更新训练数据的权值分布

训练数据 data .txt

10
1,5,1  
2,3,1  
3,1,-1  
4,5,-1  
5,6,1  
6,4,-1  
6,7,1  
7,6,1  
8,7,-1  
8,2,-1

adaboost.py
# -*- coding: utf-8 -*-
__author__ = "zengkui111@gmail.com"
__modifier__="543611694@qq.com"
import os
import sys
import math
inf = float("inf")

class Point:
    def __init__(self, x, y, label, weight ):
        self.x = x
        self.y = y
        self.label = label
        self.weight = weight 

class Learner:
    def __init__(self, vrng, fid ):
        self.vrng = vrng
        self.fid = fid
        self.weight = 0.0
        
    def test_predict(self,d):
        if self.fid=='x':
            if self.vrng[0] < d.x < self.vrng[1]:
                return 1
            else:
                return -1
        elif self.fid=='y':
            if self.vrng[0] < d.y < self.vrng[1]:
                return 1
            else:
                return -1
                
class Adaboost:
    def __init__(self, input_data, M):
        self.read_data(input_data)

        weak_learners = []
        boundary = []
        for p in self.points :
            boundary.append(p.x)
        weak_learners = self.make_learners( boundary, 'x')
        boundary = []
        for p in self.points :
            boundary.append(p.y)
        weak_learners += self.make_learners( boundary, 'y')
        print "弱分类器个数",len(weak_learners)
      
        self.learners = []
        for i in range(1,M+1):
            #calculate the error for each learner
            info = []
            for learner in weak_learners:
                err = 0.0
                for p in self.points :
                    category = learner.test_predict(p)
                    if category != p.label: 
                        err += p.weight
                info.append((err, learner))
            #根据分类误差率确定基本分类器
            [err, learner]= min(info)          # the way to select weak classifier
            #计算基本分类器的系数
            learner.weight = (math.log((1- err) / err))/2
           
            #更新训练数据集的权值分布
            z = 0.0
            for p in self.points:
                category =  learner.test_predict(p)
                t = p.weight * math.exp( -1 * learner.weight * p.label * category)
                p.weight = t
                z += t
            for p in self.points:
                p.weight = p.weight / z
            print "第",str(i),"轮,","基于",learner.fid,"进行分类"
            print "位于",learner.vrng,"的样本为正类,其他样本为负类,基本分类器系数为",learner.weight
            self.learners.append(learner)
    def read_data(self, input_data):
        fp = open(input_data)
        self.points = []
        pn = fp.readline().strip('\r\n')
        pn = float(pn)
        weight = 1.0 / pn
        for line in fp.readlines():
            x,y,label = line.strip('\r\n') .split(',')
            self.points.append( Point(float(x), float(y), float(label), weight ))
        print "样本个数:",len(self.points)
        fp.close()
        
        
#---------构建弱分类器----------#
    def make_learners(self, boundary, fid):
        boundary = [min(boundary) - 1] + sorted(boundary) + [max(boundary) + 1]
        learners = []
        for i in range(1, len(boundary)):
            if boundary[i] == boundary[i - 1]:
                continue
            l = (boundary[i] + boundary[i - 1]) / 2
            
            learners.append(Learner((l, inf), fid))
            learners.append(Learner((-inf, l), fid))
        return learners 

    def predict(self):
        print "(x, y)\tlabel\tpredict"
        for p in self.points:
            category = 0.0 
            for learner in self.learners:
                category += learner.test_predict(p) * learner.weight
            if category > 0 :
                print "(%.f, %.f)\t%+.f\t%+.f" % (p.x, p.y, p.label, 1)
            else :
                print "(%.f, %.f)\t%+.f\t%+.f" % (p.x, p.y, p.label, -1)


if __name__ == "__main__":

    adaboost = Adaboost("data1.txt", 3) 
adaboost.predict()
样本个数: 10
弱分类器个数 34
第 1 轮, 基于 x 进行分类
位于 (-inf, 2.5) 的样本为正类,其他样本为负类,基本分类器系数为 0.423648930194
第 2 轮, 基于 x 进行分类
位于 (-inf, 7.5) 的样本为正类,其他样本为负类,基本分类器系数为 0.649641492065
第 3 轮, 基于 y 进行分类
位于 (5.5, inf) 的样本为正类,其他样本为负类,基本分类器系数为 0.922913345249
(x, y)  label   predict
(1, 5)  +1      +1
(2, 3)  +1      +1
(3, 1)  -1      -1
(4, 5)  -1      -1
(5, 6)  +1      +1
(6, 4)  -1      -1
(6, 7)  +1      +1
(7, 6)  +1      +1
(8, 7)  -1      -1
(8, 2)  -1      -1
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值