adaboost算法

来源:互联网 发布:win8安装软件乱码 编辑:程序博客网 时间:2024/05/21 08:52

1 简介
Adaboost算法是一种分类器增强算法,单独而言,不具备分类器的功能,需要与其他分类器相结合才能发挥作用。Adaboost算法的核心思想是多个分类器的线性加权集成,从而最终得出判断结果。最常用的场景是对弱分类器进行增强,所谓若分类器,是指分类器的正确率至少大于50%。
既然是多个分类器的线性加权集成,那么这里面就存在两个问题需要解决:
1.每个分类器的生成。
2.每个分类器的权重。
显而易见,若是多个分类器是相同的,那么线性加权也没有什么意义,那么如何在同一组训练样本下,如何生成多个不同的分类器便是adaboost算法首要解决的问题。

2.最富信息样本
在普通的分类器训练过程中,所有的样本全都参与训练,且每个样本所占比重相同,这种情况对样本的训练不具备针对性,所有样本一视同仁,adaboost算法从这个角度上来讲,就是解决样本针对性问题的,使训练能够聚焦于容易出现错分的样本。这种样本称之为“最富信息样本”。
最富信息样本的实现,需要借助“不等概率采样”来实现,在原样本集合中,进行二次抽样,在该过程中,每个原样本集合的个体被赋予不同的权重,权重大的个体被抽样到的概率高,权重小的个体被抽样到的概率低。

3.算法流程
1)初始化训练数据的权值分布。如果有N个样本,则每一个训练样本最开始时都被赋予相同的权值:1/N。


这里写图片描述

2)在权值分布Dm(m表示第m轮迭代,m=1,2,3…).的基础上生成一个分类器。(分类器为二分类器,分类器可以为最简单的阈值分类器,也可以为高级的SVM,神经网络等等,得到的结果为-1,+1)。


这里写图片描述

3)将原始的数据集,放入上一部生成的分类器当中,统计出分类误差率em;


这里写图片描述

4)计算分类器Gm的线性系数Am,分类器误差率越低,则分类器所占的权重越高。


这里写图片描述

之所以采用这个公式是因为当em<1/2时,即不满足弱分类器的条件时,Am<0。当em>1/2时,Am>0,且Am是关于em的单调递增函数。
5)更新训练数据的权值分布,用于下一轮分类器的生成;


这里写图片描述

这一步是整个adaboost算法中最重要的一步,也是最难理解的一步。首先看一下新一轮的权值分布跟上一轮的那些因素有关。
a.上一轮对应样本个体的权值;
b.上一轮对应样本个体的实际类别yi;
c.上一轮对应样本个体的分类结果Gm(xi);
d.上一轮生成的分类器的权值;
e.规范化因子Zm;


这里写图片描述

规范化因子存在的作用是使Dm+1成为一个概率分布,即:


这里写图片描述

这里写图片描述可以看作是一个整体,方向因子。
当上一轮中,该样本分类正确,该因子为-1,下一轮该样本权值与Am呈负相关;
当上一轮中,该样本分类错误,该因子为+1,下一轮该样本权值与Am呈正相关;
该公式会导致,权重大的分类器分错的样本拥有最高的权值。

6)返回第二步,,直到达到某个预定的足够小的错误率或达到预先指定的最大迭代次数时,进行下一步;
7)线性组合各个弱分类器;
这里写图片描述

4.代码实现

