基于单层决策树的AdaBoost算法思想分析和源代码解析

前言:

上一篇SVM可是废了我好鼻子劲,这一篇咱们来点愉快的东西。我们一定听说过这句俗语:“三个臭皮匠,顶个诸葛亮!” 大致意思就是三个能力一般的人加起来,也能抵得上一个能力很强的人。通俗意思就是人多力量大。没错,今天咱们所说的这个算法,就是利用这三个臭皮匠,去替代这个诸葛亮。
源码已上传到GitHub上,有需要的小伙伴自取:源码地址,如果有帮到你,不要吝啬你的小⭐⭐

算法原理故事:

在很久以前,有一个皇帝,由于要去邻国去洽谈生意,需要找一个武功高强、知识渊博、善于言谈的人,来跟随自己去,以此来体现本国人才济济,增加胜算。

皇帝派人贴出告示,重金求赏这么一个人才。果真,不久,便来了一个人前来面试。经过考核,此人各项能力都满足我们的要求,于是打算任用他。但是此人野心很大,深知在本国找不出第二个有如此能力之人,就狮子大张口,不仅要求皇帝给出黄金万两、而且还有当个官。皇帝自然不乐意了,给朕服务是你的荣幸,拿由得你来给朕谈条件,拖出去,斩了!die。。。。

眼看着马上就要启程了,除了上次那个人,还是没有人来面试,皇帝很着急,就在早朝询问大臣们的意见。其中有一个大臣说到,的却找到这样综合实力非常强的人比较难,那么,我们可以多去找一些人,有很多人会符合其中的某一项。皇帝连连点头。便再次贴出告示,分别寻找具有这些品质的人。

果真不久,就来了三个人,这里暂时命名为A,B,C,说自己在某一个或某两个方面比较擅长,其他方面不太擅长。为了考核A,皇帝出了一套考卷(情节需要,可能不太合适,见谅),用来检测A的能力。该试卷分为三部分,每一部分是50分。

A人在武功方面很优秀,拿到了满分50分,但后两项不太行,都只拿到了25分。

接下来,皇上将试卷做了修改,将武功方面的分数改成了30分,后两项各加了10分。

皇帝拿着改完的试卷,来考察B人。

B人在知识方面非常优秀,拿到了满分60分,但是其他两项稍显薄弱,分别拿到了20和30分

皇帝看到这种情况,立即对试卷又做了修改,将考察言谈的部分增加到了80分,其他两项个35分。

皇帝拿着这套试卷去考察C人。

C人在言谈方面可所谓相当优秀了,拿到了75分的超高分,其他两项也都拿到了25分。

皇帝对于这三个人非常满意,都在某一项能力中有出众的表现。并针对他们在测试中的分数表现,对于他们的信任程度,也是不一样的,其中对于C人的信任度最高。

最后皇帝带着这三个人去谈判,顺利的谈成了生意。

算法原理解读

上面这个故事我不知道大家看的怎么样, 如果你完整的看下去了,那么,恭喜你,对于本篇adaBoost算法的原理你已经明白了!什么?这么容易? 没错,不信接着看!

我前面也总结了几个机器学习的分类算法,怎么说呢,精度越高,其算法就越复杂。业界公认最好的分类模型SVM支持向量机,我硬是磨了快两个月才弄个差不多。

也就是精度比较弱的分类器的实现要比精度高的分类器实现起来要简单很多,不信让你写个SVM和让你写个线性回归,你试试?

而几个弱分类器经过组合,他们可以组成一个强分类器。是不是有点臭皮匠顶诸葛亮的味儿了。

1. 弱分类器-单层决策树

这里,我们使用的弱分类器为单层决策树。决策树它是按照其属性分类后信息熵的变化来选择决策树的枝干的。这里我们只是使用一层,也就是只针对一个属性来进行。

