①起源:Boosting算法

Boosting算法的目的是每次基于全部数据集,通过使用同一种分类器不同的抽取参数方法(如决策树,每次都可以抽取不同的特征维度来剖分数据集)

训练一些不同弱分类器(单次分类错误率>0.5),然后将其组合起来,综合评估(默认认为每个分类器权重等价)进行分类。

AdaBoost算法进行了对其进行了改进。

一、每次训练分类器时,给予每条数据用于计算误差的不同权重D。

二、每个分类器,给予用于分类的不同权重alpha。

两种权的使用,使得AdaBoost在组合分类器时,能够根据当前的训练情况做一些调整。

②弱分类器:单决策树

单决策树应该是AdaBoost中使用最多的弱分类器。硬伤是单决策树是个0/1二类分类器。(实际是-1/+1二类)

一般决策树是通过DFS,连续选择不同维度多深度划分数据集。

单决策树就是一般决策树的1维版本,只搜dep=1就结束。

单决策树有两个好处:

一、单次分类效果很差(满足弱分类器定义)

二、根据决策属性不同,即便重复使用单决策树,也可以诞生出分类效果不同的分类器。

单决策树对于连续型数据,采用阈值(threshold)分类法。

首先确定所有数据中某个特征维度里的min/max范围。

然后采用步进的方法(每次阈值=min+当前步数*步长)来确定阈值。

基于同一个阈值,又可以把小于/大于阈值的分到不同类(2种分法)。

所以单决策树最多有【D*步数*2】种变形分类器。

②双权问题

一、分类器权alpha

定义 $\alpha = \frac{1}{2} \ln \left ( \frac{1-\varepsilon }{\varepsilon } \right )$,其中$\varepsilon$为错误率。

P.S 实际Coding时,为防止$\varepsilon$为零,通常取max($\varepsilon$,eps)

$\alpha$这个函数比较有趣,求导之后,假设每次使用新的分类器,错误率都会变小,以错误率变小为x正轴,有图像:

这个图像告诉我们,AdaBoost对后续分类器,给的权是逐渐变大的,因为我们有理由相信,后续分类器更科学一点。

分类器权如何使用呢?假设当前分类器的二类分类结果向量[-1,1,-1,1],那么其加权之后就是$\alpha$ * [-1,1,-1,1]。

对于二类问题,将全部分类器的加权结果累加起来,通过判断加权结果符号的正负判断分类,因为$\alpha$的值域是R,所以只能看符号判断分类。

二、数据权D

每条数据都有权D,该权实际是个概率权,总权和=1。

如果一条数据被正确分类,则$D_{i}^{new}= \frac{D_{i}^{old}*e^{-\alpha}}{Sum(D)}$

如果一条数据被错误分类,则$D_{i}^{new}= \frac{D_{i}^{old}*e^{\alpha}}{Sum(D)}$

正确分类的权会被减小,错误分类的权会被增大。有趣的是,这两个式子如果单从$\alpha$角度来看,似乎有点问题。

如果某次$\alpha$为负,那么$D_{i}^{new}= \frac{D_{i}^{old}*e^{-\alpha}}{Sum(D)}$中$D_{i}^{new}$似乎好像是变大了。

但如果你把$\alpha$的定义式拉到$D_{i}^{new}$里面,就会发现:

