機器學習實戰筆記(Python實現)-06-AdaBoost


---------------------------------------------------------------------------------------

本系列文章為《機器學習實戰》學習筆記,內容整理自書本,網絡以及自己的理解,如有錯誤歡迎指正。

源碼在Python3.5上測試均通過,代碼及數據 --> https://github.com/Wellat/MLaction

---------------------------------------------------------------------------------------   

1、基於數據集多重抽樣的分類器

1.1 bagging

自舉匯聚法(bootstrap aggregating),也稱為bagging方法,是在從原始數據集選擇S次后得到S個新數據集的一種技術。新數據集和原數據集的大小相等,每個數據集都是在原始數據集中有放回隨機選擇樣本得到,這意味着新數據集中可以有重復的樣本,也可能沒有包括原數據集的所有樣本。

在S個數據集建好之后,將某個學習算法分別作用於每個數據集就得到了S個分類器。當我們要對新數據進行分類時,就可以應用這S個分類器進行分類。與此同時,選擇分類器投票結果中最多的類別作為最后的分類結果。

1.2 boosting

boosting和bagging很類似,他們使用相同類型的分類器,但是在boosting中,不同的分類器是通過串行訓練而獲得的。Boosting集中關注被已有分類器錯分的那些數據來獲得新的分類器。

由於boosting分類的結果是基於所有分類器的加權求和的結果,所以在boosting中分類器的權重並不相等,每個權重代表的是其對於分類器在上一輪迭代中的成功度。

Boosting方法有多個版本,本節只關注其中一個最流行的版本AdaBoost。

1.3 AdaBoost

AdaBoost是adaptive boosting(自適應boosting)的縮寫,它的理論根植於使用弱分離器和多個實例來構建一個強分類器。這里的“弱”意味着分類器的性能比隨機猜測要略好,但是也不會好太多;而“強”分類器的錯誤率將會低很多。

其運行過程如下:訓練數據中的每個樣本,並賦予其一個權重,這些權重構成了向量D。一開始,這些權重都初始化成相等值。首先在訓練數據上訓練出一個弱分類器並計算該分類器的錯誤率,然后在同一數據集上再次訓練弱分類器。在分類器的第二次訓練當中,將會重新調整每個樣本的權重,其中第一次分對的樣本的權重將會降低,而第一次分錯的樣本的權重將會提高。為了從所有弱分類器中得到最終的分類結果,AdaBoost為每個分類器都分配了一個權重值alpha,這些alpha值是基於每個弱分類器的錯誤率進行計算的。其中,錯誤率ε的定義為:

而alpha的計算公式為:

AdaBoost算法流程如下圖:

計算出alpha值之后,可以對權重向量D進行更新,以使得那些正確分類的樣本的權重降低而錯分樣本的權重升高。

如果某個樣本被正確分類,權重更改為:

而如果被錯分,權重則更改為:

在計算出D之后,AdaBoost又開始進入下一輪迭代,知道訓練錯誤率為0或者弱分類器的數目達到用戶指定值為止。

2、AdaBoost算法的實現

2.1 構建弱分類器

單層決策樹是AdaBoost中最流行的弱分類器。

算法偽代碼↓

 1 def buildStump(dataArr,classLabels,D):
 2     '''
 3     建立一個單層決策樹
 4     輸人為權重向量D,
 5     返回具有最小錯誤率的單層決策樹、最小的錯誤率以及估計的類別向量
 6     '''    
 7     dataMatrix = mat(dataArr); labelMat = mat(classLabels).T
 8     m,n = shape(dataMatrix)
 9     numSteps = 10.0; bestStump = {}; bestClasEst = mat(zeros((m,1)))
10     minError = inf #
11     for i in range(n):#對數據集中的每一個特征
12         rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max();
13         stepSize = (rangeMax-rangeMin)/numSteps
14         for j in range(-1,int(numSteps)+1):#對每個步長
15             for inequal in ['lt', 'gt']: #對每個不等號
16                 threshVal = (rangeMin + float(j) * stepSize)
17                 predictedVals = stumpClassify(dataMatrix,i,threshVal,inequal)
18                 errArr = mat(ones((m,1)))
19                 errArr[predictedVals == labelMat] = 0
20                 weightedError = D.T*errArr  #計算加權錯誤率
21                 #print("split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError))
22                 #如果錯誤率低於minError,則將當前單層決策樹設為最佳單層決策樹                
23                 if weightedError < minError:
24                     minError = weightedError
25                     bestClasEst = predictedVals.copy()
26                     bestStump['dim'] = i
27                     bestStump['thresh'] = threshVal
28                     bestStump['ineq'] = inequal
29     return bestStump,minError,bestClasEst
30 
31 def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
32     '''
33     通過閾值比較對數據進行分類    
34     '''
35     retArray = ones((shape(dataMatrix)[0],1))
36     if threshIneq == 'lt':
37         retArray[dataMatrix[:,dimen] <= threshVal] = -1.0
38     else:
39         retArray[dataMatrix[:,dimen] > threshVal] = -1.0
40     return retArray

 

