天天看点

提升和加法树及AdaBoost算法总结提升方法概述AdaBoost算法指数损失函数和AdaBoost提升树模型数值优化adaBoost算法代码

提升方法概述

一个弱分类器的误差率只比随机猜测好一些,提升的目的就是连续对反复修改的数据应用弱分类算法,由此产生一个弱分类器序列 Gm(x) , m=1,2,3...M ,然后通过一个加权的多数表决来合并全部预测,以产生最终预测

G(x)=sign(∑Mm=1αmGm(x))

这里, αm 由提升方法来计算,它们的作用是对序列中较精确的分类器给予较高的影响。

在每个提升步,数据修改就是对每一训练观测 (xi,yi) 实施加权 wi ,开始,所有权都置成 wi=1/N ,以便第一步能够简单地用通常的方式在数据上训练分类。对每一个相继的迭代 m=2,3...M ,观测的权值被分别修改,并且分类算法被再次应用于加权观测。在第 m 步,那些被前一步导出的分类器Gm−1(x)误分类的观测权值提高,而被正确分类的观测权值降低。这样,随着迭代的进行,那些很难正确分类的观测受到了不断增长的影响。因此,每个后继分类器被强制关注被前面的分类器误分类的训练观测。

AdaBoost算法

算法流程如下:

1.初始化观测权值 wi=1/N,i=1,2...N

2.对于 m=1 到 M :

(a)使用权值wi,用分类器 Gm(x) 拟合数据

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

em=P(Gm(xi)!=yi)=∑Ni=1wmiI(Gm(xi)!=yi)

(c)计算 Gm(x) 的系数

αm=12∗log1−emem

(d)更新训练数据的权值分布

Dm+1=(wm+1,1,...wm+1,N)

wm+1,i=wmiZmexp(−αmyiGm(x)),i=1,2...N

这里,Z_m是规范化因子

Zm=∑Ni=1wmiexp(−αmyiGm(x))

它使得 Dm+1 成为一个概率分布

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

f(x)=∑Mm=1αmGm(x)

得到最终分类器

G(x)=sign(f(x))

由 αm=12∗log1−emem 可以看出,分类误差率越小的基本分类器在最终分类器中的作用越大

在每一次迭代过程中,训练数据的权值更改

