Adaboost的简单实现

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

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


#coding= utf-8

from 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()
 


猜你喜欢

转载自blog.csdn.net/qq_27157975/article/details/77575120
今日推荐