读书笔记 - 机器学习实战 - 7 用AdaBoost算法改进分类

7 用AdaBoost算法改进分类(Improving classification with the AdaBoost meta-algorithm)

元算法(meta-algorithms)是一种将各种算法组合的方法,用于消除不同机器学习算法求解问题时的差异性。

分类不平衡(classification imbalance):各类别包含样本数量差异极大。

7.1 使用多样本数据集的分类器(Classifiers using multiple samples of the dataset)

AdaBoost

优点:泛化错误低,易于编程,适用于大多数分类器,无需参数调整

缺点:对异常值敏感

适用范围:数值和标称值

**集成方法(ensemble methods):**即元算法(meta-algorithms),组合多个分类器。集成方法可以组合不同算法,组合设置了不同参数的同一算法,或将数据集的不同部分分配给不同的分类器。

7.1.1 数据随机重采样构建分类器:Bagging(Building classifiers from randomly resampled data: bagging)

自助聚集(Bootstrap aggreging),即Bagging

(1)生成SS个新数据集:从原始数据集中抽取数据SS次,生成SS个新数据集。新数据集的大小与原始数据集相同,数据是从原始数据集中随机抽取得到。新数据集允许包含重复数据,或不包含原始数据集中的某些数据。

(2)训练:新建SS个数据集后,分别对每个数据集应用一种学习算法,得到SS个分类器。

(3)推理:SS个分类器分别对新数据预测,然后投票多数表决(take a majority vote)。

7.1.2 Boosting

Boosting:各分类器依次串行训练,每个新分类器都专注于处理其之前分类器错分的数据。Boosting的输出是所有分类器输出的加权和,各分类器权重(weights)取决于前次迭代各分类器的表现。

  1. 采集:
  2. 预处理:取决于弱分类器类型,通常弱分类器形式简单,如单层决策树(decision stumps)
  3. 分析:
  4. 训练:主要时间消耗
  5. 测试:计算错误率
  6. 使用:二元分类

7.2 训练:专注处理错分样本改进分类器(Train: improving the classifier by focusing on errors)

“弱”分类器:略优于随机猜测;

“强”分类器:远优于随机猜测。

AdaBoost:自适应提升(adaptive boosting)算法,训练步骤如下:

训练数据集{xi,yi}\left\{ \mathbf{x}_i, y_i \right\}i=1,2, ,mi = 1, 2, \cdots, m

为训练集中每条样本xi\mathbf{x}_i分配一个权值did_i,样本权值向量记为d=[d1,d2, ,dm]\mathbf{d} = \left[ d_1, d_2, \cdots, d_m \right]

(1)初始化:

弱分类器t=1t = 1的样本权值向量d(1)\mathbf{d}^{(1)}初始设置为d1=d2==dmd_1 = d_2 = \cdots = d_m,在训练数据集上训练弱分类器t=1t = 1(寻找最佳分类特征、门限及不等式类型等);

(2)迭代:

计算弱分类器(t1)(t - 1)的分类错误率