wm+1,j={wmiZmexp(−αm),wmiZmexp(αm),Gm(xi)=yiGm(xi)!=yi

也就是说被基本分类器误分类的样本权值扩大,正确分类的样本权值缩小

指数损失函数和AdaBoost

AdBoost算法等价于使用以指数函数为损失函数的加法模型,AdaBoost算法是前向分步加法算法的特例。

提升树模型

提升方法实际采用加法模型与前向分步算法,以决策树为基函数的提升方法成为提升树。

二类分类问题的提升树算法

对于二类分类问题,提升树算法只需将AdaBoost算法中的基本分类器限制为二类分类树即可。以一个结点的决策树为例,即决策树桩为例,

决策树桩由三部分组成,特征,特征值,不等号的方向,代码见最后

回归问题的提升树算法

采用平方损失的回归树算法流程如下:

1.初始化 f0(x)=0

2.对 m=1,2,3...M

(a)计算残差 rmi=yi−fm−1(xi),i=1,2...N

(b)拟合残差 rmi 学习一个回归树,得到 T(x;Θ)

(c)更新 fm(x)=fm−1(x)+T(x;Θ)

3.得到回归问题提升树

fM(x)=∑Mm=1T(x;Θ)

数值优化

上面限定了损失函数并限定了加法模型为树之和,考虑任意损失函数L(x)和任意加法模型f(x)

损失为

L(f)=∑Ni=1L(yi,f(xi)) (A)

对上式进行极小化可以看做是一种数值优化

f^=argminfL(f) (B)

其中,“参数” f∈IRN 是逼近函数 f(xi) 在N个数据点上的函数值:

f={f(x1),f(x2)...f(xN)}

数值优化的过程函数求解(B)式作为分量向量的和

fM=∑Mm=0hm,hm∈IRN

其中 f0=h0 是初始猜测,每个后继的 fm 都是根据当前的参数向量 fm−1 得到的,而 fm−1 是前面导出的向量之和,数值优化方法在计算每个增量向量 hm 上是不同的。

最速下降法

最速下降选择的是 hm=−ρmgm ,其中 ρm 是一个标量,而 gm∈IRN 是在 f=fm−1 处计算的 L(f) 的梯度。梯度 gim 的分量是

gim=[∂L(yi,f(xi)∂f(xi)]f(xi)=fm−1(xi)

步长 ρm 是下式的解

ρm=argminρ L(fm−1−ρgm)

接着,当前解被更新为

fm=fm−1−ρgm

并在下一次迭代过程中重复该过程。最速下降法可以看做是一个非常贪心的策略,因为 −gm 是 IRN 中的一个局部方向,在此方向上, L(f) 在 f=fm−1 上下降最快。

梯度提升

逐步前向提升也是一种非常贪心的策略。在每一步,给定当前的模型 fm−1 和它的拟合 fm−1(xi) ,解树是下式的解

Θ^m=argminΘm∑Ni=1 L(yi,fm−1+T(xi;Θm)) (C)

这样,树预测 T(xi;Θm) 类似于负梯度的分量。两者主要的不同在于树分量不是独立的。他们被限制为一个决策树的预测,而负梯度是无约束的最大下降方向。

如果极小化训练数据上的损失是唯一目的,则最速下降将是最可取的策略。对于任意可微的损失函数,梯度的计算是平凡的,而直接求解式(C)是困难的。然而,梯度仅定义在训练数据点 xi 上,而最终的目标是将 fM(x) 拓广到不在训练集中出现的新数据。

解决这个问题的可能方法是在第m次迭代时引进一棵树 T(xi;Θm) ,使得它的预测 tm 与负梯度尽可能接近。使用平方误差来度量接近程度,即

Θ^=argminΘ∑Ni=1(−gim−T(xi;Θ))2

即我们通过最小平方误差将树T拟合到负梯度值。这里就可以用上面说到的损失函数为平方误差的树回归算法了,负梯度称作广义或伪残差r。

adaBoost算法代码

from numpy import *


# adaBoost算法
# 决策树桩仅分裂一次,也就是说只选择一次特征
# 决策树桩由三部分组成,特征,特征值,不等号的方向


# 读入数据
def loadData():
    dataMat = matrix([[ , ],
                     [ , ],
                     [,  ],
                     [ ,  ],
                     [ ,  ]])
    classLabels = matrix([, ,-, -, ]).T
    return dataMat, classLabels


# 根据当前树桩对数据进行分类
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
    retArray = ones((shape(dataMatrix)[], ))
    if threshIneq == 'lt':
        retArray[dataMatrix[:, dimen] <= threshVal] = -
    else:
        retArray[dataMatrix[:, dimen] > threshVal] = -
    return retArray


# 构造弱分类器,即决策树桩
# D为数据权重向量
# numStep是步数,据此可算出步长, bestClassEst是最优情况下的分类情况
def buildStump(dataMatrix, classLabels, D):
    m, n = shape(dataMatrix)
    numStep = 
    bestStump = {}
    minError = inf
    bestClasEst = mat(ones((m, )))
    for i in range(n):
        rangeMin = dataMatrix[:, i].min()
        rangeMax = dataMatrix[:, i].max()
        stepSize = (rangeMax-rangeMin)/numStep
        for j in range(-, int(numStep)+):
            threshVal = rangeMin + j*stepSize
            for inequal in ['lt', 'rt']:
                predictVals = stumpClassify(dataMatrix, i, threshVal, inequal)
                errArr = mat(ones((m, )))
                errArr[predictVals == classLabels] = 
                weightedError = D.T*errArr
                if weightedError < minError:
                    minError = weightedError
                    bestClassEst = predictVals
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump, minError, bestClassEst


# adaBoost训练过程
def adaBoostTrain(dataMatrix, classLabels, numIter=):
    weakClassArr = []
    m = shape(dataMatrix)[]
    D = mat(ones((m, ))/m)
    aggClassEst = mat(zeros((m, )))
    for i in range(numIter):
        bestStump, error, classEst = buildStump(dataMatrix, classLabels, D)
        # 防止除以零溢出
        alpha = float(*log((-error)/max(error, )))
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        expon = multiply(-*alpha*classLabels, classEst)
        D = multiply(D, exp(expon))
        D /= D.sum()
        aggClassEst += alpha*classEst
        # 比较两个矩阵的值得出预测正误情况
        aggError = sign(aggClassEst) != classLabels
        errorRate = aggError.sum()/m
        if errorRate == :
            break
    return weakClassArr

def adaClassify(dataMatrix, classifierArr):
    m = shape(dataMatrix)[]
    aggClassEst = mat(zeros((m, )))
    for i in range(len(classifierArr)):
        stump = classifierArr[i]
        classEst = stumpClassify(dataMatrix, stump['dim'], stump['thresh'], stump['ineq'])
        aggClassEst += stump['alpha']*classEst
    return sign(aggClassEst)

dataMat, classLabels = loadData()
classifiers = adaBoostTrain(dataMat, classLabels, )
labels = adaClassify(mat([, ]), classifiers)
print(labels)





           

继续阅读