总的思路如下:

  1. 循环数据集中的每一个特征(第一层循环):

    1. 对于每个步长(第二层循环):

      1. 对于每个不等号(第三层循环):

        1. 建立一个单层决策树并利用加权数据集对它测试
        2. 如果错误率抵御minError(初始值为无穷大),则将当前单层决策树设为最佳单层决策树
  2. 返回单层决策树

看不懂没关系,咱们举个例子:

我们手上有五个数据,数据详情如下:

x1(属性) x2(属性) y(类别)
1 2 -1
3 1 1
2 4 1
3 2 1
1 3 -1

我们需要提前初始化数据权值向量D(0.2,0.2,0.2,0.2,0.2),使其总和为1即可。

咱们看第一层循环,第一层循环是对属性的循环,首先对属性x1进行循环

我们设定的步数为10,步长=(max(x1)-min(x1))/10=0.2

也就是对于第二步循环,我们需要循环11次,从小于最小值开始【(1-0.2)~ (1+10*0.2)】。

然后进入第三层循环,这一循环是对于每个不等式:这个怎么理解呢,在我们第二步中,每增加一次循环,其步长都会加1,这样的目的就是为了让我们能够将小于这个值的分为一类,大于这个值的分为另一类。由于不知道小于这个值应该分为哪一类,那我们都进行尝试,所在在这个不等式循环中,需要循环两次,用来处理这种情况。

假设我们循环到第二步的第六个步长了,当前值为1+6x0.2=2.2.我们在第三层循环中,先将小于2.2的值归为-1类,那么剩下的归为1类。此时,我们统计与源标签不一致的情况,对照原数据,我们发现第三个属性值为(2,4)的数据标签出现了点问题。我们就计算错误值=出错的数据对应的权值之和=0.2

所以,第三步的第一次循环中,我们所采用的单层决策树的错误值为0.2.

在第三步的另一个循环中,我们将小于2.2的值归为1类,剩下的归为-1类,此时出错的数据有4个,那么对应的错误值为0.8.

每次循环我们都会记录当前错误值最小的单层决策树,直到所有循环完毕,将返回错误值最小的单层决策树。

2. 单层决策树AdaBoost算法完整思路

从上面那一步,我们能够获得当前数据权值D下的最佳单层决策树,那么,这一部分呢,我们就会对相关参数进行迭代优化。

此步步骤大致如下:

  1. 对每次迭代:

    1. 利用1方法找到最佳的单层决策树
    2. 将最佳单层决策树加入到单层决策树数组
    3. 计算alpha
    4. 计算新的权值向量D
    5. 更新累计类别估计值
    6. 如果错误率等于0,退出循环

上述方法中,alpha是这些选出来的单层决策树的权值,也就是对最终结果的话语权。咱们拿出前面讲的故事,来这些步骤进行一一对应。

我们的目的,就是完美无误的将数据分类完毕<---->皇帝需要找一个武功高强、知识渊博、善于言谈的高人辅助自己完成生意谈判。

迭代中:

方法1找到的最佳单层决策树<---->皇帝发现A人在武功方面很优秀,就留了下来。

计算alpha<---->皇帝根据其测试的成绩,成绩越高,皇帝越信任他。

计算新的权值向量D,也就是提高这个决策树分类错误的数据权值<---->皇帝在测试完A人之后,提高了知识和言谈的所占分数。

更新累计类别估计值<----->当前所获人才水平

错误率为0<----> 皇帝对当前的人才水平非常满意,已达到期望值,可以前去谈判生意。

如果还有不明白的地方,我就用我的理解再陈述一下吧:

此方法就是通过寻找当前数据权值下,对数据分类表现最好的弱分类器,并且根据这个弱分类器分类错误的数据,提到其对应的数据权值,以此来找到能对上一个分类器分类错误的数据有很好表现得分类器。这样就能够达到缺什么补什么,后者优势补前者劣势的情况。

算法公式

数据集:

初始化数据权值分布:

