一、算法简介

Adaboost算法是一种集成算法,所谓集成算法就是将多个弱的分类器组合在一起变成一个强的分类器。弱分类器通常是指分类效果比随机分类稍微好一点的分类器。就像我们在做一个重要决定的时候,通常会请教多个人的意见而不是一个人的意见,我们会综合考虑多个方面最终才会下决定。假如此时远处走来一个人,你要判断他是否是你的朋友。这时候你会从他的穿着,身高,走路姿势等多个特征来进行判断,如果仅仅是看其中一个特征都是很难做出正确判断的。这就是adaboost算法的主要思想了,下面我们来看一看计算机是怎样实现这个过程的。

二、算法原理

实现adaboost算法的基分类器有很多中,这里我们采用单层决策树作为基分类器。因为只有一层,这个决策树可以看成是一个树桩。首先我们对所有样本赋予1/n的权重,然后构建一个单层分类器,使得该分类器分类效果最好。假如下一次我们还继续在原来的数据集上进行分类的话,那么我们选出的分类器一定和之前是一样的。所以这次我们需要对数据进行一下处理,我们改变每个样本的权重,让上一次分类错误的样本我们让它的权重高一点,这样再次训练的时候,那些被分类错误的样本被分类正确的概率就高一些。第t次迭代的权重向量Dt的计算方式如下:

如果分类正确:

如果分类错误:

a为分类器的权重:其中为分类器的错误率。迭代n次之后,我们就能得到n个分类器h(x)。接下来我们给每一个分类器赋予一个权重,然后将所有分类器组合在一起,这样我们就形成了一个最终的分类器H(x).这样分类出来的效果是不是类似于将数据集所在的(超)平面分成了许多个小区域呢。在理论上可以证明这样做是合理的,下面我们通过一个简单例子对adaboost算法过程进行说明。

首先我们可以举一个例子,这是一个一维特征的数据。假如按照上述分类之后得出的结果如下,共有三个分类器,分别为以7,13,19作为阈值。箭头所指向的方向表示的是被分类为+1的区域,数字代表分类器的权重。以把7作为阈值的那个分类器为例,当分类的样本x小于7的时候,它就被分类成+1而大于7的时候它就会被分类成-1.这样就有了三个分类器h1,h2,h3,接下来我们把这三个分类器进行整合。方法如下:当x小于7的时候,h1(x)=0.5,h2(x)=-0.3,h3(x)=0.4,因此H(x)=sign(h1(x)+h2(x)+h3(x))=sign(0.6)=1.所以小于7的点就被分类成+1,同理可以计算其他区域的分类结果。如果数据在更高维度上,计算方式也类似。到这里,对于adaboost算法的工作过程应该能够理解清楚了。

接下来本来打算再从数学上说明为什么这样做,但是因为网上已经有大量的相关知识,而且公式编辑的过程太过复杂,因此这一步就省掉了。如果希望深入了解其中的数学推导过程,我建议参考一下周志华《机器学习》p172,其中解释地非常详细,也很容易明白。

三、adaboost算法的应用

为了检验adaboost算法的效果,我们需要将该算法应用到实际数据上。这里我找了一个利用声呐判断物体的数据集,其中包含208个样本,每个样本都有60个特征,分别表示从60个不同的角度测出的回声强度。由于数据集中在一起,因此我们首先向数据进行随机打乱,然后选择其中的160个作为训练集,另外48个作为测试集。这里选了迭代次数为1000次,多次修改迭代次数之后,测试的错误为16%左右。这个结果对该数据集来说已经非常不错了,据网上所说该数据集的准确率在其他算法上一般为为60-70%左右。

Roc曲线如下:

四、程序python代码

from numpy import *

def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#对数据进行分类,根据阈值划分数据
    retArray = ones((shape(dataMatrix)[0],1))
    if threshIneq == 'lt':
        retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
    else:
        retArray[dataMatrix[:,dimen] > threshVal] = -1.0
    return retArray

def buildStump(dataArr,classLabels,D):#弱分类器的构建,基于输入的权重向量寻找最好错误率最小的分类方法
    dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
    m,n = shape(dataMatrix)
    numSteps = 10.0; bestStump = {}; bestClasEst = mat(zeros((m,1)))#设定步数,建立存储最好决策树的空字典
    minError = 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):#循环步数,阈值循环
            for inequal in ['lt', 'gt']: #对于阈值我们并不知道是设定大于或者小于阈值为-1哪种效果好,因此需要对两种情况讨论,取最好的方法
                threshVal = (rangeMin + float(j) * stepSize)#阈值
                predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)
                errArr = mat(ones((m,1)))
                errArr[predictedVals == labelMat] = 0
                weightedError = D.T*errArr  #
                #print("split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError))
                if weightedError < minError:#判断错误率是否下降,若下降则更新分类字典。直到找到最好的哪个
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump,minError,bestClasEst

