集成算法

集成算法(融合算法)

元算法(meta-algorithm)

思路:对其他算法进行组合。

使用集成算法时有多种形式:
不同算法的集成;
同一算法在不同设置下的集成;
数据集不同部分,分配给不同分类器之后的集成。

bagging(bootstrap aggregating) 自举汇聚法

定义:从原始数据集选择S次后得到S个新数据集的一种技术, 新数据集和原数据集大小相等。每个数据集都是从原始数据集中

随机选择一个得到的,允许新数据中有重复的值

思想:

使用不同数据集分别训练模型,然后将多个不同模型预测结果融合产生预测值。

数据产生方式:有放回重采样,产生不同数据【样本数目不一样,数据样本不一样】

作用:
不同数据集训练,模型考虑样本特征不同,部分模型对特殊特征值进行学习,在多个模型融合时,特殊特征信息将会过滤掉,

使模型更有鲁棒性,缓解模型过拟合

经典算法: 随机森林

构件过程:
1、从原始数据中重采样m条数据,去重得到子数据;
2、利用子数据构件决策树模型,选择划分特征时,引入随机特征划分:
a. 从原始特征中随机选择k个特征,从k个特征中选择最优划分的特征作为当前节点划分(此时为最优局部划分,可以降低模型过拟合);
3、使用上述步骤构件N次,产生N个模型,形成随机森林模型;
4、使用N个模型对样本进行预测,对N个结果进行融合(分类:多数投票; 回归:均值)

boosting

思想:

使用一种模型迭代,使每一步模型构建都是让模型的最终预测更加精准;

让模型误差率越来越小,即模型构建需要基于之前模型预测结果之上。

作用:主要作用提高模型欠拟合

区别:

boosting集中关注被已有分类器错分的那些数据来获得新的分类器

boosting分类结果是,基于所有分类器的加权求和结果的,bagging中权重相等,boosting中权重不等;

每个权重代表对应分类器在上一轮中成功度。

经典算法:AdaBoost, GBDT, XGBoost

注:boosting有多个版本,流行版本为AdaBoost

AdaBoost(adaptive boosting)自适应boost

优点:泛化错误率低, 容易编码,可以应用在大部分分类器上,无参数调整;

缺点:对离群点敏感;

思想:

通过修改样本权重系数,改变模型构建时,各个样本预测失败带来损失函数值,让模型构建时,对于权重系数较大样本着重考虑,

尽可能让权重过大的样本预测成功。

模型融合时,对预测精准的基模型,给一个较大权重,相当预测精准模型可信度相对较大

构建过程:

1、给定所有样本初始权重一致
2、基于样本及样本权重训练一个基模型,在基模型构建过程中,对于样本权重大的样本,预测比较准确
3、训练好基模型后,计算出当前基模型在训练集上准确率,准确率越高预测结果越可信
4、如果预测失败,增加样本权重,让样本在下一个模型构建时,具有更大的影响因子,预测成功,减小权重
5、当错误率或子模型数目达到一定限制时,结束模型训练

代码实例:

单层决策树构建
boost.py

from numpy import *



