利用AdaBoost元算法提高分类性能
当做重要决定时,大家可能都会吸取多个专家而不只是一个人的意见。机器学习处理问题时又何尝不是如此?这就是元算法背后的思路。元算法是对其他算法进行组合的一种方式。
自举汇聚法(bootstrap aggregating),也称为bagging方法,是从原始数据集选择S次后得到S个新数据集的一种技术。新数据集和原数据集的大小相等。每个数据集都是通过在原始数据集中随机选择一个样本来进行替换而得到的。在S个数据集建好之后,将某个学习算法分别作用于每个数据集就得到了S个分类器。当我们要对新数据进行分类时,就可以应用这S个分类器进行分类。与此同时,选择分类器投票结果中最多的类别作为最后的分类结果。
Boosting是一种与bagging类似的技术,所使用的多个分类器的类型都是一致的。在boosting技术中,不同的分类器是通过串行训练而获得的,每个新分类器都根据已训练出的分类器的性能来进行训练,boosting是通过集中关注被已有分类器错分的哪些数据来获得新的分类器。
AdaBoost是boosting方法中最流行的一种元算法。
AdaBoost算法:
优点:泛华错误率低,易编码,可以应用在大部分分类器上,无参数调整。
缺点:对离群点敏感。
适用数据类型:数值型和标称型数据。
AdaBoost是adaptive boosting(自适应boosting)的缩写,其运行过程如下:
训练数据中的每个样本,并赋予其一个权重,这些权重构成了向量D。一开始,这些权重都初始化成相等值。首先在训练数据上训练出一个弱分类器并计算该分类器的错误率,然后在同一数据集上再次训练弱分类器。在分类器的第二次训练当中,将会重新调整每个样本的权重,其中第一次分对的样本的权重将会降低,而第一次分错的样本的权重将会提高。为了从所有弱分类器中得到最终的分类结果,AdaBoost为每个分类器都分配了一个权重值alpha,这些alpha值是基于每个弱分类器的错误率进行计算的。
错误率 =(未正确分类的样本数目)/(所有样本数目)
alpha = 1/2 * ln((1-错误率)/错误率)
权重更新公式:
如果某个样本被正确分类,那么该样本的权重更改为:
如果某个样本被错误分类,那么样本的权重更改为:
计算出D之后,Adaboost开始进行下一轮迭代。AdaBoost算法会不断地重复训练和调整权重的过程,直到训练错误率为0或者弱分类器的数目达到用于指定值为止。
基于单层决策树构建弱分类器,单层决策树是一种简单的决策树,它仅基于单个特征来做决策,只有一次分裂过程。通过使用多颗单层决策树,就可以构建出一个能够对数据集完全正确分类的分类器。
单层决策树算法伪代码:
将最小错误率minError设为+∞ 对数据集的每一个特征(第一层循环) 对每个步长(第二层循环) 对每个不等号(第三层循环): 建立一颗单层决策树并利用加权数据集对它进行测试 如果错误率低于minError,则将当前单层决策树设为最佳单层决策树 返回最佳单层决策树
AdaBoost算法伪代码:
对每次迭代: 找出最佳的单层决策树 将最佳单层决策树加入到单层决策树数组 计算alpha 计算新的权重向量D 更新累计类别估计值 若果错误率为0.0,则退出循环
单层决策树算法代码实现:
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):#just classify the data 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): dataMatrix = mat(dataArr); labelMat = mat(classLabels).T m,n = shape(dataMatrix) numSteps = 10.0; bestStump = {}; bestClasEst = mat(zeros((m,1))) minError = inf #init error sum, to +infinity for i in range(n):#loop over all dimensions rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max(); stepSize = (rangeMax-rangeMin)/numSteps for j in range(-1,int(numSteps)+1):#loop over all range in current dimension for inequal in ['lt', 'gt']: #go over less than and greater than threshVal = (rangeMin + float(j) * stepSize) predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThan errArr = mat(ones((m,1))) errArr[predictedVals == labelMat] = 0 weightedError = D.T*errArr #calc total error multiplied by D #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
AdaBoost算法代码实现:
def adaBoostTrainDS(dataArr, classLabels, numIt=40): 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))) bestStump['alpha'] = alpha weakClassArr.append(bestStump) print "classEst: ", classEst.T expon = multiply(-1*alpha*mat(classLabels).T, classEst) D = multiply(D, exp(expon)) D = D/D.sum() aggClassEst += alpha*classEst print "aggClassEst: ", aggClassEst.T aggErrors = multiply(sign(aggClassEst)!=mat(classLabels).T, ones((m,1))) errorRate = aggErrors.sum()/m print "total error:", errorRate, "\n" if errorRate == 0.0: break return weakClassArr