使用具有权值分布Dm训练数据集,得到基本分类器Gm(x):

计算Gm(x)在训练数据集上的分类误差率:

计算分类器Gm(x)的权值系数:

更新训练数据集的权值分布:

构建基本分类器的线性组合:

最终分类器:

基本上用到的公式就这些了,如果我将他们整理到了word文档中,如果有需要,文章留言。

算法源代码解读

1. 加载数据

我是用的数据图像分布如下:

def loadSimpData():dataMat = []labelMat = []data = open('datasets/testSet.txt')for dataline in data.readlines():linedata = dataline.split('\t')dataMat.append([float(linedata[0]),float(linedata[1])])labelMat.append(float(linedata[2].replace('\n','')))return dataMat,labelMat

将数据从文本中读取,然后按照将不同属性和分类标签进行分割,并放入不同的列表中

2. 获取单层最佳决策树

这里分为两个方法。

第一个方法是在将小于(或大于)阈值的数据归为一类:

#通过阈值比较对数据进行分类,所有在一边的将会被分类到同一类别
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):retArray = np.ones((np.shape(dataMatrix)[0],1))#创建一个初始值为1的大小为(m,1)的数组if(threshIneq=='lt'):#lt表示小于的意思retArray[dataMatrix[:,dimen]<=threshVal]=-1.0else:retArray[dataMatrix[:,dimen]>threshVal]=-1.0return retArray

第二个方法是获取最好的单层决策树:

#参数分别是 数据、数据分类、数据权重
#此方法用来获取分类效果最好的分类方式,包括分类阈值、属性值等
def buildStump(dataArr,classLabels,D):dataMatrix=np.mat(dataArr)#转化为二维矩阵,而且只适应于二维labelMat = np.mat(classLabels).T#矩阵的转置m,n = np.shape(dataMatrix)numSteps = 10.0#总步数bestStump={}#存储给定权重向量D时所得到的最佳单层决策树bestClasEst = np.mat(np.zeros((m,1)))minError = float('inf')#正无穷大for i in range(n):#第一层循环,进行两次循环,每次针对一个属性值#获取当前属性值的最大最小值rangeMin = dataMatrix[:,i].min();rangeMax = dataMatrix[:,i].max()stepSize = (rangeMax-rangeMin)/numSteps# 获取步长for j in range(-1,int(numSteps)+1):#从-1开始,#目的是解决小值标签为-1 还是大值标签为-1的问题for inequal in ['lt','gt']:threshVal = (rangeMin+float(j)*stepSize)#从-1步开始,每走一步的值predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)#根据这个值进行数据分类errArr = np.mat(np.ones((m,1)))#创建错误向量,初始值为1errArr[predictedVals==labelMat]=0#若预测的值和真实值相同,则赋值为0weightedError = D.T*errArr#权重与错误向量相乘求和print("split:dim %d, thresh %.2f,thresh inequal: %s,the weighted error is %.3f" %(i,threshVal,inequal,weightedError))if weightedError<minError:#此if语句在于获取最小的 错误权值minError = weightedErrorbestClasEst = predictedVals.copy()bestStump['dim']=ibestStump['thresh']=threshValbestStump['ineq'] = inequalreturn bestStump,minError,bestClasEst

这里的步骤和我们前面所讲的基本一样,也没有涉及到什么公式,也是挺好理解的。详细的都写在注释中了。

3. AdaBoost算法主方法