def adaBoostTrainDS(dataArr,classLabels,numIt=40):#迭代次数默认为40
    weakClassArr = []
    m = shape(dataArr)[0]
    D = mat(ones((m,1))/m)   #初始化权重值
    aggClassEst = mat(zeros((m,1)))
    for i in range(numIt):
        bestStump,error,classEst = buildStump(dataArr,classLabels,D)#构件简单树
        #print "D:",D.T
        alpha = float(0.5*log((1.0-error)/max(error,1e-16)))#计算alpgha,同时控制其下溢为0
        bestStump['alpha'] = alpha  
        weakClassArr.append(bestStump)                  #把树存储到分类器中
        #一下用于计算样本权重值
        expon = multiply(-1*alpha*mat(classLabels).T,classEst) #exponent for D calc, getting messy
        D = multiply(D,exp(expon))                              #Calc New D for next iteration
        D = D/D.sum()
        #计算所有分类器的错误数
        aggClassEst += alpha*classEst
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
        errorRate = aggErrors.sum()/m
        if errorRate == 0.0: break
    return weakClassArr,aggClassEst

def adaClassify(datToClass,classifierArr):
    dataMatrix = mat(datToClass)
    m = shape(dataMatrix)[0]
    aggClassEst = mat(zeros((m,1)))
    for i in range(len(classifierArr)):
        classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],\
                                 classifierArr[i]['thresh'],\
                                 classifierArr[i]['ineq'])#此处在书中版本可能出现问题,需要在[i]前面加[0]
        aggClassEst += classifierArr[i]['alpha']*classEst
        #print(aggClassEst)
    return sign(aggClassEst)

def plotROC(predStrengths, classLabels):
    import matplotlib.pyplot as plt
    cur = (1.0,1.0) #cursor
    ySum = 0.0 #variable to calculate AUC
    numPosClas = sum(array(classLabels)==1.0)
    yStep = 1/float(numPosClas); xStep = 1/float(len(classLabels)-numPosClas)
    sortedIndicies = predStrengths.argsort()#get sorted index, it's reverse
    fig = plt.figure()
    fig.clf()
    ax = plt.subplot(111)
    #loop through all the values, drawing a line segment at each point
    for index in sortedIndicies.tolist()[0]:
        if classLabels[index] == 1.0:
            delX = 0; delY = yStep;
        else:
            delX = xStep; delY = 0;
            ySum += cur[1]
        #draw line from cur to (cur[0]-delX,cur[1]-delY)
        ax.plot([cur[0],cur[0]-delX],[cur[1],cur[1]-delY], c='b')
        cur = (cur[0]-delX,cur[1]-delY)
    ax.plot([0,1],[0,1],'b--')
    plt.xlabel('False positive rate'); plt.ylabel('True positive rate')
    plt.title('ROC curve for AdaBoost horse colic detection system')
    ax.axis([0,1,0,1])
    plt.show()
    print("the Area Under the Curve is: ",ySum*xStep)

from adaboost import*
def loadDataSet1(fileName):
    dataMat=[];labelMat=[];data=[]
    fr=open(fileName)
    for line in fr.readlines():
        line=line.replace(',','\t')#去除逗号
        line=line.replace('M','-1')#对标签进行替换
        line=line.replace('R','1')
        lineArr=line.strip('\n').split('\t')
        data.append([float(lineArr[i]) for i in range(len(lineArr))])
    random.shuffle(data)  #随机打乱列表
    for i in range(len(data)):
        dataMat.append(data[i][0:len(data[1])-1])
        labelMat.append(data[i][-1])
    dataMat=matrix(dataMat)*100#将所有元素都放大100倍
    labelMat=labelMat
    return dataMat,labelMat
def test(testArr,testLabel,classifyArr):
    errors=0
    for i in range(len(testArr)):
        predictVal=adaClassify(testArr[i],classifyArr)
        if predictVal!=testLabel[i]:
            errors+=1
    rate=errors/len(testArr)
    return rate

def getTrainTestData(dataMat,labelMat):
    '''
    trainData=dataMat[0:100];trainLabel=labelMat[0:100]#前160个数据
    testData=dataMat[100:len(dataMat)];testLabel=labelMat[100:len(dataMat)]#后48个数据
    '''
    trainData=dataMat[0:160];trainLabel=labelMat[0:160]#前208个数据
    testData=dataMat[160:len(dataMat)];testLabel=labelMat[160:len(dataMat)]#后48个数据
    return trainData,trainLabel,testData,testLabel

dataArr,labelArr=loadDataSet1('Sonar.txt')
trainData,trainLabel,testData,testLabel=getTrainTestData(dataArr,labelArr)
classifyArr,aggClassEst=adaBoostTrainDS(trainData,trainLabel,numIt=100)
#l=adaClassify(testData[1],classifyArr)
rate=test(testData,testLabel,classifyArr)
print(rate)
plotROC(aggClassEst.T,labelArr)#绘制roc曲线

参考文献:

[1]Adaboost入门教程——最通俗易懂的原理介绍(图文实例)

https://blog.csdn.net/px_528/article/details/72963977

[2] 机器学习实战 peter Harrington

[3] 周志华《机器学习》

