前言算法
有人認爲 AdaBoost 是最好的監督學習的方式。數組
某種程度上由於它是元算法,也就是說它會是幾種分類器的組合。這就比如對於一個問題可以諮詢多個 "專家" 的意見了。數據結構
組合的方式有多種,多是不一樣分類算法的分類器,多是同一算法在不一樣設置下的集成,還能夠是數據集在不一樣部分分配給不一樣分類器以後的集成等等。app
本文將給出的 AdaBoost 分類器實現基於第二種 (另外幾種實如今此基礎上稍做改動便可)。函數
一種原始的元算法 - bagging (自舉匯聚法)性能
這個算法的意思有點像投票系統,其思路步驟大體以下:學習
1. 將數據按照必定的規則劃分紅 N 份,每份的大小和原數據集同樣大 (所以裏面確定是有重複數據的)。測試
2. 將這 N 份數據集分發到多個分類器中。ui
3. 按照 "少數服從多數" 原則,從這 N 個分類器的分類結果中總結出最優結果。spa
boost (提升任意給定學習算法精確度算法) vs bagging (自舉匯聚法)
boost 和 bagging 一個很大的不一樣是它會給那些分錯的樣本更高關注度(權重)。AdaBoost 是一種最爲典型的 boost 元算法。
所以理論上它能在相對較少的迭代次數下獲得更爲精確的分類結果。
AdaBoost 元算法的基本原理
AdaBoost 的強大之處,在於它可以繼承多個弱分類器,造成一個強分類器。
所謂弱分類器就是分類錯誤率大於五成的分類器,比隨機分類還渣。(可是它的分類算法是肯定的,這點和隨機分類器不一樣。顯然你沒法經過集成隨機分類器獲得什麼有價值的東西)
其具體步驟大體以下:
1. 對每一個樣本給定一個權重 d。
2. 基於權重向量 D 調用一次弱分類器並得出此次統計的分類器權重值 alpha (注意是分類器權重值,上一步的)
3. 基於分類器權重值 alpha 更新各個樣本的權重向量
4. 循環 2 - 3 直到錯誤率爲 0 或者循環到了指定的次數
5. 1-4 爲訓練部分算法,訓練好了以後,即可帶入樣本進行分類。分類的方法是依次帶入訓練集中的各個分類器中求出分類結果,而後各部分結果乘以其對應的分類器權重值 alpha 再累加求和。
下圖可用來幫助理解 (直方圖中的矩形長度表示樣本權重,三角形中的值表示分類器權重值 alpha):
基於單層決策樹的 AdaBoost 元算法分類器實現
首先,準備好單層決策樹的數據結構。
在本文的 AdaBoost 實現中,元算法中的分類器組合模式是 "同一算法在不一樣設置下的集成",那麼不一樣設置不一樣在哪裏?
不一樣就不一樣在每次構建單層決策樹都是選擇劃分正確率最高的劃分方式。
所以在構建單層決策樹函數中,必須有一個擇優過程,具體能夠參考下面的實現代碼。
函數的功能應當是返回一個單層決策樹信息結構(僅僅是劃分信息就能夠了不用數據)
同時,函數應該返回一個錯誤信息值,這個錯誤值是和權重向量D相關的,用於計算分類器權重值 alpha。(固然也能夠在該函數內部實現該字段)
最後,分類結果天然也要返回。
單層決策樹代碼實現以下:
1 #========================================== 2 # 輸入: 3 # dataMatrix: 輸入數據 4 # dimen: 劃分特徵下標 5 # threshVal: 劃分閾值 6 # threshIneq: 劃分方向(是左1右0分類仍是左0右1分類) 7 # 輸出: 8 # retArray: 分類結果 9 #========================================== 10 def stumpClassify(dataMatrix,dimen,threshVal,threshIneq): 11 '按照指定方式分類並返回結果' 12 13 retArray = numpy.ones((numpy.shape(dataMatrix)[0],1)) 14 if threshIneq == 'lt': 15 retArray[dataMatrix[:,dimen] <= threshVal] = -1.0 16 else: 17 retArray[dataMatrix[:,dimen] > threshVal] = -1.0 18 19 return retArray 20 21 22 #========================================== 23 # 輸入: 24 # dataArr: 輸入數據 25 # classLabels: 分類標籤集 26 # D: 權重向量 27 # 輸出: 28 # bestStump: 決策樹信息 29 # minError: 帶權錯誤(用於生成分類器權重值 alpha) 30 # bestClasEst: 分類結果 31 #========================================== 32 def buildStump(dataArr,classLabels,D): 33 '建立單層最佳決策樹' 34 35 dataMatrix = numpy.mat(dataArr); 36 labelMat = numpy.mat(classLabels).T 37 m,n = numpy.shape(dataMatrix) 38 39 # 特徵值閾值步長 40 numSteps = 10.0; 41 # 當前最佳決策樹信息集 42 bestStump = {}; 43 # 分類結果 44 bestClasEst = numpy.mat(numpy.zeros((m,1))) 45 # 最小帶權錯誤初始化爲無窮大 46 minError = numpy.inf 47 48 for i in range(n): # 遍歷全部的特徵選取最佳劃分特徵 49 rangeMin = dataMatrix[:,i].min(); 50 rangeMax = dataMatrix[:,i].max(); 51 stepSize = (rangeMax-rangeMin)/numSteps 52 53 for j in range(-1,int(numSteps)+1): # 遍歷全部的特徵值選取最佳劃分特徵值 stepSize爲探測步長 54 55 for inequal in ['lt', 'gt']: # 對於 左1右0 和 左0右1 兩種分類方式 56 57 # 當前劃分閾值 58 threshVal = (rangeMin + float(j) * stepSize) 59 # 分類 60 predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal) 61 # 統計分類錯誤信息 62 errArr = numpy.mat(numpy.ones((m,1))) 63 errArr[predictedVals == labelMat] = 0 64 weightedError = D.T*errArr 65 66 # 更新最佳決策樹的信息 67 if weightedError < minError: 68 minError = weightedError 69 bestClasEst = predictedVals.copy() 70 bestStump['dim'] = i 71 bestStump['thresh'] = threshVal 72 bestStump['ineq'] = inequal 73 74 return bestStump,minError,bestClasEst
在單層決策樹之上,即是 AdaBoost 分類器的實現,下面先給出僞代碼:
1 對每次迭代: 2 找到最佳單層決策樹 3 將該樹加入到最佳決策樹數組 4 計算分類器權重 alpha 5 更新權重向量 D 6 更新累計類別估計值 7 PS: 若是錯誤率等於0.0,則立馬退出循環。
Python 代碼實現以下:
1 #========================================== 2 # 輸入: 3 # dataArr: 輸入數據 4 # classLabels: 分類標籤集 5 # numIt: 最大迭代次數 6 # 輸出: 7 # bestStump: 決策樹信息 8 # minError: 帶權錯誤(用於生成分類器權重值 alpha) 9 # bestClasEst: 分類結果 10 #========================================== 11 def adaBoostTrainDS(dataArr,classLabels,numIt=40): 12 'AdaBoost 分類器' 13 14 # 最佳決策樹集合 15 weakClassArr = [] 16 # 樣本個數 17 m = numpy.shape(dataArr)[0] 18 # 權重向量 19 D = numpy.mat(numpy.ones((m,1))/m) 20 # 各個類別的估計累積值 21 aggClassEst = numpy.mat(numpy.zeros((m,1))) 22 23 for i in range(numIt): # 迭代 numIt 次 24 # 構建最佳決策樹 25 bestStump,error,classEst = buildStump(dataArr,classLabels,D) 26 # 計算該決策樹的分類器權重值 alpha 27 alpha = float(0.5*numpy.log((1.0-error)/max(error,1e-16))) 28 bestStump['alpha'] = alpha 29 # 將該決策樹加入到決策樹數組中去 30 weakClassArr.append(bestStump) 31 32 # 更新權重向量 33 expon = numpy.multiply(-1*alpha*numpy.mat(classLabels).T,classEst) 34 D = numpy.multiply(D,numpy.exp(expon)) 35 D = D/D.sum() 36 37 # 計算當前的總錯誤率。若是錯誤率爲0則退出循環。 38 aggClassEst += alpha*classEst 39 aggErrors = numpy.multiply(numpy.sign(aggClassEst) != numpy.mat(classLabels).T,numpy.ones((m,1))) 40 errorRate = aggErrors.sum()/m 41 print "錯誤率: ",errorRate 42 if errorRate == 0.0: break 43 44 return weakClassArr
至此,就能夠用 AdaBoost 進行分類了。
首先訓練出一個訓練集,而後將訓練集帶入分類函數,以下:
1 # 獲取訓練集 2 classifierArr = adaBoostTrainDS(daaArr, labelArr, 30) 3 # 分類並打印結果 4 print adaClassify([0,0], classifierArr)
測試結果:
顯然,能夠看出 AdaBoost 分類器由三個決策樹構成。樣本最終分類結果爲 -1。
小結
本文介紹了分類器中的元算法思想。經過這樣的思想,可以將多種分類器組合起來,大大地增強了分類性能。
另外據可靠數據分析,較之 邏輯迴歸,AdaBoost 分類器沒有過分擬合(overfitting)現象。
Boost算法還有不少種,AdaBoost 只是其中最爲經典的實現之一,還有更多高級實習須要在往後學習工做中進行研究。