#参数分别是 数据、数据分类标签、循环次数
def adaBoostTrainDS(dataArr,classLabels,numIt=40):weakClassArr = []m = np.shape(dataArr)[0]#获取数据个数D = np.mat(np.ones((m,1))/m)#初始化数据权值aggClassEst = np.mat(np.zeros((m,1)))#for i in range(numIt):#循环bestStump,error,classEst = buildStump(dataArr,classLabels,D)#寻找最优单层决策树print('D:',D.T)#该值是说明总分类器单层决策树输出结果的权重?#le-16 作用是保证没有除0溢出错误发生alpha = float(0.5*np.log((1.0-error)/max(error,1e-16)))#eN表示10的N次方print("alpha:",alpha)bestStump['alpha'] = alphaweakClassArr.append(bestStump)print("classEst:",classEst.T)expon = np.multiply(-1*alpha*np.mat(classLabels).T,classEst)D = np.multiply(D,np.exp(expon))D = D/D.sum()#用于计算下一次迭代中的新权重向量DaggClassEst +=alpha*classEst#类别估计值#sign 函数就是二值分类函数,大于0为1 小于0 为-1aggErrors = np.array((np.sign(aggClassEst)!=np.mat(classLabels).T)*1.0)errorRate = aggErrors.sum()/m#计算错误率print("total error:",errorRate)if errorRate ==0.0:breakreturn weakClassArr

基本上涉及到公式的地方都是来自于这里。

  1. alpha更新公式。主要参数是获取的最佳决策树的它处理数据的错误值(分类错误的权值和)
  2. 数据权值向量D的更新。其参数主要是alpha。对于分类错误的数据,增大它的权值,对于分类正确的数据,我们减少其权值。再需要满足总权值和为1.只要能够满足这两个条件,那么权值D的更新公式,我认为可以有很多写法,不一定要局限于咱们前面提到的公式。
  3. 数据结果值的计算。aggClassEst 这个是将我们目前获得的最佳决策树xalpha的总和,对应这个我们前面公式的f(x)
  4. 数据分类情况。np.sign(aggClassEst)这个公式等价于前面我们的公式G(f(x))=sign(f(x)),其输出结果为最终{-1,1}的分类情况。
  5. 错误值计算。将算法计算出来的分类值和原标签值进行对比,输出错误值。

思考记录:

  1. 为什么要给数据添加权值?

在训练的过程中,针对判断错误的数据,我们增加它的权值,针对判断正确的数据,我们减少它的权值,这样就能增大判断错误的数据的影响程度。

  1. 数据权值在每次循环都会发生改变,但是累计分类结果aggclassarr采用累加方式,数据的权值到底影响着什么,只是alpha值吗?

数据的权值影响着决策树的选择。我们是通过计算错误值来选择错误值最小的单层决策树。那么,针对在上一次循环中,那些出错的数据,被给予了更高的权值,在这次循环中,它就会更倾向于在些数据上表现更好的决策树。有点缺哪补哪的意思。就好比我们像去创建一个公司,一开始我们只有两个干活的人,但是到了交税的时候,发现缺少这样的人,那么,我们就去找个懂财务的。

  1. 为什么训练的时候需要用到数据权值D,而测试的时候,只使用alpha的值就可以了?

说白了,数据权值的作用就是查漏补缺用的,就是找到能够弥补前面模型不足的模型,也就是书中举的例子: “三个臭皮匠,顶个诸葛亮!”

总结:

原来我们语文老师教的“三个臭皮匠,顶个诸葛亮”,还真的用到了算法中了。真的是学术无界呀。我们以前学的都是,都是在为我们之后打基础,好好学习基础学科吧。更多有疑问或者讲解不恰当的地方,欢迎大家留言讨论!