def loadSimpData():
    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):
    """
    通过阈值比较,对数据分类
    :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 = {}  # 存储给定权重向量D时,所得到的最佳单层决策树的相关信息
    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)
                errArr = mat(ones((m, 1)))
                errArr[predictedVals == labelMat] = 0
                weightedError = D.T * errArr  # 计算加权错误率
                print(f'split: dim {i}, '
                      f'thresh {threshVal}, '
                      f'thresh inequal: {inequal}, '
                      f'the weighted error is {weightedError}')
                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()
                    bestStump['dim'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal

    return bestStump, minError, bestClasEst


if __name__ == '__main__':
    datMat, classLabels = loadSimpData()
    D = mat(ones((5, 1)) / 5)
    buildStump(datMat, classLabels, D)

adaboost

弱分类器为单层决策树

from numpy import *
from test.machine_learning.algorithm.ada_boost.boost import buildStump, stumpClassify


def loadSimpData():
    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 adaBoostTrainDs(dataArr, classLabels, numIt=40):
    """
    单层决策树adaBoost训练过程
    :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(f'D: {D.T}')
        alpha = float(0.5 * log((1.0-error) / max(error, 1e-16)))  # max(error, 1e-16) 确保错误时,不会发生零的溢出
        bestStump['alpha'] = alpha
        weakClassArr.append(bestStump)
        print(f'classEst: {classEst.T}')
        expon = multiply(-1 * alpha * mat(classLabels).T, classEst)
        D = multiply(D, exp(expon))
        D = D / D.sum()
        aggClassEst += alpha * classEst
        print(f'aggClassEst: {aggClassEst.T}')
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1)))
        errorRate = aggErrors.sum()/m
        print(f'total error: {errorRate}')
        if errorRate == 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(f'aggClassEst: {aggClassEst}')
    return sign(aggClassEst)


def loadDataSet(fileName):
    """
    自适应数据加载函数
    :param fileName:
    :return:
    """
    fr = open(fileName)
    numFeat = len(fr.readline().split('\t'))
    dataMat = []
    labelMat = []
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat-1):
            try:
                lineArr.append(float(curLine[i]))
            except Exception:
                pass
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))

        # currLine = line.strip().split()
        # lineArr = []
        # for i in range(21):
        #     lineArr.append(float(currLine[i]))
        # dataMat.append(lineArr)
        # labelMat.append(float(currLine[21]))

    return dataMat, labelMat

def plotROC(predStrengths, classLabels):
    """
    ROC曲线绘制
    :param predStrengths:
    :param classLabels:
    :return:
    """

    import matplotlib.pyplot as plt
    cur = (1.0, 1.0)
    ySum = 0
    numPosClas = sum(array(classLabels) == 1.0)
    yStep = 1/float(numPosClas)
    xStep = 1/float(len(classLabels)-numPosClas)
    sortedIndicies = predStrengths.argsort()
    fig = plt.figure()
    fig.clf()
    ax = plt.subplot(111)
    for index in sortedIndicies.tolist()[0]:
        if classLabels[index] == 1.0:
            delX = 0
            delY = yStep
        else:
            delX = xStep
            delY = 0
            ySum += cur[1]
        ax.plot([cur[0], cur[o]-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(f'the Area Under the Curve is {ySum*xStep}')


if __name__ == '__main__':
    # datMat, classLabels = loadSimpData()
    # classifierArray = adaBoostTrainDs(datMat, classLabels, 9)
    # cla = adaClassify([[5, 5],[0, 0]], classifierArray)
    # print(cla)

    # 在难数据集上的应用
    datArr, labelArr = loadDataSet(r"D:\workplace\data\tensorflow\logistic_data\horse-colic.data")
    classifierArray, aggClassEst = adaBoostTrainDs(datArr, labelArr, 10)
    plotROC(aggClassEst.T, labelArr)

GBDT

思想:

通过修改标签y值,让每次构建的模型误差足够小,当模型误差值最小时,所对应的标签值就是最优值

采用损失函数梯度值作为下一个模型构建时新y值标签

构建过程:

1、 训练基础模型;
2、基于当前模型计算损失函数梯度值,更新训练中标签值,使用梯度值作为标签值;
3、基于标签值更新的数据训练下一个模型;
4、当损失函数值或子模型数目达到一定限制时,结束模型训练。

预测过程:所有子模型累加值就是最终预测值

XGBoostGBDT区别:

1、加入模型复杂度考虑, 防止模型存在过拟合;
2、底层构建时,GBDT是穿行构建, XGBoost 选择划分特征时,是并行构建
3、GBDT底层只是支持决策树,XGBoost支持决策树,线性回归等模型

posted @ 2022-09-13 17:56  酷酷的排球  阅读(228)  评论(0编辑  收藏  举报