Adaboost
Adaboost算法概述
Adaboost算法核心思想:“三個臭皮匠賽過一諸葛亮”。我們平常構建的分類模型可以說是弱分類器,若將這些弱分類器組合起來可以成為一個強分類器。大多數的提升方法是該表訓練數據的概率分布(訓練數據的權值分布),針對不同的訓練數據分布調用弱學習算法學習。
如何改變訓練數據的權值分布:第一輪初始化均勻分布樣本權值,往后每一輪,提高那些被前一輪弱分期錯誤分類樣本的權值,而降低那些被正確分類樣本的權值。這樣錯誤分類的樣本權值加大會受到后一輪弱分類器的更大關注,于是分類問題被一系列的弱分類器分而治之
如何將弱分類器組合成強分類器:Adaboost采取多數表決的方法。即加大分類誤差率小的弱分類器的權值,減少分類誤差率大的弱分類器的權值。
adaBoost的運行過程
訓練數據的每一個樣本,并賦予其一個權重,這些權值構成權重向量D,維度等于數據集樣本個數。開始時,這些權重都是相等的,首先在訓練數據集上訓練出一個弱分類器并計算該分類器的錯誤率,然后在同一數據集上再次訓練弱分類器,但是在第二次訓練時,將會根據分類器的錯誤率,對數據集中樣本的各個權重進行調整,分類正確的樣本的權重降低,而分類錯的樣本權重則上升,但這些權重的總和保持不變為1.
并且,最終的分類器會基于這些訓練的弱分類器的分類錯誤率,分配不同的決定系數alpha,錯誤率低的分類器獲得更高的決定系數,從而在對數據進行預測時起關鍵作用。alpha的計算根據錯誤率得來:
alpha=0.5*ln(1-ε/max(ε,1e-16))
其中,ε=為正確分類的樣本數目/樣本總數,max(ε,1e-16)是為了防止錯誤率為而造成分母為0的情況發生
計算出alpha之后,就可以對權重向量進行更新了,使得分類錯誤的樣本獲得更高的權重,而分類正確的樣本獲得更低的權重。D的計算公式如下:
如果某個樣本被正確分類,那么權重更新為:
D(m+1,i)=D(m,i)*exp(-alpha)/sum(D)
如果某個樣本被錯誤分類,那么權重更新為:
D(m+1,i)=D(m,i)*exp(alpha)/sum(D)
其中,m為迭代的次數,即訓練的第m個分類器,i為權重向量的第i個分量,i<=數據集樣本數量
當我們更新完各個樣本的權重之后,就可以進行下一次的迭代訓練。adaBoost算法會不斷重復訓練和調整權重,直至達到迭代次數,或者訓練錯誤率為0。
基于單層決策樹構建弱分類器
單層決策樹是一種簡單的決策樹,也稱為決策樹樁。單層決策樹可以看做是由一個根節點直接連接兩個葉結點的簡單決策樹,比如x>v或x<v,就可以看做是一個簡單決策樹。
為了更好的演示adaBoost的訓練過程,我們首先建立一個簡單的數據集,并將其轉為我們想要的數據格式,代碼如下:
#獲取數據集
def loadSimpData():
dataMat=matrix([[1. ,2.1],
[2. ,1.1],
[1.3,1. ],
[1. ,1. ],
[2. ,1. ]])
classLabels=[1.0,1.0,-1.0,-1.0,1.0]
return dataMat,classLabels
接下來,我們就要通過上述數據集來尋找最佳的單層決策樹,最佳單層決策樹是具有最低分類錯誤率的單層決策樹,偽代碼如下:
#構建單層分類器
#單層分類器是基于最小加權分類錯誤率的樹樁
#偽代碼
#將最小錯誤率minError設為+∞
#對數據集中的每個特征(第一層特征):
#對每個步長(第二層特征):
#對每個不等號(第三層特征):
#建立一顆單層決策樹并利用加權數據集對它進行測試
#如果錯誤率低于minError,則將當前單層決策樹設為最佳單層決策樹
#返回最佳單層決策樹
接下來看單層決策樹的生成函數代碼:
#單層決策樹的閾值過濾函數
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq):
#對數據集每一列的各個特征進行閾值過濾
retArray=ones((shape(dataMatrix)[0],1))
#閾值的模式,將小于某一閾值的特征歸類為-1
if threshIneq=='lt':
retArray[dataMatrix[:,dimen]<=threshVal]=-1.0
#將大于某一閾值的特征歸類為-1
else:
retArray[dataMatrix[:,dimen]>threshVal]=-1.0
def buildStump(dataArr,classLabels,D):
#將數據集和標簽列表轉為矩陣形式
dataMatrix=mat(dataArr);labelMat=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 ['lt','gt']:
#閾值計算公式:最小值+j(-1<=j<=numSteps+1)*步長
threshVal=(rangeMin+float(j)*stepSize)
#選定閾值后,調用閾值過濾函數分類預測
predictedVals=
stumpClassify(dataMatrix,i,threshVal,'inequal')
#初始化錯誤向量
errArr=mat(ones((m,1)))
#將錯誤向量中分類正確項置0
errArr[predictedVals==labelMat]=0
#計算"加權"的錯誤率
weigthedError=D.T*errArr
#打印相關信息,可省略
#print("split: dim %d, thresh %.2f,thresh inequal:
# %s, the weighted error is %.3f",
# %(i,threshVal,inequal,weigthedError))
#如果當前錯誤率小于當前最小錯誤率,將當前錯誤率作為最小錯誤率
#存儲相關信息
if weigthedError<minError:
minError=weigthedError
bestClasEst=predictedVals.copy()
bestStump['dim']=i
bestStump['thresh']='threshVal'
bestStump['ineq']=inequal
#返回最佳單層決策樹相關信息的字典,最小錯誤率,決策樹預測輸出結果
return bestStump,minError,bestClasEst
需要說明的是,上面的代碼包含兩個函數,第一個函數是分類器的閾值過濾函數,即設定某一閾值,凡是超過該閾值的結果被歸為一類,小于閾值的結果都被分為另外一類,這里的兩類依然同SVM一樣,采用+1和-1作為類別。
完整AdaBoost算法實現
上面已經構建好了基于加權輸入值進行決策的單層分類器,那么就已經有了實現一個完整AdaBoost算法所需要的所有信息了。下面先看一下整個AdaBoost的偽代碼實現:
#完整AdaBoost算法實現
#算法實現偽代碼
#對每次迭代:
#利用buildStump()函數找到最佳的單層決策樹
#將最佳單層決策樹加入到單層決策樹數組
#計算alpha
#計算新的權重向量D
#更新累計類別估計值
#如果錯誤率為等于0.0,退出循環
再來看看具體的實現代碼吧:
#adaBoost算法
#@dataArr:數據矩陣
#@classLabels:標簽向量
#@numIt:迭代次數
def adaBoostTrainDS(dataArr,classLabels,numIt=40):
#弱分類器相關信息列表
weakClassArr=[]
#獲取數據集行數
m=shape(dataArr)[0]
#初始化權重向量的每一項值相等
D=mat(ones((m,1))/m)
#累計估計值向量
aggClassEst=mat((m,1))
#循環迭代次數
for i in range(numIt):
#根據當前數據集,標簽及權重建立最佳單層決策樹
bestStump,error,classEst=buildStump(dataArr,classLabels,D)
#打印權重向量
print("D:",D.T)
#求單層決策樹的系數alpha
alpha=float(0.5*log((1.0-error)/(max(error,1e-16))))
#存儲決策樹的系數alpha到字典
bestStump['alpha']=alpha
#將該決策樹存入列表
weakClassArr.append(bestStump)
#打印決策樹的預測結果
print("classEst:",classEst.T)
#預測正確為exp(-alpha),預測錯誤為exp(alpha)
#即增大分類錯誤樣本的權重,減少分類正確的數據點權重
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,"
")
#錯誤率為0.0退出循環
if errorRate==0.0:break
#返回弱分類器的組合列表
return weakClassArr
測試算法
那么有了訓練好的分類器,是不是要測試一下呢,畢竟訓練錯誤率針對的是已知的數據,我們需要在分類器未知的數據上進行測試,看看分類效果。上面的訓練代碼會幫我們保存每個弱分類器的重要信息,比如分類器系數,分類器的最優特征,特征閾值等。有了這些重要的信息,我們拿到之后,就可以對測試數據進行預測分類了
#測試adaBoost,adaBoost分類函數
#@datToClass:測試數據點
#@classifierArr:構建好的最終分類器
def adaClassify(datToClass,classifierArr):
#構建數據向量或矩陣
dataMatrix=mat(datToClass)
#獲取矩陣行數
m=shape(dataMatrix)[0]
#初始化最終分類器
aggClassEst=mat(zeros((m,1)))
#遍歷分類器列表中的每一個弱分類器
for i in range(len(classifierArr)):
#每一個弱分類器對測試數據進行預測分類
classEst=stumpClassify(dataMat,classifierArr[i]['dim'],
classifierArr[i]['thresh'],
classifierArr[i]['ineq'])
#對各個分類器的預測結果進行加權累加
aggClassEst+=classifierArr[i]['alpha']*classEst
print('aggClassEst',aggClassEst)
#通過sign函數根據結果大于或小于0預測出+1或-1
return sign(aggClassEst)
總結
- 上一篇: matlab sign函数用法及实例
- 下一篇: translate 和 translat