KaTeX parse error: Expected '}', got '#' at position 27: … = \frac{\text{#̲ of incorrectly…

计算弱分类器(t1)(t - 1)的权值

α=12ln(1εε)\alpha = \frac{1}{2} \ln \left( \frac{1 - \varepsilon}{\varepsilon} \right)

增加弱分类器tt,根据弱分类器(t1)(t - 1)的分类错误率计算其样本权值向量d(t)\mathbf{d}^{(t)},使已被正确分类样本的权值减少,未被正确分类样本的权值增加:

di(t+1)={di(t)eα,if correctly predicted, i.e. y^i=yidi(t)eα,if incorrectly predicted, i.e. y^i̸=yid(t+1)=d(t+1)di(t+1)\begin{aligned} d_i^{(t+1)} = & \begin{cases} d_i^{(t)} e^{- \alpha}, \quad & \text{if correctly predicted, i.e. } \hat{y}_i = y_i \\ d_i^{(t)} e^{\alpha}, \quad & \text{if incorrectly predicted, i.e. } \hat{y}_i \not= y_i \\ \end{cases} \\ \mathbf{d}^{(t+1)} = & \frac{\mathbf{d}^{(t+1)}}{\sum d_i^{(t+1)}} \end{aligned}

yi{1,1}y_i \in \{ -1, 1 \}时,上式也可改写为:

di(t+1)=di(t)ey^iyiαd(t+1)=d(t+1)di(t+1)\begin{aligned} d_i^{(t+1)} = & d_i^{(t)} e^{\hat{y}_i y_i \alpha} \\ \mathbf{d}^{(t+1)} = & \frac{\mathbf{d}^{(t+1)}}{\sum d_i^{(t+1)}} \end{aligned}

在训练数据集上训练弱分类器tt

(3)终止条件:训练错误为0或弱分类器的数量达到用户定义的值。

读书笔记 - 机器学习实战 - 7 用AdaBoost算法改进分类

左侧为数据集,条形图的宽度表示每条样本的权重。样本加权后经弱分类器预测, 预测结果经加权(α\alpha)累加作为最终输出。

7.3 单层决策树弱学习器(Creating a weak learner with a decision stump)

单层决策树(decision stump):只利用单个特征对训练数据集进行分割、预测。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

def loadSimpData():
    datMat = np.matrix([[1, 2.1],
                        [2, 1.1],
                        [1.3, 1],
                        [1, 1],
                        [2, 1]])
    classLabels = [1, 1, -1, -1, 1]

    return datMat, classLabels

datMat, classLabels = loadSimpData()

class_1_indices = np.nonzero(np.array(classLabels) > 0)
class_2_indices = np.nonzero(np.array(classLabels) < 0)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(datMat[class_1_indices, 0].A, datMat[class_1_indices, 1].A,
           color='green', marker='o', label="Class 1")
ax.scatter(datMat[class_2_indices, 0].A, datMat[class_2_indices, 1].A,
           color='red', marker='s', label="Class 2")
ax.legend()
plt.show()

读书笔记 - 机器学习实战 - 7 用AdaBoost算法改进分类

SET $minError = + \infty$

FOR 遍历训练数据集样本特征:
    FOR 遍历判决门限:
        FOR 遍历不等式类型:
            单层决策树对训练数据集分类
            对训练数据集分类结果加权
            IF 误差 < $minError$:
                SET 最佳单层决策树 = 该单层决策树
            END
        END
    END
END

RETURN 最佳单层决策树

# Listing 7.1 Decision stump-generating functions

def stumpClassify(dataMatrix, dimen, threshVal, thershIneq):
    retArray = np.ones((dataMatrix.shape[0], 1))
    
    if thershIneq == "lt":
        retArray[dataMatrix[:, dimen] <= threshVal] = - 1
    else:
        retArray[dataMatrix[:, dimen] > threshVal] = - 1
        
    return retArray

def buildStump(dataArr, classLabels, D):
    dataMatrix = np.matrix(dataArr)
    labelMat = np.matrix(classLabels).transpose()
    m, n = dataMatrix.shape
    numSteps = 10
    bestStump = {}
    bestClasEst = np.matrix(np.zeros((m, 1)))
    minError = np.inf
    
    for i in range(n):
        rangeMin = dataMatrix[:, i].min()
        rangeMax = dataMatrix[:, i].max()
        stepSize = (rangeMax - rangeMin) / numSteps
        
        for j in range(-1, numSteps + 1):
            
            for inequal in ["lt", "gt"]:
                threshVal = rangeMin + j * stepSize
                predictedVals = stumpClassify(
                    dataMatrix, i, threshVal, inequal)
                errArr = np.matrix(np.ones((m, 1)))
                errArr[predictedVals == labelMat] = 0
                
                # calculate weighted error
                weightedError = np.dot(D.T, errArr)
#                 print("split: dim {}, thresh {}, thresh ineqal: {}, the weighted error is {}" \
#                       .format(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

    
D = np.matrix(np.ones((5, 1)) / 5)
print(buildStump(datMat, classLabels, D))
({'dim': 0, 'thresh': 1.3, 'ineq': 'lt'}, matrix([[0.2]]), array([[-1.],
       [ 1.],
       [-1.],
       [-1.],
       [ 1.]]))

stumpClassify():单层决策树分类器

  • 输入:训练数据集所有样本,特征索引,判决门限,不等式类型

  • 输出:训练数据集所有样本预测标签向量

buildStump():构建最佳单层决策树分类器

  • 输入:训练数据集(样本、标签),样本权值

  • 输出:最佳单层决策树分类器

buildStump()首先遍历样本特征;然后对于每个特征,设置不同的门限和不等式类型,比较分类结果;计算加权分类误差,得到最佳单层决策树。

7.4 AdaBoost算法(Implementing the full Ada Boost algorithm)

伪代码:

FOR EACH 迭代:

    调用buildStump()计算最佳单层决策树
    将最佳单层决策树加入单层决策树列表
    计算$\alpha$
    计算新的权值向量$\mathbf{D}$
    更新累积类别估计
    
    IF 错误率 == 0
        BREAK
    END IF
    
END FOR



# Listing 7.2 AdaBoost training with decision stumps

def adaBoostTrainDS(dataArr, classLabels, numIt=40):
    
    weakClassArr = []
    m = dataArr.shape[0]
    D = np.matrix(np.ones((m, 1)) / m)
    aggClassEst = np.matrix(np.zeros((m, 1)))
    
    for i in range(numIt):
        
        # print("D: {}".format(D.T))
        bestStump, error, classEst = buildStump(
            dataArr, classLabels, D)
        
        alpha = float(0.5 * np.log((1 - error) / max(error, 1e-16)))
        bestStump["alpha"] = alpha
        weakClassArr.append(bestStump)
        # print("classEst: {}".format(classEst.T))
        
        # calculate D for next iteration
        expon = -1 * alpha * np.multiply(np.matrix(classLabels).T,
                                         classEst)
        D = np.multiply(D, np.exp(expon))
        D = D / D.sum()
        
        # aggregate error calculation
        aggClassEst += alpha * classEst
        # print("aggClassEst: {}".format(aggClassEst.T))
        aggErrors = np.multiply(
            np.sign(aggClassEst) != np.matrix(classLabels).T,
            np.ones((m, 1)))
        errorRate = aggErrors.sum() / m
        # print("total error: {}\n".format(errorRate))
        
        if errorRate == 0:
            break
            
    return weakClassArr


classifierArr = adaBoostTrainDS(datMat, classLabels, 9)
print(classifierArr)
[{'dim': 0, 'thresh': 1.3, 'ineq': 'lt', 'alpha': 0.6931471805599453}, {'dim': 1, 'thresh': 1.0, 'ineq': 'lt', 'alpha': 0.9729550745276565}, {'dim': 0, 'thresh': 0.9, 'ineq': 'lt', 'alpha': 0.8958797346140273}]

7.5 AdaBoost分类测试(Test: classifying with AdaBoost)

# Listing 7.3 AdaBoost classification function

def adaClassify(datToClass, classifierArr):
    
    dataMatrix = np.matrix(datToClass)
    m = dataMatrix.shape[0]
    aggClassEst = np.matrix(np.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 np.sign(aggClassEst)

print(adaClassify([0, 0], classifierArr))
[[-1.]]

7.6 例:AdaBoost分类(Example: AdaBoost on a difficult dataset)

例:AdaBoost在马绞痛数据集上的表现

  1. 采集:
  2. 预处理:确保样本标签是+1+11-1
  3. 分析:
  4. 训练:使用adaBoostTrainDS()函数训练分类器
  5. 测试:与逻辑回归预测结果同类比较(apples-to-apples comparison)
  6. 使用:二元分类
# Listing 7.4 Adaptive load data function 

def loadDataSet(fileName):
    
    dataMat = []
    labelMat = []
    with open(fileName, "r") as fr:
        
        for line in fr.readlines():
            curLine = line.strip().split('\t')
            dataMat.append([float(item) for item in curLine[0: -1]])
            labelMat.append(float(curLine[-1]))
            
    dataMat = np.array(dataMat)
    labelMat = np.array(labelMat)
    labelMat[labelMat == 0] = -1
    
    return dataMat, labelMat

datArr, labelArr = loadDataSet("./horse_colic./horseColicTraining.txt")
classifierArray = adaBoostTrainDS(datArr, labelArr)
print(classifierArray)
[{'dim': 9, 'thresh': 3.0, 'ineq': 'gt', 'alpha': 0.4616623792657674}, {'dim': 17, 'thresh': 52.5, 'ineq': 'gt', 'alpha': 0.31248245042467104}, {'dim': 3, 'thresh': 55.199999999999996, 'ineq': 'gt', 'alpha': 0.2868097320169577}, {'dim': 18, 'thresh': 62.300000000000004, 'ineq': 'lt', 'alpha': 0.23297004638939506}, {'dim': 10, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.19803846151213741}, {'dim': 5, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.18847887349020634}, {'dim': 12, 'thresh': 1.2, 'ineq': 'lt', 'alpha': 0.15227368997476778}, {'dim': 7, 'thresh': 1.2, 'ineq': 'gt', 'alpha': 0.15510870821690512}, {'dim': 5, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.13536197353359405}, {'dim': 4, 'thresh': 28.799999999999997, 'ineq': 'lt', 'alpha': 0.12521587326132078}, {'dim': 11, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.1334764812820767}, {'dim': 9, 'thresh': 4.0, 'ineq': 'lt', 'alpha': 0.1418224325377107}, {'dim': 14, 'thresh': 0.0, 'ineq': 'gt', 'alpha': 0.10264268449708028}, {'dim': 0, 'thresh': 1.0, 'ineq': 'lt', 'alpha': 0.11883732872109484}, {'dim': 4, 'thresh': 19.2, 'ineq': 'gt', 'alpha': 0.09879216527106625}, {'dim': 2, 'thresh': 36.72, 'ineq': 'lt', 'alpha': 0.12029960885056867}, {'dim': 3, 'thresh': 92.0, 'ineq': 'lt', 'alpha': 0.10846927663989175}, {'dim': 15, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.09652967982091411}, {'dim': 3, 'thresh': 73.6, 'ineq': 'gt', 'alpha': 0.08958515309272022}, {'dim': 18, 'thresh': 8.9, 'ineq': 'lt', 'alpha': 0.09210361961272426}, {'dim': 16, 'thresh': 4.0, 'ineq': 'gt', 'alpha': 0.10464142217079622}, {'dim': 11, 'thresh': 3.2, 'ineq': 'lt', 'alpha': 0.09575457291711606}, {'dim': 20, 'thresh': 0.0, 'ineq': 'gt', 'alpha': 0.09624217440331524}, {'dim': 17, 'thresh': 37.5, 'ineq': 'lt', 'alpha': 0.0785966288518967}, {'dim': 9, 'thresh': 2.0, 'ineq': 'lt', 'alpha': 0.0714286363455072}, {'dim': 5, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.07830753154662214}, {'dim': 4, 'thresh': 28.799999999999997, 'ineq': 'lt', 'alpha': 0.07606159074712784}, {'dim': 4, 'thresh': 19.2, 'ineq': 'gt', 'alpha': 0.08306752811081955}, {'dim': 7, 'thresh': 4.2, 'ineq': 'gt', 'alpha': 0.0830416741141175}, {'dim': 3, 'thresh': 92.0, 'ineq': 'lt', 'alpha': 0.08893356802801224}, {'dim': 14, 'thresh': 3.0, 'ineq': 'gt', 'alpha': 0.07000509315417908}, {'dim': 7, 'thresh': 5.3999999999999995, 'ineq': 'lt', 'alpha': 0.07697582358565964}, {'dim': 18, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.08507457442866707}, {'dim': 5, 'thresh': 3.2, 'ineq': 'lt', 'alpha': 0.0676590387302069}, {'dim': 7, 'thresh': 3.0, 'ineq': 'gt', 'alpha': 0.08045680822237049}, {'dim': 12, 'thresh': 1.2, 'ineq': 'lt', 'alpha': 0.05616862921969557}, {'dim': 11, 'thresh': 2.0, 'ineq': 'gt', 'alpha': 0.06454264376249863}, {'dim': 7, 'thresh': 5.3999999999999995, 'ineq': 'lt', 'alpha': 0.05308888435382875}, {'dim': 11, 'thresh': 0.0, 'ineq': 'lt', 'alpha': 0.0734605861478849}, {'dim': 13, 'thresh': 0.0, 'ineq': 'gt', 'alpha': 0.07872267320907414}]
testArr, testLabelArr = loadDataSet("./horse_colic/horseColicTest.txt")
prediction10 = adaClassify(testArr, classifierArray)
m = prediction10.shape[0]

errArr = np.ones((m, 1))
err_rate = errArr[prediction10 != np.expand_dims(testLabelArr, axis=1)].sum() / m

print("error rate is {}%".format(err_rate * 100))
error rate is 19.402985074626866%

在监督学习中,AdaBoost和支持向量机被视为最优秀算法,它们之间存在一些相似之处。

(1)AdaBoost中的弱学习器可视为支持向量机中的核函数;

(2)AdaBoost算法也可表示为最大化最小余量。

7.7 非均衡分类(Classification imbalance)

非均衡分类(classification imbalance)问题是指在训练数据集中正例数目和反例数目相差很大;或错分正例和反例的代价不同。

7.7.1 性能度量:精确度、召回率和ROC

  • 混淆矩阵(confusion matrix)
Actual class
$+1$ $-1$
Predicted class $+1$ True Positive (TP) False Positive (FP)
$-1$ False Negative (FN) True Negative (TN)
  • 精度(precision):

Precision=TPTP+FP\mathrm{Precision} = \frac{\mathrm{TP}}{\mathrm{TP + FP}}

精度表示分类器预测为正的样本中有多少是被正确预测的。

  • 召回率(recall):

Recall=TPTP+FN\mathrm{Recall} = \frac{\mathrm{TP}}{\mathrm{TP + FN}}

召回率度量被分类器正确预测的正样本占所有正样本的比例。

  • ROC曲线

受试者工作特征(receiver operating characteristic,ROC)曲线以假阳性概率(False positive rate)为横轴,真阳性概率(True positive rate)为纵轴所组成的坐标图,和受试者在特定刺激条件下由于采用不同的判断标准得出的不同结果画出的曲线。ROC可用于衡量分类器在非均衡分类问题上的表现。

读书笔记 - 机器学习实战 - 7 用AdaBoost算法改进分类

图中,xx轴表示假阳性概率,yy轴表示真阳性概率。ROC曲线给出了假阳性概率和真阳性概率随阈值的变化的规律,最左侧的点对应于将所有样本分为负类,最右侧的点对应于将所有样本分为正类,虚线表示随机猜测。

通过比较ROC曲线,我们能够对分类器的性价比(cost-versus-benefit)做出取舍。理想的分类器应该尽可能靠近左上角,即分类器的检测率很高且误报率很低。

AUC(area under the curve)是用来衡量ROC曲线的测度,给出了分类器性能的均值。理想分类器的AUC值是1,而随机猜测的AUC值0.5。

# Listing 7.5 ROC plotting and AUC calculating function
%matplotlib inline
import matplotlib.pyplot as plt

def plotROC(predStrengths, classLabels):
    
    cur = (1, 1)
    ySum = 0
    numPosClas = np.sum(np.array(classLabels) == 1)
    yStep = 1 / numPosClas
    xStep = 1 / (len(classLabels) - numPosClas)
    sortedIndicies = predStrengths.argsort()
    
    fig = plt.figure()
    fig.clf()
    ax = fig.add_subplot(111)
    
    for index in sortedIndicies.tolist()[0]:
        if classLabels[index] == 1:
            delX = 0
            delY = yStep
        else:
            delX = xStep
            delY = 0
            ySum += cur[1]
            
        ax.plot([cur[0], cur[0] - delX], [cur[1], cur[1] - delY], c='b')
        cur = (cur[0] - delX, cur[1] - delY)
        
    ax.plot([0, 1], [0, 1], "b--")
    ax.set_xlabel("False Positive Rate")
    ax.set_ylabel("True Positive Rate")
    ax.set_title("ROC curve for AdaBoost Horse Colic Detection System")
    ax.axis([0, 1, 0, 1])
    plt.show()
    print("the Area Under the Curve is: {}".format(ySum * xStep))
    

# Listing 7.2 AdaBoost training with decision stumps

def adaBoostTrainDS(dataArr, classLabels, numIt=40):
    
    weakClassArr = []
    m = dataArr.shape[0]
    D = np.matrix(np.ones((m, 1)) / m)
    aggClassEst = np.matrix(np.zeros((m, 1)))
    
    for i in range(numIt):
        
        # print("D: {}".format(D.T))
        bestStump, error, classEst = buildStump(
            dataArr, classLabels, D)
        
        alpha = float(0.5 * np.log((1 - error) / max(error, 1e-16)))
        bestStump["alpha"] = alpha
        weakClassArr.append(bestStump)
        # print("classEst: {}".format(classEst.T))
        
        # calculate D for next iteration
        expon = -1 * alpha * np.multiply(np.matrix(classLabels).T,
                                         classEst)
        D = np.multiply(D, np.exp(expon))
        D = D / D.sum()
        
        # aggregate error calculation
        aggClassEst += alpha * classEst
        # print("aggClassEst: {}".format(aggClassEst.T))
        aggErrors = np.multiply(
            np.sign(aggClassEst) != np.matrix(classLabels).T,
            np.ones((m, 1)))
        errorRate = aggErrors.sum() / m
        # print("total error: {}\n".format(errorRate))
        
        if errorRate == 0:
            break
            
    return weakClassArr, aggClassEst


datArr,labelArr = loadDataSet('./horse_colic/horseColicTraining.txt')
classifierArray, aggClassEst = adaBoostTrainDS(datArr, labelArr, 10)
plotROC(aggClassEst.T, labelArr)

classifierArray, aggClassEst = adaBoostTrainDS(datArr, labelArr, 40)
plotROC(aggClassEst.T, labelArr)

读书笔记 - 机器学习实战 - 7 用AdaBoost算法改进分类

the Area Under the Curve is: 0.8582969635063604

读书笔记 - 机器学习实战 - 7 用AdaBoost算法改进分类

the Area Under the Curve is: 0.8918191104095092

7.7.2 基于代价函数的分类器决策

调整分类器阈值是处理非均衡分类问题的常用手段,此外代价敏感学习(cost sensitive learning)也可处理非均衡分类问题。

下表给出二分类问题的代价矩阵,表7.4 -(1)为均衡分类问题的代价矩阵,总代价期望为:

TP×0+FN×1+FP×1+TN×0TP \times 0 + FN \times 1 + FP \times 1 + TN \times 0

表7.4 -(2)为均衡分类问题的代价矩阵为非均衡分类问题的代价矩阵,总代价期望为:

TP×(5)+FN×1+FP×50+TN×0TP \times (-5) + FN \times 1 + FP \times 50 + TN \times 0

代价矩阵(2)中的两类错分(FP、FN)代价不同,同样两类正确分类(TP、TN)所获收益也不同。

Actual class
$+1$ $-1$
Predicted class $+1$ $0$ $1$
$-1$ $1$ $0$

(1)

Actual class
$+1$ $-1$
Predicted class $+1$ $-5$ $50$
$-1$ $1$ $0$

(2)

表7.4 二分类问题的代价矩阵(cost matrix)

将代价函数引入分类算法的方法有多种:对于AdaBoost算法,可根据代价函数调整样本权值向量d\mathbf{d};对于朴素贝叶斯算法,分类依据可用最小期望代价代替最大分类概率。对于SVM算法,可为不同类别的代价函数设置不同的参数C。这样,当训练分类器时,样本少的类别会被赋予更高的权值,该类别中样本被错分的概率会减小。

7.7.3 非均衡分类问题的数据采样

通过修改训练集数据采样方法也可处理非均衡分类问题,主要包括欠采样(undersampling)和过采样(oversampling)。欠采样表示样本重复采样,欠采样表示删除部分样本。

非均衡分类问题中,例如信用卡诈骗,正样本数量极少,因此应保留正样本信息,并对负样本降采样。该方法缺点在于丢弃哪些负样本,因为丢弃样本可能包含其它样本中没有信息。该问题可通过丢弃远离决策边界的样本解决;或者使用混合方法,即对负样本欠采样并对正样本过采样。

正样本过采样:(1)复制已有正样本添加;(2)根据已有正样本插值。

正样本过采样可能会导致过拟合(overfitting)。

7.8 总结(Summary)

集成(emsemble)方法通过组合多个分类器的预测结果获得更优的分类结果。

组合多个分类器能够克服单个分类器的缺点,如过拟合。只要多个分类器彼此之间存在显著差异,集成方法便有助于性能提升。这种差异可以是算法差异,也可是各算法使用数据的差异。

本章介绍了两种集成方法:bagging和boost。bagging算法对有放回的数据集随机采样,构造与原始数据集大小相同的数据集,训练多个分类器。boost在同一数据集上对分类器串行训练。此外集成算法还有随机森林。