#include<iostream>#include<cmath>#include<time.h>#include<algorithm>using namespace std;#define CLASSIFY_NUM_MAX 10000          //最大弱分类次数#define EXAMPLE_NUM 10000           //样本数#define MAX_NUM 10              //样本最大值#define MAX_DIMEN 1             //最大样本维度#define INTERVAL 1000             bool ifAchieveAccuracy(float _accuracy);int adaboostClassify(float *X);int num_of_classify = 0;struct trainingExample{         //样本    float features[MAX_DIMEN];  //X    int classLabel;             //y    int res;                    //记录每次分类结果    float weight;               //存储权值}trExp[EXAMPLE_NUM];struct weakClassify{    float alpha;                //权值alpha    float threshold;            //阈值    int direction;              //分类方向    int dimen;                  //维度}weakC[CLASSIFY_NUM_MAX];void createData(){                              //构造训练数据            float temp[EXAMPLE_NUM];    int label[EXAMPLE_NUM];    srand( (unsigned)time( NULL ) );    for(int i=0; i<EXAMPLE_NUM; i++)    {        label[i] = ((i/INTERVAL)%2)?1:-1;    }    for(int dim = 0;dim < MAX_DIMEN;dim++){        for(int i=0;i<EXAMPLE_NUM;i++)            temp[i] = rand()%(MAX_NUM*10)/10.0;        sort(temp,temp+EXAMPLE_NUM);        for(int i=0;i<EXAMPLE_NUM;i++){            trExp[i].features[dim] = temp[i];   //控制样本在MAX_NUM以内            trExp[i].classLabel = label[i];        }    }}/*    根据公式Wm+1 = Wm * exp(-1 * ALPHAm* Yi * Gm(Xi)/Zm更新权值。    准备进行下次迭代。*/void updateWeight(int index,int res[]){     //更新权值    float temp[EXAMPLE_NUM];    float sum=0;    for(int i=0;i<EXAMPLE_NUM;i++){                 temp[i] = trExp[i].weight * exp(-1.0 * weakC[index].alpha * (float)trExp[i].classLabel * (float)res[i]);        sum += temp[i];                     //sum用来归一化    }       for(int i=0;i<EXAMPLE_NUM;i++){        trExp[i].weight = temp[i]/sum;    }}/*    将区间划分,遍历每个位置的误差,    寻找误差最小的阈值,并记录分类器状态。*/void findSimpleClassifyThreshold(int index){    int i;    float step = (float)MAX_NUM/100;            float thr = 0.0;    float err;    float minErr = 100000000;    int res[EXAMPLE_NUM];    for(int dim = 0;dim < MAX_DIMEN;dim++){        for(thr = 0.0;thr < MAX_NUM;thr+=step){ //寻找弱分类器合适阈值            for(int dir=0;dir<=1;dir++){        //两个方向判断阈值                err=0;                for(i=0;i<EXAMPLE_NUM;i++){     //根据方向进行初步分类                    if(!dir){                        if(trExp[i].features[dim] <= thr)                               trExp[i].res = 1;                        else trExp[i].res = -1;                    }                    else{                        if(trExp[i].features[dim] >= thr)                            trExp[i].res = 1;                        else trExp[i].res = -1;                    }                }                for(i=0;i<EXAMPLE_NUM;i++){     //如果分类错误 计算误差率                    if(trExp[i].res!=trExp[i].classLabel)                        err+=trExp[i].weight;   //分类器权重                }                if(err<minErr){                 //寻找最小的误差 存储相应数据                    minErr = err;                    weakC[index].dimen = dim;                    weakC[index].threshold = thr;                    weakC[index].direction = dir;                    for(i=0;i<EXAMPLE_NUM;i++){                        res[i] = trExp[i].res;                    }                }                                   }        }    }    weakC[index].alpha = log((1.0-minErr)/minErr)/2;    //计算分类器权值alpha//  printf("weakC[%d].alpha = %f \n",index,weakC[index].alpha);    updateWeight(index,res);                            //更新各数据权重  更新权重的策略是什么?}void Adaboost(){    for(int i=0;i<EXAMPLE_NUM;i++){     //分配权重 默认权重相同        trExp[i].weight = (float)1.0/EXAMPLE_NUM;    }    int classify_index = 0;    //当达到给定正确率或者超过最大分类器个数时停止运行程序    while(1)    {        findSimpleClassifyThreshold(classify_index);        bool ret = ifAchieveAccuracy(0.99);        if(ret)        {            printf("achieve accuracy gived!!\n");            std::cout << "using " << num_of_classify << " classifies" << std::endl;            break;        }        if(num_of_classify > CLASSIFY_NUM_MAX - 2)        {            printf("has using out classify!!\n");            break;        }        classify_index ++;        num_of_classify = classify_index;    }}bool ifAchieveAccuracy(float _accuracy){    int right_num = 0;    for(int i=0; i<EXAMPLE_NUM; i++)    {        float input[MAX_DIMEN];        input[0] = trExp[i].features[0];        int output = adaboostClassify(input);        if(output == trExp[i].classLabel)        {            right_num ++;        }    }    //正确率在分类器个数增加的情况下,为什么不是呈递增的趋势,而是波动?    float accuracy = (float)right_num/(float)EXAMPLE_NUM;    std::cout << "the num of classify is  " << num_of_classify << "the current accuracy is " << accuracy << endl;    if(accuracy > _accuracy)    {        return true;    }    else    {        return false;    }}/*    根据输入x,得到各个分类器分类结果*/int simpleClassify(float x,int index){    if(weakC[index].direction == 0){        if(x>weakC[index].threshold)            return -1;        else return 1;    }    else{        if(x>weakC[index].threshold)            return 1;        else return -1;    }}int sign(float x){    if(x>=0) return 1;    return -1;}int adaboostClassify(float *X){    float result = 0,temp;    for(int i = 0;i < num_of_classify; i++){        temp = weakC[i].alpha * (float)simpleClassify(X[weakC[i].dimen],i);         result += temp;    }    return sign(result);}int main(){    createData();                               //构造训练数据    Adaboost();                             //计算各分类器权值    return 0;}
1 0
原创粉丝点击