機器學習實戰——AdaBoost

書籍:《機器學習實戰》中文版
IDE:Spyder

環境:Adaconda3  python3.6

(Spyder相對pycharm來說,比較簡潔,而且對於常用matlab的人,感覺更親切。它可以方便的觀察變量值,查看運行結果等。但是spyder沒有代碼摺疊!代碼提示方面也遠不如pycharm!)


Ensemble方法:集合方法,將弱分類器變成一個強分類器。

可以是不同算法的集成、同一算法在不同設置下的集成、數據集不同部分分配給不同分類器之後的集成。


一、基本概念 

1、bagging方法

Bagging即套袋法,其算法過程如下:

1)從原始樣本集中抽取訓練集。每輪從原始樣本集中使用Bootstraping的方法抽取n個訓練樣本(在訓練集中,有些樣本可能被多次抽取到,而有些樣本可能一次都沒有被抽中)。共進行k輪抽取,得到k個訓練集。(k個訓練集之間是相互獨立的)

2)每次使用一個訓練集得到一個模型,k個訓練集共得到k個模型。(注:這裏並沒有具體的分類算法或迴歸方法,我們可以根據具體問題採用不同的分類或迴歸方法,如決策樹、感知器等)

3)對分類問題:將上步得到的k個模型採用投票的方式得到分類結果;對迴歸問題,計算上述模型的均值作爲最後的結果。(所有模型的重要性相同)


2、boosting

不同分類器通過串行訓練獲得,每個新分類器根據已訓練出的分類器的性能來進行訓練。boosting每一輪的訓練集不變,通過集中關注被已有分類器錯分的那些數據(改變樣本權重)來獲得新的分類器。

boosting分類結果是基於所有分類器的加權求和結果的,而bagging中的分類器權重是相等的。

最流行的是AdaBoost(adaptive boosting):訓練數據中的每個樣本被賦予一個權重D。下一次的訓練權重根據上一次的訓練結果進行調整,其中上一次分隊的樣本的權重降低,而上一次分錯的樣本的權重會提高。爲了從所有弱分類器中得到最終的分類結果,AdaBoost爲每個分類器分配一個權重alpha




3、兩者比較:

https://www.cnblogs.com/liuwu265/p/4690486.html


二、AdaBoost代碼     弱分類器:單層決策樹

from numpy import *

def loadSimpData():
    datMat = 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 datMat,classLabels
datMat,classLabels = loadSimpData()
#根據設定的閾值,針對給定維,對數據進行分類
def stumpClassify(dataMat,dimen,threshVal,threshIneq):#just classify the data
    retArr = ones((shape(dataMat)[0],1))
    if threshIneq == 'lt':
        retArr[dataMat[:,dimen]<=threshVal] = -1.0
    else:
        retArr[dataMat[:,dimen]>threshVal] = -1.0
    return retArr
# 單節點決策樹,根據adaboost權重D判斷最佳的維度
# 確保標籤是+1和-1
def buildStump(dataArr,classLabels,D):
    dataMat = mat(dataArr)
    labelMat = mat(classLabels).T
    m,n = shape(dataMat)
    numSteps = 10.0;bestStump={};bestClasEst=mat(zeros((m,1)))
    minError = inf #init error sum, to +infinity
    for i in range(n):  #loop over all dimensions
        rangeMin = dataMat[:,i].min();
        rangeMax = dataMat[:,i].max();
        stepSize = (rangeMax-rangeMin)/numSteps
        for j in range(-1,int(numSteps)+1):#loop over all range in current dimension
            for inequal in ['lt','gt']:
                threshVal = rangeMin + float(j) * stepSize
                predictedVals = stumpClassify(dataMat,i,threshVal,inequal)
                errArr = mat(ones((m,1)))
                errArr[predictedVals == labelMat] = 0
                weightedError = D.T * errArr #calc total error multiplied by D
                #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                
#D = mat(ones((5,1))/5)      
#bestStump,minError,bestClasEst=buildStump(datMat,classLabels,D)  

#基於單層決策樹的AdaBoost訓練過程
def adaboostTrainDS(dataMat,classLabels,numIt=40):
    weakClassArr = []
    m = shape(dataMat)[0]
    D = mat(ones((m,1))/m)  #init D to all equal
    aggClassEst = mat(zeros((m,1)))
    for i in range(numIt):
        bestStump,error,classEst = buildStump(dataMat,classLabels,D)  #build Stump
#        print('D:',D.T)
        #calc alpha, throw in max(error,eps) to account for error=0
        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) #exponent for D calc, getting messy
        D = multiply(D,exp(expon))
        D = D/D.sum()
        #calc training error of all classifiers, if this is 0 quit for loop early (use break)
        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)
        if errorRate == 0.0: break
    return weakClassArr
#AdaBoost分類函數
def adaClassify(datToClass,classifierArr):
    dataMatrix = mat(datToClass) 
    m = shape(dataMatrix)[0]
    aggClassEst = mat(zeros((m,1)))
    for i in range(len(classifierArr)):
        classEst = stumpClassify(dataMatrix,classifierArr[i]['dim'],\
                                 classifierArr[i]['thresh'],\
                                 classifierArr[i]['ineq']) 
        aggClassEst += classifierArr[i]['alpha']*classEst
        print (aggClassEst)
    return sign(aggClassEst)
#自適應數據加載函數
def loadDataSet(fileName):
    numFeat = len(open(fileName).readline().split('\t'))
    dataMat=[];labelMat=[]
    fr = open(fileName)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat-1):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

dataArr,labelArr = loadDataSet('horseColicTraining2.txt')
classifierArray = adaboostTrainDS(dataArr,labelArr,10)
testArr,testLabelArr = loadDataSet('horseColicTest2.txt')
errArr = mat(ones((67,1)))
errNum = errArr[predictedVals != mat(testLabelArr).T].sum()




注:

1、主要是權重D和alpha的計算、類別估計累計值

weightedError = D.T * errArr

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

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


2、運行問題 ufunc 'multiply' did not contain a loop with signature matching types

原因:labelMat.append(float(curLine[-1]))  中float漏寫。

因爲從文件中讀取的每個數據都是字符串即 'XXX'形式,因此需要float()或int()。



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