元算法是對其他算法進行組合的一種方式。
單層決策樹實際上是一個單節點的決策樹。
adaboost
優點:泛化錯誤率低,易編碼,可以應用在大部分分類器上,無參數調整
缺點:對離群點敏感
適用數據類型:數值型和標稱型數據
bagging:基於數據隨機重抽樣的分類器構建方法
自舉匯聚法,也稱為bagging方法,是在從原始數據集選擇S次后得到的S個新數據集的一種技術。
新數據集和原數據集的大小相等。每個數據集都是通過在原始數據集中隨機選擇一個樣本來進行替換得到的。
這里的替換就意味着可以多次選擇同一個樣本。這一性質允許新數據集中可以有重復的值,而原始數據集的
某些值在新集合中則不再出現。
在S個數據集建好之后,將某個學習算法分別作用於每個數據集就得到了s個分類器。當我們要對新數據進行
分類時,就可以應用這s個分類器進行分類。與此同時,選擇分類器投票結果中最多的類別作為最后的分類結果。
boosting是一種與bagging很類似的技術。不論是在boosting還是bagging當中,所使用的多個分類器的類型都是
一致的。但是在前者當中,不同的分類器是通過串行訓練而獲得的,每個新分類器都根據已訓練出的分類器的性
能進行訓練。boosting是通過集中關注被已有分類器錯分的那些數據來獲得新的分類器
由於boosting分類器的結果是基於所有分類器的加權求和結果的,因此boosting與bagging不太一樣,bagging中的
分類器權重是相等的,而boosting中的分類器權重並不相等,每個權重代表的是其對應分類器在上一輪迭代中的成功度。
Adaboost的一般流程
(1)收集數據:可以適用任意方法
(2)准備數據:依賴於所使用的弱分類器類型,本章使用的是單層決策樹,這種分類器可以處理任何數據類型。
當然也可以使用任意分類器作為弱分類器,第2章到第6章中的任一分類器都可以充當弱分類器。作為弱分類器,簡單分類器的效果更好。
(3)分析數據:可以使用任意方法
(4)訓練算法:AdaBoost的大部分時間都用在訓練上,分類器將多次在同一數據集上訓練弱分類器
(5)測試算法:計算分類的錯誤率
(6)使用算法:同SVM一樣,AdaBoost預測兩個類別中的一個。如果想把它應用到多個類別的場合,
那么就要像多類SVM中的做法一樣對AdaBoost進行修改
弱分類器就是說在二分類下錯誤率會高於50%,而'強'分類器的錯誤率會低很多。
AdaBoost是adaptive boosting(自適應 boosting)的縮寫,其運行過程如下:訓練數據中的每個樣本,並賦予其一個權重,
這些權重構成了向量D。一開始,這些權重都初始化稱相等值。首先在訓練數據上訓練出一個弱分類器並計算該分類器的錯
誤率,然后在同一個數據集上再次訓練弱分類器。在分類器的第二次訓練當中,將會重新調整每個樣本的權重,其中第一次
分對的樣本的權重將會降低,而第一次分許哦的樣本權重將會提高。為了從所有弱分類器中得到最終的分類結果,AdaBoost為
每一個分類器都分配了一個權重alpha,這些alpha值是基於每個弱分類器的錯誤率進行計算的。
1 rom numpy import * 2 3 def loadSimpData(): 4 datMat = matrix([[ 1. , 2.1], 5 [ 2. , 1.1], 6 [ 1.3, 1. ], 7 [ 1. , 1. ], 8 [ 2. , 1. ]]) 9 classLabels = [1.0, 1.0, -1.0, -1.0, 1.0] 10 return datMat,classLabels 11 12 ''' 13 接下來構造單層決策樹。第一個函數將用於測試是否有某個值小於或大於我們正在測試的閾值。 14 第二個函數則更加復雜一些,它會在一個加權數據集中循環,並找到具有最低錯誤率的單層決策樹。 15 這個程序的偽代碼看起來大致如下: 16 將最小錯誤率minError設為+∞ 17 對數據集中的每一個特征(第一層循環): 18 對每個步長(第二層循環): 19 對每個不等號(第三層循環): 20 建立一顆單層決策樹並利用加權數據集對它進行測試 21 如果錯誤率低於minError,則將當前單層決策樹設為最佳單層決策樹 22 返回最佳單層決策樹 23 ''' 24 25 26 def stumpClassify(dataMatrix, dimen, threshVal, threshIneq): # just classify the data 27 retArray = ones((shape(dataMatrix)[0], 1)) 28 if threshIneq == 'lt': 29 retArray[dataMatrix[:, dimen] <= threshVal] = -1.0 30 else: 31 retArray[dataMatrix[:, dimen] > threshVal] = -1.0 32 return retArray 33 34 35 def buildStump(dataArr, classLabels, D): 36 dataMatrix = mat(dataArr); 37 labelMat = mat(classLabels).T 38 m, n = shape(dataMatrix) 39 numSteps = 10.0; 40 bestStump = {}; 41 bestClasEst = mat(zeros((m, 1))) 42 minError = inf # init error sum, to +infinity 43 for i in range(n): # loop over all dimensions 44 rangeMin = dataMatrix[:, i].min(); 45 rangeMax = dataMatrix[:, i].max(); 46 stepSize = (rangeMax - rangeMin) / numSteps 47 for j in range(-1, int(numSteps) + 1): # loop over all range in current dimension 48 for inequal in ['lt', 'gt']: # go over less than and greater than 49 threshVal = (rangeMin + float(j) * stepSize) 50 predictedVals = stumpClassify(dataMatrix, i, threshVal, 51 inequal) # call stump classify with i, j, lessThan 52 errArr = mat(ones((m, 1))) 53 errArr[predictedVals == labelMat] = 0 54 weightedError = D.T * errArr # calc total error multiplied by D 55 # print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError) 56 if weightedError < minError: 57 minError = weightedError 58 bestClasEst = predictedVals.copy() 59 bestStump['dim'] = i 60 bestStump['thresh'] = threshVal 61 bestStump['ineq'] = inequal 62 return bestStump, minError, bestClasEst 63 64 ''' 65 完整AdaBoost算法的實現 66 整個實現的偽代碼如下: 67 對每次迭代: 68 利用buildStump()函數找到最佳的單層決策樹 69 將最佳單層決策樹加入到單層決策樹數組 70 計算alpha 71 計算新的權重向量D 72 更新累計類別的估計值 73 如果錯誤率等於0.0,則退出循環 74 75 ''' 76 def adaBoostTrainDS(dataArr,classLabels,numIt=40): 77 weakClassArr = [] 78 m = shape(dataArr)[0] 79 D = mat(ones((m,1))/m) #init D to all equal 80 aggClassEst = mat(zeros((m,1))) 81 for i in range(numIt): 82 bestStump,error,classEst = buildStump(dataArr,classLabels,D)#build Stump 83 #print "D:",D.T 84 alpha = float(0.5*log((1.0-error)/max(error,1e-16)))#calc alpha, throw in max(error,eps) to account for error=0 85 bestStump['alpha'] = alpha 86 weakClassArr.append(bestStump) #store Stump Params in Array 87 #print "classEst: ",classEst.T 88 expon = multiply(-1*alpha*mat(classLabels).T,classEst) #exponent for D calc, getting messy 89 D = multiply(D,exp(expon)) #Calc New D for next iteration 90 D = D/D.sum() 91 #calc training error of all classifiers, if this is 0 quit for loop early (use break) 92 aggClassEst += alpha*classEst 93 #print "aggClassEst: ",aggClassEst.T 94 aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1))) 95 errorRate = aggErrors.sum()/m 96 print("total error: ",errorRate) 97 if errorRate == 0.0: break 98 return weakClassArr,aggClassEst 99 100 def adaClassify(datToClass,classifierArr): 101 dataMatrix = mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDS 102 m = shape(dataMatrix)[0] 103 aggClassEst = mat(zeros((m,1))) 104 for i in range(len(classifierArr)): 105 classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])#call stump classify 106 aggClassEst += classifierArr[i]['alpha']*classEst 107 print(aggClassEst) 108 return sign(aggClassEst) 109 110 111 dataMat,classLabels=loadSimpData() 112 D=mat(ones((5,1))/5) 113 A,B,C=buildStump(dataMat,classLabels,D) 114 classifierArr=adaBoostTrainDS(dataMat,classLabels,30) 115 print(classifierArr) 116 adaClassify([0,0],classifierArr)
小結:集成方法通過組合多個分類器的分類結果,獲得了比簡單的單分類器更好的分類結果。有一些利用不同分類器的繼承方法,但是本章只介紹了那些利用同一類分類器的集成方法。
多個分類器組合可能會進一步凸顯單分類器的不足,比如過擬合問題。如果分類器之間差別顯著,那么多個分類器組合就可能會緩解這一問題。分類器之間的差別可以是算法本身或者是應用於算法上的數據的不同
本章介紹的兩種集成方法是bagging和boosting。在bagging中,是通過隨機抽樣的替換方式,得到了與原始數據集規模一樣的數據集。而boosting在bagging的思路上更進了一步,他在數據集上順序應用了多個不同的分類器。另一個成功的繼承方法就是隨機森林,但是由於隨機森林不如adaboost流行,所以本書並沒有對他進行介紹
本章介紹了boosting方法中最流行的一個稱為AdaBoost的算法。AdaBoost以弱學習器作為基分類器,並且輸入數據,使其通過權重向量進行加權。在第一次迭代當中,所有數據都等權重。但是在后續的迭代當中,前次迭代中分錯的數據的權重會增大。這種針對錯誤的調節能力正是Adaboost的長處。
本章以單層決策樹作為弱學習器構建了AdaBoost分類器。實際上,AdaBoost函數可以應用於任意分類器,只要該分類器能夠處理加權數據即可,AdaBoost算法十分強大,它能夠快速處理其他分類器很難處理的數據集。
非均衡分類問題是指在分類器訓練時正例數目和反例數目不相等(相差很大)。該問題在錯分正例和反例不同時也存在。
本章介紹了通過過抽樣和欠抽樣方法來調節數據集中的正例和反例數目。另外一種可能更好的非均衡問題的處理方法,就是在訓練分類器時將錯誤的代價考慮在內