$\left\{\begin{matrix}
D_{i}^{new}= \frac{1}{\sqrt{e}}*\frac{1-\varepsilon }{\varepsilon }
\\
D_{i}^{new}= \sqrt{e}*\frac{1-\varepsilon }{\varepsilon}
\end{matrix}\right.$

这样,很明显就可以看出,正确分类的权确实相对于错误分类的权被减小了。

数据权D的引入,主要是采用一种新的方式计算错误率。

一般的错误率$\varepsilon=\frac{errorExamples}{allExamples}$

但是AdaBoost里对错误率也进行加权了,$\varepsilon=\sum_{i=1}^{m}D_{i}*isError?1:0$

由于D是概率权,这样算出来的也算是错误率。如果一条数据分错了、又分错了、还是分错了,那么这条数据理应得到重视,其也会导致错误率比较大。

这种加权错误率对于在单决策树里,从众多变形分类器中,选择一个错误率最低分类器,有很好的参考意义。

③算法过程

★训练过程

while(true)

{

一、构建一个错误率最低的单决策树分类器,并保存记录该分类器全部属性(α、阀值、选取维度、分类结果)

二、利用构建的单决策树分类器计算α加权分类结果

若数据样本分类全部正确(大数据情况下几乎不可能)、分类正确率到达一定情况(多见于正确率收敛)则break

}

★测试过程

for(全部构建的分类器)

      for(全部测试数据)

           一、使用当前分类器分类

二、累计计算使用全部分类器的加权结果(记录α的原因)

根据加权结果的正负判断分类

不难发现,测试过程其实就是训练过程的某一步提取出来的。

④代码

  1. #include "iostream"
  2. #include "fstream"
  3. #include "sstream"
  4. #include "math.h"
  5. #include "vector"
  6. #include "string"
  7. #include "cstdio"
  8. using namespace std;
  9. #define fin cin
  10. #define inf 1e10
  11. #define D dataSet[0].feature.size()
  12. #define delta 100
  13. int sign(double x) {return x<?-:;}
  14. struct Data
  15. {
  16. vector<double> feature;
  17. int y;
  18. Data(vector<double> feature,int y):feature(feature),y(y) {}
  19. };
  20. struct Stump
  21. {
  22. vector<int> classEst;
  23. int dim,symbol;
  24. double threshold,error,alpha;
  25. Stump() {}
  26. Stump(vector<int> classEst,int dim,double threshold,int symbol,double error):classEst(classEst),dim(dim),threshold(threshold),symbol(symbol),error(error) {}
  27. };
  28. vector<Data> dataSet;
  29. void read()
  30. {
  31. ifstream fin("traindata.txt");
  32. string line;
  33. double fea,cls;
  34. int id;
  35. while(getline(cin,line))
  36. {
  37. vector<double> feature;
  38. stringstream sin(line);
  39. sin>>id;
  40. while(sin>>fea) feature.push_back(fea);
  41. cls=feature.back();feature.pop_back();
  42. dataSet.push_back(Data(feature,cls==?-:));
  43. }
  44. }
  45. vector<int> stumpClassify(int d,double threshold,int symbol)
  46. {
  47. vector<int> ret(dataSet.size(),);
  48. for(int i=;i<dataSet.size();i++)
  49. {
  50. if(!symbol) {if(dataSet[i].feature[d]<=threshold) ret[i]=-;}
  51. else {if(dataSet[i].feature[d]>threshold) ret[i]=-;}
  52. }
  53. return ret;
  54. }
  55. Stump buildStump(vector<double> dataWeight)
  56. {
  57. int step=;
  58. Stump bestStump;
  59. double minError=inf,weightError;
  60. for(int i=;i<D;i++)
  61. {
  62. double minRange=inf,maxRange=-inf,stepSize;
  63. for(int j=;j<dataSet.size();j++)
  64. {
  65. minRange=min(minRange,dataSet[j].feature[i]);
  66. maxRange=max(maxRange,dataSet[j].feature[i]);
  67. }
  68. stepSize=(maxRange-minRange)/step;
  69. for(int j=;j<=step;j++)
  70. {
  71. double threshold=minRange+stepSize*j;
  72. for(int k=;k<=;k++)
  73. {
  74. vector<int> classEst=stumpClassify(i,threshold,k);
  75. weightError=0.0;
  76. for(int t=;t<classEst.size();t++)
  77. if(classEst[t]!=dataSet[t].y) weightError+=dataWeight[t];
  78. if(weightError<minError)
  79. {
  80. bestStump=Stump(classEst,i,threshold,k,weightError);
  81. minError=weightError;
  82. }
  83. }
  84. }
  85. }
  86. return bestStump;
  87. }
  88. vector<Stump> mainProcess()
  89. {
  90. int iter=,repeat=,last_cnt=-;
  91. vector<double> dataWeight(dataSet.size(),1.0/dataSet.size());
  92. vector<double> aggClassEst(dataSet.size(),0.0);
  93. vector<Stump> stumpList;
  94. while()
  95. {
  96. iter++;
  97. Stump nowStump=buildStump(dataWeight);
  98. double alpha=0.5*log((1.0-nowStump.error)/max(nowStump.error,1e-)),DSum=0.0;
  99. nowStump.alpha=alpha;
  100. stumpList.push_back(nowStump);
  101. int err_cnt=;
  102. for(int i=;i<dataSet.size();i++)
  103. {
  104. double ret=-*alpha*dataSet[i].y*nowStump.classEst[i];
  105. dataWeight[i]=dataWeight[i]*exp(ret);
  106. DSum+=dataWeight[i];
  107. }
  108. for(int i=;i<dataSet.size();i++)
  109. {
  110. dataWeight[i]/=DSum;
  111. aggClassEst[i]+=alpha*nowStump.classEst[i];
  112. if(sign(aggClassEst[i])!=dataSet[i].y) err_cnt++;
  113. }
  114. //cout<<err_cnt<<"/"<<dataSet.size()<<endl;
  115. if(err_cnt!=last_cnt) {last_cnt=err_cnt;repeat=;}
  116. else repeat++;
  117. if(err_cnt==||repeat>delta) break;
  118. }
  119. return stumpList;
  120. }
  121. void classify(vector<Stump> stumpList)
  122. {
  123. ifstream fin("testdata.txt");
  124. dataSet.clear();
  125. string line;
  126. double fea,cls;
  127. int id;
  128. while(getline(cin,line))
  129. {
  130. vector<double> feature;
  131. stringstream sin(line);
  132. sin>>id;
  133. while(sin>>fea) feature.push_back(fea);
  134. cls=feature.back();feature.pop_back();
  135. dataSet.push_back(Data(feature,cls==?-:));
  136. }
  137. vector<double> aggClassEst(dataSet.size(),0.0);
  138. for(int i=;i<stumpList.size();i++)
  139. {
  140. vector<int> classEst=stumpClassify(stumpList[i].dim,stumpList[i].threshold,stumpList[i].symbol);
  141. for(int j=;j<dataSet.size();j++)
  142. aggClassEst[j]+=(stumpList[i].alpha*classEst[j]);
  143. }
  144. for(int i=;i<dataSet.size();i++)
  145. if(sign(aggClassEst[i])==-) printf("%test #%d: origin: %d class %d\n",i,dataSet[i].y,-);
  146. else printf("%test #%d: origin: %d class %d\n",i,dataSet[i].y,);
  147. }
  148. int main()
  149. {
  150. read();
  151. vector<Stump> stumpList=mainProcess();
  152. classify(stumpList);
  153. }

基于单决策树的AdaBoost的更多相关文章

  1. 基于单层决策树的AdaBoost算法源码

    基于单层决策树的AdaBoost算法源码 Mian.py # -*- coding: utf-8 -*- # coding: UTF-8 import numpy as np from AdaBoos ...

  2. 基于单层决策树的AdaBoost算法原理+python实现

    这里整理一下实验课实现的基于单层决策树的弱分类器的AdaBoost算法. 由于是初学,实验课在找资料的时候看到别人的代码中有太多英文的缩写,不容易看懂,而且还要同时看代码实现的细节.算法的原理什么的, ...

  3. 基于Haar特征的Adaboost级联人脸检测分类器

    基于Haar特征的Adaboost级联人脸检测分类器基于Haar特征的Adaboost级联人脸检测分类器,简称haar分类器.通过这个算法的名字,我们可以看到这个算法其实包含了几个关键点:Haar特征 ...

  4. 照片美妆---基于Haar特征的Adaboost级联人脸检测分类器

    原文:照片美妆---基于Haar特征的Adaboost级联人脸检测分类器 本文转载自张雨石http://blog.csdn.net/stdcoutzyx/article/details/3484223 ...

  5. VC基于单文档OpenGL框架

    本文是在VC6.0的环境下,运用MFC实现的OpenGL最基本框架,需要简单了解MFC编程(会在VC6.0里创建MFC单文档应用程序就行),甚至不必了解OpenGL的知识.以下是具体的步骤. 1.创建 ...

  6. 也来写写基于单表的Orm(使用Dapper)

    前言 这两天看园子里有个朋友写Dapper的拓展,想到自己之前也尝试用过,但不顺手,曾写过几个方法来完成自动的Insert操作.而对于Update.Delete.Select等,我一直对Diction ...

  7. 【SVM、决策树、adaboost、LR对比】

    一.SVM 1.应用场景: 文本和图像分类. 2.优点: 分类效果好:有效处理高维空间的数据:无局部最小值问题:不易过拟合(模型中含有L2正则项): 3.缺点: 样本数据量较大需要较长训练时间:噪声不 ...

  8. 决策树和adaboost

    前面:好老的东西啊,啊啊啊啊啊啊啊啊啊 来源于统计学习方法: 信息增益: 其中 信息增益率: 基尼指数: 取gini最小的 先剪枝——在构造过程中,当某个节点满足剪枝条件,则直接停止此分支的构造. 后 ...

  9. 相机标定:PNP基于单应面解决多点透视问题

              利用二维视野内的图像,求出三维图像在场景中的位姿,这是一个三维透视投影的反向求解问题.常用方法是PNP方法,需要已知三维点集的原始模型. 本文做了大量修改,如有不适,请移步原文:  ...

随机推荐

  1. 20145206实验四《Android开发基础》

    20145206 实验四<Android开发基础> 实验内容 ·安装Android Studio ·运行安卓AVD模拟器 ·使用安卓运行出虚拟手机并显示HelloWorld以及自己的学号 ...

  2. JavaScript的内置对象和浏览器对象

    在javascript中对象通常包括两种类型:内置对象和浏览器对象,此外,用户还可以自定义对象. 对象包含两个要素:1.用来描述对象特性的一组数据,也就是若干变量,通常称为属性.2.用来操作对象特性的 ...

  3. IOS 开发,调用打电话,发短信,打开网址

    IOS 开发,调用打电话,发短信,打开网址   1.调用 自带mail [[UIApplication sharedApplication] openURL:[NSURL URLWithString: ...

  4. 服务器知识----IIS架设问题

    1,基本配置,应用程序池,路径等. 2,权限设置  Iuser  IIS_users 只读权限 3,isapi映射  framework安装目录下  运行 aspnet_regiis.exe -i 注 ...

  5. HTML+CSS页面滚动效果处理

    HTML+CSS代码如下: <!doctype html> <html> <head> <meta charset="utf-8"> ...

  6. [LeetCode] Implement strStr()

    Implement strStr(). Returns a pointer to the first occurrence of needle in haystack, or null if need ...

  7. windows下Tomcat配置多实例

    详情参见tomcat安装目录下RUNNING.txt中Advanced Configuration - Multiple Tomcat Instances部分. 问题源于下面这段tomcat官方文档的 ...

  8. Golang Beego 分析(一)

    关于注解路由,实质上其实是comment route. 作者使用ast自动生成注册代码,实质上感觉是画蛇添足了. 有一定的使用价值,但是在代码管理上反而混乱了.所以本人建议不要使用此项特性.

  9. ORA-01041: 内部错误,hostdef 扩展名不存在

    在工作中打算将生产环境的数据库设置成归档模式时,遇到的问题. 一.重启数据库 Sql代码: shutdown immediate; startup mount; 也就是在我执行startup moun ...

  10. 如何实现Outlook 2010 下载邮件后自动删除服务器上的邮件

    outlook2010---文件---信息---账户设置---选中要设置的帐号---双击点选要设置的邮箱---其他设置---高级---在服务器上保留邮件的副本---14天后删除服务器上的邮件副本,修改 ...