機器學習實戰之adaboost
阿新 • • 發佈:2019-01-08
1.概念定義
(1)元演算法(meta-algorithm)/整合方法(ensemble method): 是對其他演算法進行組合的一種方式.有多種整合方式:
- 不同演算法的整合;
- 同一演算法在不同設定下的整合
- 資料集不同部分分配給不同分類器之後的整合
(2)單層決策樹(decision stump ): 是一個只有一個節點的決策樹;僅僅基於單個特徵來做決策.只有一個分裂過程.例如大於5的為型別1,小於5的型別為-1;
2. 幾種整合演算法
(1)bagging,自舉匯聚法(bootstrap aggregating):
- 是從原始資料集中選擇s次得到s個新資料集的一種方法,新資料集和原始資料集大小一樣,每個資料集都是通過在原始資料集中隨機選擇一個樣本組合而成的,這屬於有放回的取樣,這一特點使得原始資料集中可以有重複的值,且原始資料集中的有些值在新資料集中不出現.
- 得到s個數據集之後,使用某個學習演算法(例如決策樹等等)分別作用於每個資料集得到s個分類器.
- 當進行分類時,應用這s個分類器分別對新資料進行分類,選擇分類器分類結果中最多的類別作為最後的分類結果.
(2)boosting
- 不同的分類器是通過序列訓練得到的,而bagging是並行的,不同分類器是相互獨立的;每個新分類器都根據已訓練出的分類器的效能來進行訓練.boosting通過關注被已有分類器錯分類的那些資料來獲得新的分類器.
- boosting的分類結果是基於所有分類器的加權求和結果的,bagging中分類器權重都是一樣的,boosting中的分類器權重不相等,每個權重代表其對應分類器在上一輪迭代中的正確分類率.
3.adaboost(adaptive boosting)
(1)一般流程
- 準備資料:依賴於選擇的弱分類器,本次將選擇單層決策樹,這種分類器可以處理任何資料型別;作為弱分類器,簡單分類器的效果更好.
- 訓練演算法:adaboost的大部分時間使用在訓練上,分類器將多次在同一資料集上訓練若分類器;
- 測試演算法:計算錯分類的概率
- 使用場所:adaboost預測屬於兩個類別中的哪一個.若要將其使用在多分類場合,要做一定的修改.
(2)執行過程
- 訓練資料中的每個樣本,並賦予其一個權重,權重向量為W,權重初始化為相等值;即1/所有的樣本數
- 首先在訓練資料上訓練出一個弱分類器並計算其分類的錯誤率,錯誤率=未正確分類的樣本數/所有樣本數
- 繼續在同一資料集上訓練另一個弱分類器,在第二次訓練之前,將會調整每個訓練樣本的權重值,其中第一次分對的樣本的權重會降低,第一次分錯的樣本權重會提高.
- 為了將所有的弱分類器組合得到最終的分類器,adaboost為每個弱分類器分配了一個權重值alpha,這些alpha值基於每個弱分類器的錯誤率計算的, alpha=1/2*ln((1-錯誤率)/錯誤率)
- 根據alpha值對每個樣本的權重進行修改:修改規則是正確分類的權重降低,錯分類的權重增加
- 更新樣本權重之後,開始第二次訓練.不斷重複訓練的調整權重的過程,直到訓練錯誤率為0或者弱分類器的數目達到使用者的指定值為止.
(3)程式碼實現
- 單層決策樹生成
<span style="font-size:14px;">def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
returnArray = ones((shape(dataMatrix)[0],1))
if threshIneq == 'lessthan':
returnArray[dataMatrix[:,dimen] <= threshVal] = -1.0
else:
returnArray[dataMatrix[:,dimen] > threshVal] = -1.0
return returnArray</span>
下面的函式產生當前權重向量下最適合資料集的單層決策樹;輸入訓練樣本資料集以及其對應的類別標籤,D是樣本權重向量.
<span style="font-size:14px;">def buildStump(dataArr,classLabels,D):
dataMatrix = mat(dataArr); labelMatrix = mat(classLabels).T
m,n = shape(dataMatrix)
numSteps = 10.0;bestStump ={}
bestClasEst = mat(zeros((m,1)))
minError = inf
for i in range(n):
rangeMin = dataMatrix[:,i].min()
rangeMax = dataMatrix[:,i].max()
stepSize = (rangeMax - rangeMin)/numSteps #對該維的每個所有可能取值進行遍歷,以找到最適合的臨界值
for j in range(-1,int(numSteps)+1):
for inequal in ['lessthan','greaterthan']:
threshVal = rangeMin + float(j) * stepSize
predictVals = stumpClassify(dataMatrix,i,threshVal,inequal)
errArr = mat(ones((m,1)))
errArr[predictVals == labelMatrix] = 0
weightedError = D.T * errArr #根據權重向量計算錯誤分類誤差
if weightedError < minError:
minError = weightedError
bestClasEst = predictVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump,minError,bestClasEst
</span>
- adaboost訓練演算法
實現虛擬碼如下:
對每次迭代:
利用buildStump()函式找到基於當前樣本權重向量D下的最佳決策單層決策樹
將最佳單層決策樹加入到單層決策樹陣列
計算alpha
計算新的樣本權重向量D
更新整合的類別估計值(已有的弱分類器分類結果的疊加)
如果錯誤率等於0,則退出迴圈
實現程式碼:
<span style="font-size:14px;">def adaBoostTrain(dataArr,classLabels,numIter = 40):
weakClassifier = [] #儲存每個弱分類器的資訊
m,n = shape(dataArr)
#initialize the weight of every sample
W = mat(ones((m,1))/m)
aggClassEst = mat(zeros((m,1))) #累計類別的估計值,將已有的弱分類器的反而類結果乘以它們對應的權重加起來,構成最後的分類器
for i in range(numIter):
bestStump,error,classEst = buildStump(dataArr,classLabels,W)
#print "W:" , W.T
alpha = float(0.5*log((1.0-error)/max(error,1e-16))) #分母不只是error,是為了確保在沒有錯誤時不睡發生除0溢位.故取其和一個很小值的最大值,防止errro為0的情況發生
bestStump['alpha'] = alpha
weakClassifier.append(bestStump)
#print "classEst: ",classEst.T
expon = multiply(-1*alpha*mat(classLabels).T,classEst)
W = multiply(W,exp(expon))
W = W/W.sum()
aggClassEst += alpha*classEst
#print "aggClassEst: ", aggClassEst.T
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1))) #sign是為了得到二值分類結果
errorRate = aggErrors.sum()/m
print "the error is : ",errorRate,"\n"
if errorRate == 0.0:
break
return weakClassifier</span>
- adaboost分類函式
所有弱分類器的加權求和就是最後的結果.輸入為待分類的特徵向量以及訓練得到的弱分類器的陣列集合.
<span style="font-size:14px;">def adaClassify(dataToClass,classifier):
dataMatrix = mat(dataToClass)
m = shape(dataMatrix)[0]
aggClassEst = mat(zeros((m,1)))
for i in range(len(classifier)):
classEst = stumpClassify(dataMatrix,classifier[i]['dim'],classifier[i]['thresh'],classifier[i]['ineq'])
aggClassEst += classifier[i]['alpha'] * classEst #弱分類器的加權結果求和
print aggClassEst
return sign(aggClassEst) #得到二值分類結果</span>