機器學習實戰之AdaBoost元算法

今天學習的機器學習算法不是一個單獨的算法,我們稱之爲元算法或集成算法(Ensemble)。其實就是對其他算法進行組合的一種方式。俗話說的好:“三個臭皮匠,賽過諸葛亮”。集成算法有多種形式:對同一數據集,使用多個算法,通過投票或者平均等方法獲得最後的預測模型;同一算法在不同設置下的集成;同一算法在多個不同實例下的集成。本文着重講解最後一種集成算法。

bagging

如果訓練集有n個樣本,我們隨機抽取S次,每次有放回的獲取m個樣本,用某個單獨的算法對S個數據集(每個數據集有m個樣本)進行訓練,這樣就可以獲得S個分類器。最後通過投票箱來獲取最後的結果(少數服從多數的原則)。這就是bagging方法的核心思想,如圖所示。

bagging中有個常用的方法,叫隨機森林(random forest),該算法基於決策樹,不僅對數據隨機化,也對特徵隨機化。

數據的隨機化:應用bootstrap方法有放回地隨機抽取k個新的自助樣本集。

特徵隨機化:n個特徵,每棵樹隨機選擇m個特徵劃分數據集。

每棵樹無限生長,最後依舊通過投票箱來獲取最後的結果。

boosting

boosting方法在模型選擇方面和bagging一樣:選擇單個機器學習算法。但boosting方法是先在原數據集中訓練一個分類器,然後將前一個分類器沒能完美分類的數據重新賦權重(weight),用新的權重數據再訓練出一個分類器,以此循環,最終的分類結果由加權投票決定。所以:boosting是串行算法(必須依賴上一個分類器),而bagging是並行算法(可以同時進行);boosting的分類器權重不同,bagging相同(下文中詳細講解)。

boosting也有很多版本,本文只講解AdaBoost(自適應boosting)方法的原理和代碼實踐。如圖所示,爲AdaBoost方法的原理示意圖。

首先,訓練樣本賦權重,構成向量D(初始值相等,如100個數據,那每個數據權重爲1/100)。

在該數據上訓練一個弱分類器並計算錯誤率和該分類器的權重值(alpha)。

基於該alpha值重新計算權重(分錯的樣本權重變大,分對的權重變小)。

循環2,3步,但完成給定的迭代次數或者錯誤閾值時,停止循環。

最終的分類結果由加權投票決定。

alpha和D的計算見下圖(來源於機器學習實戰):

AdaBoost方法實踐

數據來源

數據通過代碼創建:

from numpy import *

def loadSimpData():

dataArr = array([[1., 2.1], [2., 1.1], [1.3, 1.], [1., 1.], [2., 1.]])

labelArr = [1.0, 1.0, -1.0, -1.0, 1.0]

return dataArr, labelArr

弱決策樹

該數據有兩個特徵,我們只用一個特徵進行分類(弱分類器),然後選擇精度最高的分類器。

def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):

retArray = ones((shape(dataMatrix)[0],1))

if threshIneq == 'lt':

retArray[dataMatrix[:,dimen] <= threshVal] = -1.0

else:

retArray[dataMatrix[:,dimen] > threshVal] = -1.0

return retArray

def buildStump(dataArr, labelArr, D):

dataMat = mat(dataArr)

labelMat = mat(labelArr).T

m, n = shape(dataMat)

numSteps = 10.0

bestStump = {}

bestClasEst = mat(zeros((m, 1)))

minError = inf

for i in range(n):

rangeMin = dataMat[:, i].min()

rangeMax = dataMat[:, i].max()

stepSize = (rangeMax-rangeMin)/numSteps

for j in range(-1, int(numSteps)+1):

for inequal in ['lt', 'gt']:

threshVal = (rangeMin + float(j) * stepSize)

predictedVals = stumpClassify(dataMat, i, threshVal, inequal)

# print predictedVals

errArr = mat(ones((m, 1)))

errArr[predictedVals == labelMat] = 0

weightedError = D.T*errArr

# print("split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError))

if weightedError < minError:

minError = weightedError

bestClasEst = predictedVals.copy()

bestStump['dim'] = i

bestStump['thresh'] = threshVal

bestStump['ineq'] = inequal

return bestStump, minError, bestClasEst

AdaBoost算法

該函數用於構造多棵樹,並保存每棵樹的信息。

def adaBoostTrainDS(dataArr,classLabels, numIt=40):

weakClassArr = []

m = shape(dataArr)[0]

D = mat(ones((m,1))/m)

aggClassEst = mat(zeros((m,1)))

for i in range(numIt):

bestStump,error,classEst = buildStump(dataArr, classLabels, D)

print('D:',D.T)

alpha = float(0.5*log((1.0-error)/max(error,1e-16)))

bestStump['alpha'] = alpha

weakClassArr.append(bestStump)

print('classEst:',classEst.T)

expon = multiply(-1*alpha*mat(classLabels).T,classEst)

D = multiply(D, exp(expon))

D = D/D.sum()

aggClassEst += alpha*classEst

print('aggClassEst:',aggClassEst.T)

aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m,1)))

errorRate = aggErrors.sum()/m

print('total error:',errorRate,'\n')

if errorRate == 0:break

return weakClassArr

算法優缺點

優點:精度高

缺點:容易過擬合

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章