机器学习笔记·adaboost的更多相关文章

  1. Python机器学习笔记:sklearn库的学习

    网上有很多关于sklearn的学习教程,大部分都是简单的讲清楚某一方面,其实最好的教程就是官方文档. 官方文档地址:https://scikit-learn.org/stable/ (可是官方文档非常 ...

  2. Python机器学习笔记 集成学习总结

    集成学习(Ensemble  learning)是使用一系列学习器进行学习,并使用某种规则把各个学习结果进行整合,从而获得比单个学习器显著优越的泛化性能.它不是一种单独的机器学习算法啊,而更像是一种优 ...

  3. 机器学习笔记:Gradient Descent

    机器学习笔记:Gradient Descent http://www.cnblogs.com/uchihaitachi/archive/2012/08/16/2642720.html

  4. 机器学习笔记5-Tensorflow高级API之tf.estimator

    前言 本文接着上一篇继续来聊Tensorflow的接口,上一篇中用较低层的接口实现了线性模型,本篇中将用更高级的API--tf.estimator来改写线性模型. 还记得之前的文章<机器学习笔记 ...

  5. 机器学习之AdaBoost原理与代码实现

    AdaBoost原理与代码实现 本文系作者原创,转载请注明出处: https://www.cnblogs.com/further-further-further/p/9642899.html 基本思路 ...

  6. Python机器学习笔记:使用Keras进行回归预测

    Keras是一个深度学习库,包含高效的数字库Theano和TensorFlow.是一个高度模块化的神经网络库,支持CPU和GPU. 本文学习的目的是学习如何加载CSV文件并使其可供Keras使用,如何 ...

  7. Python机器学习笔记:不得不了解的机器学习面试知识点(1)

    机器学习岗位的面试中通常会对一些常见的机器学习算法和思想进行提问,在平时的学习过程中可能对算法的理论,注意点,区别会有一定的认识,但是这些知识可能不系统,在回答的时候未必能在短时间内答出自己的认识,因 ...

  8. 机器学习笔记(4):多类逻辑回归-使用gluton

    接上一篇机器学习笔记(3):多类逻辑回归继续,这次改用gluton来实现关键处理,原文见这里 ,代码如下: import matplotlib.pyplot as plt import mxnet a ...

  9. 【转】机器学习笔记之(3)——Logistic回归(逻辑斯蒂回归)

    原文链接:https://blog.csdn.net/gwplovekimi/article/details/80288964 本博文为逻辑斯特回归的学习笔记.由于仅仅是学习笔记,水平有限,还望广大读 ...

随机推荐

  1. js日期格式化-----总结

    1. // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分(m).秒(s).季度(q) 可以用 1-2 个占位符, // 年(y)可以用 1-4 ...

  2. git-服务器搭建-协议概念

    现在开发过程中,很多的实现某一些功能的工具,都是类似的服务器-客户端结构,即C-S架构,例如消息队列的KAFKA,文件存储的EasticSearch,包括我们日常工作中的数据库,他都是一种C-S架构, ...

  3. OS第六章

    OS第七次实验 多进程 添加一个进程体 添加进程B,首先设置i的初值为0x1000,这样来方便程序运行时的时候能区分.其余地方与A一致. 相关变量和宏 Minix中定义了一个数组,叫做tasktab的 ...

  4. Kafka高性能的原理

    Kafka高性能的原理 高性能,高并发,高可用 使用了NIO技术.高并发. 顺序读写.硬盘的顺序读写性能要高于内存的随机读写. 跳表设计. 稀疏索引.index文件里面有部分offset的位置. 使用 ...

  5. XCTF EasyHook

    无壳,使用IDA直接分析主函数 逻辑很简单,问题的关键是Hook,题目也是EasyHook, 会发现在生成文件后,文件内容是被加密后的,那就怀疑加密函数参与Hook 动态调试一步步来看,先进入4012 ...

  6. Azure Service Bus(二)在NET Core 控制台中如何操作 Service Bus Queue

    一,引言 上一篇讲到关于 Azure ServiceBus 的一些概念,讲到 Azure Service Bus(服务总线),其实也叫 "云消息服务",是微软在Azure 上提供的 ...

  7. 用python写图片格式批量处理工具

    一.思路分析 其实,照片处理要求很简单,主要是两个方面:一个是调整图片尺寸(即宽x高),另一个是调整图片的大小(即压缩).为了实现这两个功能,利用python中的PIL库即可,其安装方法如下: pip ...

  8. SonarQube - 以Docker方式启动SonarQube

    1 - SonarQube镜像 https://hub.docker.com/_/sonarqube/ Dockerfile - 7.9.1-community https://github.com/ ...

  9. [LeetCode]86. Partition List分离链表

    /* 这个题是medium的意思应该是用双指针的方法做,如果使用下边的新建链表的方法,就是easy的题目了 双指针会用到很多链表的相连操作 */ public ListNode partition(L ...

  10. [leetcode]114. Flatten Binary Tree to Linked List由二叉树构建链表

    /* 先序遍历构建链表,重新构建树 */ LinkedList<Integer> list = new LinkedList<>(); public void flatten( ...