基于单层决策树的adaBoost算法思想分析和源代码解析相关推荐

  1. eclipse的jsp第一行代码报错_机器学习之AdaBoost算法及纯python代码手工实现

    Adaboost算法是boost算法中最具代表性的一个,它是adaptive boosting的简称(自使用算法);在训练数据中的每个样本赋予一个权重,构成初始的向量D(每个样本的权重初始时均相等). ...

  2. 机器学习算法——利用AdaBoost元算法提高分类性能(基于单层决策树构建的弱分类器)

    当做出重要决定时,我们往往会听取多个专家而不只是一个人的意见.元算法正是采用这种思路,元算法是对其他算法进行组合的一种方式,本篇博文主要介绍AdaBoost元算法,该算法是机器学习工具箱中最强有力的工 ...

  3. 集成算法--AdaBoost算法【含python代码】

    1. 基于数据集多重抽样的分类器 将不同的分类器组合起来,称为集成算法(ensemble method) 或者 元算法(meta-algorithm).使用集成算法会有多种形式:可以是不同算法的集成, ...

  4. Adaboost算法原理分析和实例+代码(简明易懂)

    Adaboost算法原理分析和实例+代码(简明易懂) [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333   ...

  5. Adaboost算法原理分析和实例+代码(转载)

    [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333     本人最初了解AdaBoost算法着实是花了几天时 ...

  6. 利用计算机语言实现ID3算法,机器学习之决策树学习-id3算法-原理分析及c语言代码实现.pdf...

    机器学习之决策树学习-id3算法-原理分析及c语言代码实现.pdf 还剩 23页未读, 继续阅读 下载文档到电脑,马上远离加班熬夜! 亲,很抱歉,此页已超出免费预览范围啦! 如果喜欢就下载吧,价低环保 ...

  7. 道家·老子的算法思想分析

    道家·老子的算法思想分析 在前一篇文章"屈原·渔父的算法追求"中谈到,屈原追求的是高效的算法,而渔父追求的是高可靠性的算法. 对于屈原与渔父的思想,后人通常认为屈原反映了儒家杀身成 ...

  8. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  9. 视觉SLAM开源算法ORB-SLAM3 原理与代码解析

    来源:深蓝学院,文稿整理者:何常鑫,审核&修改:刘国庆 本文总结于上交感知与导航研究所科研助理--刘国庆关于[视觉SLAM开源算法ORB-SLAM3 原理与代码解析]的公开课. ORB-SLA ...

最新文章

  1. Scala Spark Streaming + Kafka + Zookeeper完成数据的发布和消费
  2. linux文件指令 例子,Linux 命令:文件目录操作与实例
  3. 时间约束的实体解析中记录对排序研究
  4. python random库怎么用_Python || Random库的使用
  5. Lucene入门与使用(一) [转]
  6. (十) 一起学 Unix 环境高级编程 (APUE) 之 线程控制
  7. 【支付宝】支付宝ISV申请方法
  8. 开发板实战篇4 RGB565 LCD刷颜色数据
  9. win10系统CAJViewer 绿色提示缺少由于找不到 MSVCR71.dll
  10. 基于STM32平台的数字温度显示器系统设计
  11. icloud备份微信聊天记录怎么恢复
  12. 苹果ios用js的Date() 获取到的日期时间 显示NaN
  13. 7-2 程序改错题4 (5 分)
  14. 【语音唤醒】MDTC:Multi-scale dilated temporal convolutional network
  15. Kafka学习征途:.NET Core操作Kafka
  16. ov5640帧率配置_《使命召唤 黑色行动 冷战》详细PC配置需求公布
  17. python爬取 过去的微博热搜(热搜神器)
  18. 认识Axure RP
  19. 好的大创计算机类课题,年电信学院大创项目选题清单.xlsx
  20. 阿里云mysql测试_MySQL主主测试-阿里云开发者社区

热门文章

  1. win10 docker部署gpu项目
  2. 程序设计入门C语言 --- 素数和
  3. 基于海思AI芯片的智能视频分析边缘网关
  4. 腾讯云 视频通话SDK 第一个坑 域名要开https
  5. h5 底部按钮兼容 iPhone X(解决底部横杠遮挡问题)
  6. 【JAVA 学习笔记】HashMap 探究
  7. 关于BCB的安装过程
  8. vue 移动端头像裁剪_移动端 上传头像 并裁剪功能(h5)
  9. 基于用户体验的手机产品交互设计原则
  10. 【论文翻译】3461 AdderSR Towards Energy Efficient Image Super-Resolution(个人粗略翻译)