1. 程式人生 > >機器學習實戰之adaboost

機器學習實戰之adaboost

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)程式碼實現

  • 單層決策樹生成
下面的函式基於資料集的第dimen維特徵分類,返回當前樣本的分類結果;臨界值是threshval,有2種可能,第一種大於臨界值的為1,第二種大於臨界值的為-1.threshineq決定是哪種可能.
<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>