机器学习算法及实战——AdaBoost

俗话说“三个臭皮匠顶个诸葛亮”,集合算法(提升算法)就是将若干个算法集成,输出投票表决的结果。


AdaBoost与Bagging两者的区别是:

  • Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。
  • Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。
  • Bagging:使用均匀取样,每个样例的权重相等。
  • Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大。
  • Bagging:所有预测函数的权重相等。
  • Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。
  • Bagging:各个预测函数可以并行生成。
  • Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。

而随机森林()是Bagging的延展。

算法-AdaBoost

  • 输入:
    • 训练数据集T= \lbrace (x_1, y_1), (x_2, y_2),…,(x_N, y_N) \rbrace,其中x_i \in R^n, y_i \in \lbrace -1, +1 \rbrace;
    • 弱学习算法
  • 输出:最终分类器G(x)
  • (1) 初始化训练样本的权值分布为

    D_1=(w_{11}, w_{12},...,w_{1N}), w_{1i}=\frac{1}{N}, i=1,2,...,N

    即各个训练样本的权重均等
  • (2) 对m=1,2,…,M, m表示训练轮数(亦即第m个基分类器,因为每一轮产生一个基分类器):
    • 使用具有权值分布D_m的训练数据集学习,得到基本分类器G_m(x)
    • 计算G_m(x)在训练数据集上的分类错误率:

      e_m=P(G_m(x_i) \neq y_i)=\sum_{i=1}^Nw_{mi}I(G_m(x_i) \neq y_i)

      即(分类错误的样本\times该样本的权重)之和
    • 计算最终基分类器在组合分类器中的权重值

      \alpha_m=\frac{1}{2}log\frac{1-e_m}{e_m}

      由式屏幕快照 2016-04-05 下午10.06.18.png可知,当屏幕快照 2016-04-06 上午9.09.34.png时,屏幕快照 2016-04-06 上午9.09.54.png,并且屏幕快照 2016-04-06 上午9.08.00.png随着屏幕快照 2016-04-06 上午9.10.19.png的减小而增大,所以分类误差率越小的基本分类器在最终分类器中的作用越大。
    • 更新训练数据集的权值分布

      D_{m+1}=(w_{m+1,1},...,w_{m+1,i},...,w_{m+1,N})

      如果G_m(x_i)=y_i那么

      w_{m+1,i}=\frac{w_{m,i}}{Z_m}e^{-\alpha_m}

      否则

      w_{m+1,i}=\frac{w_{m,i}}{Z_m}e^{\alpha_m}

如果将权重更新简化表示就是(因为y_i,G_m(x_i) \in \lbrace -1, +1 \rbrace,根据其异同可以决定指数部分的符号)

w_{m+1,i}=\frac{w_{m,i}}{Z_m}exp(-\alpha_my_iG_m(x_i))

其中 Z_m是规范化因子,用来使权重分布成为一个概率分布(这里就可以看到错分样本的权重被调大)

Z_m=\sum_{i=1}^Nw_{m,i}exp(-\alpha_my_iG_m(x_i))

  • (3) 构建基本分类器的线性组合

    f(x)=\sum_{m=1}^M\alpha_mG_m(x)

    得到最终分类器

    G(x)=sign(f(x))=sign(\sum_{m=1}^M\alpha_mG_m(x))

python实现:

def loadSimpData():
    """
加载简单数据集
    :return:
    """
    datMat = matrix([[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
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):  # just classify the data
    """
用只有一层的树桩决策树对数据进行分类
    :param dataMatrix: 数据
    :param dimen: 特征的下标
    :param threshVal: 阈值
    :param threshIneq: 大于或小于
    :return: 分类结果
    """
    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):
    """
构建决策树(一个树桩)
    :param dataArr: 数据特征矩阵
    :param classLabels: 标签向量
    :param D: 训练数据的权重向量
    :return: 最佳决策树,最小的错误率加权和,最优预测结果
    """
    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']:  # 遍历大于和小于
                threshVal = (rangeMin + float(j) * stepSize)
                predictedVals = stumpClassify(dataMatrix, i, threshVal,
                                              inequal)  # 使用参数 i, j, lessThan 调用树桩决策树分类
                errArr = mat(ones((m, 1)))
                errArr[predictedVals == labelMat] = 0 # 预测正确的样本对应的错误率为0,否则为1
                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):
    """
基于单层决策树的ada训练
    :param dataArr: 样本特征矩阵
    :param classLabels: 样本分类向量
    :param numIt: 迭代次数
    :return: 一系列弱分类器及其权重,样本分类结果
    """
    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)))  # 计算 alpha, 防止发生除零错误
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)  # 保存树桩决策树
        # print "classEst: ",classEst.T
        expon = multiply(-1 * alpha * mat(classLabels).T, classEst)  # 每个样本对应的指数,当预测值等于y的时候,恰好为-alpha,否则为alpha
        D = multiply(D, exp(expon))  # 计算下一个迭代的D向量
        D = D / D.sum() # 归一化
        # 计算所有分类器的误差,如果为0则终止训练
        aggClassEst += alpha * classEst
        # print "aggClassEst: ",aggClassEst.T
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1))) # aggClassEst每个元素的符号代表分类结果,如果与y不等则表示错误
        errorRate = aggErrors.sum() / m
        print "total error: ", errorRate
        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'])  
        aggClassEst += classifierArr[i]['alpha'] * classEst
        print aggClassEst
    return sign(aggClassEst)

http://izhaoyi.top/2017/06/29/boosting/

http://www.hankcs.com/ml/adaboost.html

https://blog.csdn.net/c406495762/article/details/78212124

猜你喜欢

转载自blog.csdn.net/keithic/article/details/81270283
今日推荐