Adaboost的简单实现

来源:互联网 发布:java将双引号替换空格 编辑:程序博客网 时间:2024/06/06 00:01

  Adaboost在实现上并不困难,这里主要是参考的李航老师的《统计机器学习》和《机器学习实战》内容。

简单来说,先有个简单的二分类器,可以将数据分成两部分,目标变量值分别是-1和1。然后就用公式更新权值,一直计算就行了。


#coding= utf-8from numpy import *def loadSimpData():    datMat = mat([[ 1. ,  2.1],                  [ 2. ,  1.1],                  [ 1.3,  1. ],                  [ 1. ,  1. ],                  [ 2. ,  1. ]])    classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]    return datMat,classLabels"""#单层决策树分割数据的方法(不同于普通决策树的分类,单层决策树在分类过程中并没有复杂的选取最优特征进行分类)#:dataMat:数据集;dimen:特征位置(也就是数据集的第几列);threshVal:阈值;threshIneq:阈值选择模式#r:预测值"""def stumpClassify(dataMat, feature, threshVal, threshIneq):    m = shape(dataMat)[0]    retArray = ones((m, 1))    #阈值的模式,将小于某一阈值的特征归类为-1(单层决策树的目标变量的值为-1和0,    #由于上面初始化时retArray的初值为1,所以这里只需要将一些位置赋值-1即可)    if threshIneq=='lt':        retArray[dataMat[:,feature]<=threshVal]=-1.0  #这里使用了布尔数组索引方法    #将大于某一阈值的特征归类为-1    else:        retArray[dataMat[:,feature]>threshVal]=-1.0    return retArray"""#构建单层决策树#:dataMat:数据集;classLabels:标签值(目标变量值);D:最初的权值#r:最佳单层决策树相关信息的字典;最小错误率;决策树预测输出结果"""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):#遍历各个步长区间;这里由于range()会不包括右端的数,所以要加1            #以下过程就是把所有的阈值都取一遍,看看哪个效果最好            for inequal in ['lt', 'gt']: #两种阈值过滤模式                threshVal = (rangeMin + float(j) * stepSize)  #阈值的求法;由于与阈值比较时使用大于,所以为了防止出现所有值都是同一个值的情况,所以使用-1                predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)                errArr = mat(ones((m,1)))                errArr[predictedVals == labelMat] = 0 #这里使用布尔数组进行赋值,predictedVals == labelMat形成布尔数组,                                                      # 所产生的效果就是两者相同的位置赋0值                weightedError = D.T*errArr  #将权值矩阵乘以误差矩阵,就可以得到权值误差                                            #(也就是筛选出有错误的位置的权值,把没有错误的位置的权值置0,然后加起来求和)                if weightedError < minError:                    minError = weightedError                    bestClasEst = predictedVals.copy()                    bestStump['dim'] = i  #最好的特征列数                    bestStump['thresh'] = threshVal  #最好的阀值                    bestStump['ineq'] = inequal #最好的阈值的模式    return bestStump,minError,bestClasEst  #返回最佳单层决策树相关信息的字典,最小错误率,决策树预测输出结果#@dataArr:数据矩阵#@classLabels:标签向量#@numIt:迭代次数"""#算法主体(基本可参考李航p138到p139的公式即可)#:dataArr:数据集;classLabels:标签值(目标变量值);numIt:迭代次数#r:弱分类器的组合列表"""def adaBoostTrainDS(dataArr,classLabels,numIt=40):    #弱分类器相关信息列表    weakClassArr=[]    #获取数据集行数    m=shape(dataArr)[0]    #初始化权重向量的每一项值相等    D=mat(ones((m,1))/m)    #累计估计值向量    aggClassEst=mat((m,1))    #循环迭代次数    for i in range(numIt):        #根据当前数据集,标签及权重建立最佳单层决策树        bestStump,error,classEst=buildStump(dataArr,classLabels,D)        # print("D:",D.T)        #求单层决策树的系数alpha        alpha=float(0.5*log((1.0-error)/(max(error,1e-16))))  #这里使用1e-16是为了防止分母为0的情况        #存储决策树的系数alpha到字典        bestStump['alpha']=alpha        #将该决策树存入列表        weakClassArr.append(bestStump)        #打印决策树的预测结果        # print("classEst:",classEst.T)        #预测正确为exp(-alpha),预测错误为exp(alpha),即增大分类错误样本的权重,减少分类正确的数据点权重        #这里的公式可参考李航机器学习p139(8.4);这里的expon就是为了使式子更有可读性        expon=multiply(-1*alpha*mat(classLabels).T,classEst)        #更新权值向量        D=multiply(D,exp(expon))        D=D/D.sum() #除以求和是为了规范化        #累加当前单层决策树的加权预测值        aggClassEst=aggClassEst + alpha*classEst        endClass = sign(aggClassEst)        print "endClass",endClass.T        #求出分类错的样本个数        aggErrors=multiply(sign(aggClassEst)!= mat(classLabels).T,ones((m,1)))        #计算错误率        errorRate=aggErrors.sum()/m        print "total error:",errorRate        #错误率为0.0退出循环        if errorRate==0.0:break    #返回弱分类器的组合列表    return weakClassArr#以下是测试if __name__ == '__main__':    dataSet,label = loadSimpData()