2.2 基於單層決策樹的AdaBoost訓練過程

算法偽代碼↓

 1 def loadSimpData():
 2     '''
 3     導入簡單訓練數據    
 4     '''
 5     datMat = matrix([[ 1. ,  2.1],
 6         [ 2. ,  1.1],
 7         [ 1.3,  1. ],
 8         [ 1. ,  1. ],
 9         [ 2. ,  1. ]])
10     classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
11     return datMat,classLabels
12 
13 def adaBoostTrainDS(dataArr,classLabels,numIt=40):
14     '''
15     基於單層決策樹的AdaBoost訓練過程
16     '''
17     weakClassArr = []
18     m = shape(dataArr)[0]
19     D = mat(ones((m,1))/m)   #初始化權重向量為1/m
20     aggClassEst = mat(zeros((m,1)))#記錄每個數據點的類別估計累計值
21     for i in range(numIt):
22         #建立一個單層決策樹
23         bestStump,error,classEst = buildStump(dataArr,classLabels,D)
24         print("D:",D.T)
25         #計算alpha,此處分母用max(error,1e-16)以防止error=0
26         alpha = float(0.5*log((1.0-error)/max(error,1e-16)))
27         bestStump['alpha'] = alpha  
28         weakClassArr.append(bestStump)
29         print("classEst: ",classEst.T)
30         #計算下一次迭代的D
31         expon = multiply(-1*alpha*mat(classLabels).T,classEst)
32         D = multiply(D,exp(expon))                              
33         D = D/D.sum()
34         #以下計算訓練錯誤率,如果總錯誤率為0,則終止循環
35         aggClassEst += alpha*classEst
36         print("aggClassEst: ",aggClassEst.T)
37         aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
38         errorRate = aggErrors.sum()/m
39         print("total error: ",errorRate)
40         if errorRate == 0.0: break
41     return weakClassArr,aggClassEst

2.3 簡單測試分類效果

 1 def adaClassify(datToClass,classifierArr):
 2     '''
 3     利用訓練出的多個弱分類器進行分類    
 4     datToClass:待分類數據
 5     classifierArr:訓練的結果
 6     '''
 7     dataMatrix = mat(datToClass)
 8     m = shape(dataMatrix)[0]
 9     aggClassEst = mat(zeros((m,1)))
10     #遍歷classifierArr中的所有弱分類器,並基於stumpClassify對每個分類器得到一個類別的估計值
11     for i in range(len(classifierArr)):
12         classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],\
13                                  classifierArr[i]['thresh'],\
14                                  classifierArr[i]['ineq'])
15         aggClassEst += classifierArr[i]['alpha']*classEst
16         print(aggClassEst)
17     return sign(aggClassEst)

按如下指令測試:

3、實例:在馬疝病數據集上應用AdaBoost分類器

前面一個章節中曾利用Logistic回歸來預測患有疝病的馬是否能夠存活,而在本節我們將利用多個單層決策樹和AdaBoost來預測。

 1 def loadDataSet(fileName):
 2     '''讀取數據函數'''
 3     numFeat = len(open(fileName).readline().split('\t')) #獲取列數,默認最后一列為類標簽且類標簽為+1和-1
 4     dataMat = []; labelMat = []
 5     fr = open(fileName)
 6     for line in fr.readlines():
 7         lineArr =[]
 8         curLine = line.strip().split('\t')
 9         for i in range(numFeat-1):
10             lineArr.append(float(curLine[i]))
11         dataMat.append(lineArr)
12         labelMat.append(float(curLine[-1]))
13     return dataMat,labelMat
14 
15 if __name__ == "__main__":
16     
17     '''馬疝病測試'''
18     #導入訓練數據
19     datArr,labelArr = loadDataSet('horseColicTraining2.txt')
20     weakClassArr,aggClassEst = adaBoostTrainDS(datArr,labelArr,10)
21     #導入測試數據
22     testArr,testLabelArr = loadDataSet('horseColicTest2.txt')
23     prediction = adaClassify(testArr,weakClassArr) 
24     #計算錯誤率
25     errArr = mat(ones((67,1)))
26     errArr[prediction != mat(testLabelArr).T].sum()/67

將弱分類器的數目設定為1到10000之間的幾個不同數字,並運行上述過程。得到如下結果

在同一數據集上采用Logistic回歸得到的平均錯誤率為0.35,而使用AdaBoost方法,從表中可以看出,僅僅使用50個弱分類器就達到了較高的性能。

 

 

 

THE END.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM