eclipse的jsp第一行代码报错_机器学习之AdaBoost算法及纯python代码手工实现
Adaboost算法是boost算法中最具代表性的一個,它是adaptive boosting的簡稱(自使用算法);在訓練數據中的每個樣本賦予一個權重,構成初始的向量D(每個樣本的權重初始時均相等)。首先在訓練數據上訓練出一個弱分類器并計算該分類器的錯誤率,然后在同一個數據集上再次訓練弱分類器。在弱分類器的第二次訓練中,將會調整每個樣本的權重,其中第一次分對的樣本的權重會降低,而分錯的樣本權重會提高。為了從所有弱分類器中得到最終的分類結果,Adaboost為每個分類器配了一個權重alpha,這些alpha是基于每個弱分類器的錯誤率進行計算得到的,分類效果好的弱分類器的alpha值會較大、被Adaboost算法更器重和關注。
錯誤率的定義為:
而alpha的計算公式如下:
Adaboost算法示意圖如下:
左邊是數據集,其中直方圖的不同寬度表示每個樣例上的不同權重。在經過一個分類器之后,加權的預測結果會通過三角形中的alpha值進行加權。每個三角形中輸出的加權結果在圓形中進行求和,從而得到最終的輸出結果。
得到alpha值之后,可以對權重D進行更新,該算法的是更注重被上一輪分類器錯分的樣本,所以是降低那些正確分類的樣本權重而增加錯誤分類樣本的權重。其計算公式方法如下:
如果一個樣本在被正確分類,則權重按如下公式進行更新:
如果一個樣本在被錯誤分類,則權重按如下公式進行更新:
更新D的權重后Adaboosting算法又會進入到下一輪的迭代中,循環反復的重復訓練和調整權重,直到錯誤率、弱分類器的數目或者迭代的次數達到用戶設定的閾值時將不再進行循環。
Adaboost算法的一般流程
(1)收集數據;
(2)準備數據:主要將數據處理為弱分類器可以處理的格式和類型;
(3)分析數據;
(4)訓練算法:在同一份數據集上循環往復的訓練弱分類器,消耗大量的訓練時間;
(5)測試算法:計算分類的錯誤率;
(6)使用算法;
Adaboost算法優缺點
優點:泛化錯誤率低,容易編碼,可以用在大部分的數據集上,超參數基本沒有或一兩個;
缺點:對異常樣本點數據敏感;
適用數據類型:數值型或者標稱型數據;
代碼部分:
首先創建一個簡單的訓練數據集
#手工構建Adaboost會用到的模塊from math import infimport numpy as npfrom numpy import *#構建簡單的測試數據集,該數據集一個特點是靠單顆決策樹無法完成正確的分類def loadSimpleData(): #DatMat = np.arange(10).reshape(5,2) DatMat = np.matrix([[1.,2.1],[2.,1.1],[1.3,1.],[1.,1.],[1.5,1.6]]) classLabels = [1.0,1.0,-1.0,-1.0,1.0] return DatMat,classLabels該份數據分布情況如下(無法用單層決策樹很好的擬合該份數據):
單層決策樹生成函數
def stumpClassify(dataMatrix,dimen,threshVal,threshIneq): """通過閾值比較對數據進行分類,所有在閾值一邊的都會被分為-1、在另一邊的則被分為+1; 實現上是通過數組的過濾來完成,首先將返回數組的全部元素設置為1,即如下第一行; 將所有不滿足不等式要求的都設置為-1,可以基于數據集中的任一元素進行比較,同時可以將預算符進行切換。 """ retArray = ones((shape(dataMatrix)[0],1)) if threshIneq == 'lt': retArray[dataMatrix[:,dimen] <= threshVal] = -1.0 else: retArray[dataMatrix[:,dimen] > threshVal] = -1.0 return retArray"""將最小的錯誤率minError初始化正無窮大;將數據集中的每一個特征(第一層for循環): 對每個步長(第二層dor循環): 對每個不等號(第三層for循環): 建議一顆單層決策樹(即樹樁)并利用加權數據集對它進行測試 如果錯誤率低于minError,則將當前單層決策樹設為最佳單層決策樹返回最佳單層決策樹"""def buildStump(dataArr,classLabels,D): """會遍歷stumpClassify()函數所有可能的輸入值,并找到數據集上最佳的單層決策樹 """ dataMatrix = mat(dataArr) labelMat = mat(classLabels).T m,n = shape(dataMatrix) "numSteps用于在特征的所有可能值上進行便利" numSteps = 10.0 "創建為空的bestStump空字典,用于存放給定權重向量D時所得到的最佳單層決策樹的相關信息" bestStump = {};bestClasEst = mat(zeros((m,1))) "初始化為正無窮大,用于尋找可能的最小錯誤率" minError = inf """第一層for循環在數據集的所有特征上進行遍歷; 根據最大、最小值還計算步長; """ for i in range(n): rangeMin = dataMatrix[:,i].min(); rangeMax = dataMatrix[:,i].max(); stepSize = (rangeMax - rangeMin) / numSteps """ 第二層for循環在這些值上遍歷,甚至將閾值設置為整個取值范圍之外也是可以的。 """ for j in range(-1,int(numSteps) + 1): """第三層for循環在大于和小于之間進行切換""" # 對每個不等號,lt: less than; gt: great than for inequal in ['lt','gt']: threshVal = (rangeMin + float(j) * stepSize) predictedVals = \ stumpClassify(dataMatrix,i,threshVal,inequal) """構建列向量用于存儲記錄預測值中多少和實際的標簽不相符的情況, 若與測試不等于真正的類別標簽值,則errArr中相應位置為1""" errArr = mat(ones((m,1))) # 計算加權錯誤率,錯誤向量 dot* 權重向量,weightedError是一個值:[[ 0.57142857]] errArr[predictedVals == labelMat] = 0 "將錯誤率和向量D進行相乘并求和,得到weightedError,是Adaboosting與分類其交互的地方" weightedError = D.T * errArr """最后將得到的最小錯誤率和現有的錯誤率進行比較,如果值較小,則在bestStump 中更新決策樹的信息;并字典、錯誤率和類別估計返回傳給下一步的Adaboosting算法中""" if weightedError < minError: minError = weightedError bestClasEst = predictedVals.copy() bestStump['dim'] = i bestStump['thresh'] = threshVal bestStump['ineq'] = inequal????return?bestStump,minError,bestClasEst基于單層決策樹的Adaboost算法的訓練過程
#開始基于上面構建的單層決策樹構建AdaBoosting算法"""對每次迭代: 利用buildStump()函數找到最佳的單層決策樹 將最佳的單層決策樹加入到單層決策樹數組 計算alpha 計算新的權重向量D 更新累計類別的估計值 如果錯誤率等于0.0,則退出循環"""def AdaboostingTrainDS(dataArr,classLabels,numIt = 40): """Adaboosting算法輸入參數包括數據集、類別標簽以及迭代次數; 這里迭代次數唯一一個超參數:人工干預提供的值; 函數后面的DS代表單層決策樹(decision stump) """ weakClassArr = [] m = shape(dataArr)[0] """向量D存儲每個數據點的權重,初始化為均等值;這里D是概率分布、根據數據集中的 數據點的數據m進行均分、總和為1 """ D = mat(ones((m,1))/m) """記錄每個數據點的類別估計累計值 """ aggClassEst = mat(zeros((m,1))) """for循環運行numIt次或者直到訓練錯誤率為0為止""" for i in range(numIt): "根據輸入權重向量D,得到一個具有最小錯誤率的單層決策樹" bestStump,error,classEst = buildStump(dataArr,classLabels,D) print("D:",D.T) "max(error,1e-16)用于避免除零溢出報錯" alpha = float(0.5*log((1.0-error)/max(error,1e-16))) bestStump['alpha'] = alpha weakClassArr.append(bestStump) print("classEst",classEst.T) """用于計算下一次迭代中的新權重向量D""" # 如果當前樣本被正確分類((1 * 1)or(-1 * -1)) = 1,乘參數-1 = -alpha,權重下降 # 如果當前樣本被錯分((1 * -1)or(-1 * 1)) = -1,乘以參數-1 = alpha,權重升高 expon = multiply(-1.0 * alpha * mat(classLabels).T,classEst) D = multiply(D,exp(expon)) # 其實是一個迭代的過程D_i+1 = D_i * exp(expon) D = D / D.sum() """維護一個運行時的類別估計值來用于判斷錯誤率是否為0、若為0則提前退出循環""" aggClassEst += alpha*classEst print("aggClassEst",aggClassEst.T) # 使用sign進行二分類 aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1))) errorRate = aggErrors.sum() / m print("total error :",errorRate, "\n") if errorRate == 0.0:break return weakClassArrAdaboost分類函數構建
#在有了多個弱分類器以及對應的權重參數后,對這些弱分類器的結果加權求和就得到了最后的結果def adaClassify(dataToClass,classifierArr): """利用訓練好的多個弱分類器進行分類,傳入一個或多個待分類的樣例dataToClass 以及多個弱分類器組成的數組classifierArr;首先對進行的樣例轉換成矩陣;然后得到待分類樣例的個數m; """ dataMatrix = mat(dataToClass) 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): # 計算特征個數(如果用下面的fr來讀,那么訓練集和測試集中就少了一個樣本數據) 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): # 不能split()后直接append,應該先用float格式化數據,統一數據類型 lineArr.append(float(curLine[i])) dataMat.append(lineArr) labelMat.append(float(curLine[-1])) return dataMat, labelMat構建簡單的數據集進行測試
TestData = [[5.,5.],[0.,0.]]if __name__ == "__main__": #loadDataSet 如果是文件則用該函數導入數據 #dataMat, classLabels = loadDataSet("文件名稱") #testMat, testLabels = loadDataSet('文件名稱') dataArr,labelArr = loadSimpleData() classifierArr = AdaboostingTrainDS(dataArr,labelArr,30) adaClassify(TestData,classifierArr) pass代碼執行結果如下:
[Running] python -u "\AdaBoostingCodingSelf.py"D: [[0.2 0.2 0.2 0.2 0.2]]classEst [[ 1. 1. -1. -1. 1.]]aggClassEst [[ 18.42068074 18.42068074 -18.42068074 -18.42068074 18.42068074]]total?error?:?0.0?[[ 18.42068074]?[-18.42068074]][Done] exited with code=0 in 1.175 seconds同時基于sklearn實現Adaboost算法,并將單顆決策樹的擬合效果和多顆決策樹的擬合效果進行比對,并采用圖形直觀展示的方式畫出來
print(__doc__)from operator import concatimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.tree import DecisionTreeRegressorfrom sklearn.ensemble import AdaBoostRegressor# Create the datasetrng = np.random.RandomState(1)X = np.linspace(0, 6, 100)[:, np.newaxis]y = np.sin(X).ravel() + np.sin(6 * X).ravel() + rng.normal(0, 0.1, X.shape[0])print(X.shape)print(y.shape)# Fit regression modelmaxepth = 5nestimatorsest = 1000#最簡單的決策樹、僅限制樹深regr_1 = DecisionTreeRegressor(max_depth=maxepth)regr_2 = AdaBoostRegressor(DecisionTreeRegressor(max_depth=maxepth), n_estimators=nestimatorsest)regr_1.fit(X, y)regr_2.fit(X, y)# Predicty_1 = regr_1.predict(X)y_2 = regr_2.predict(X)# Plot the resultsplt.figure()plt.scatter(X, y, c="k", label="training samples")plt.plot(X, y_1, c="g", label="n_estimators=1", linewidth=2)plt.plot(X, y_2, c="r", label=concat("n_estimators= ",str(nestimatorsest)), linewidth=2)plt.xlabel("data")plt.ylabel("target")plt.title("Boosted Decision Tree Regression")plt.legend()plt.show()結果展示如下:
這里Adaboost中的弱分類器數目調的有點大,實際大概在50-100左右對數據的擬合程度就已經很好了,而單顆樹很明顯表現的要差很多。
單顆決策樹難免較好的擬合數據,經常會出現欠擬合的現象;而多顆樹有時則會更好的擬合所有訓練數據,但也容易出現過擬合的現象;為更好理解欠擬合和過擬合,進行直觀展示、方便在算法訓練中選擇一個比較好的模型。
print(__doc__)import numpy as npimport matplotlib.pyplot as pltfrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import PolynomialFeaturesfrom sklearn.linear_model import LinearRegressionfrom sklearn.model_selection import cross_val_scorenp.random.seed(0)n_samples = 30degrees = [1, 4, 15]true_fun = lambda X: np.cos(1.5 * np.pi * X)X = np.sort(np.random.rand(n_samples))y = true_fun(X) + np.random.randn(n_samples) * 0.1plt.figure(figsize=(14, 5))for i in range(len(degrees)): ax = plt.subplot(1, len(degrees), i + 1) plt.setp(ax, xticks=(), yticks=()) polynomial_features = PolynomialFeatures(degree=degrees[i], include_bias=False) linear_regression = LinearRegression() pipeline = Pipeline([("polynomial_features", polynomial_features), ("linear_regression", linear_regression)]) pipeline.fit(X[:, np.newaxis], y) # Evaluate the models using crossvalidation scores = cross_val_score(pipeline, X[:, np.newaxis], y, scoring="neg_mean_squared_error", cv=10) X_test = np.linspace(0, 1, 100) plt.plot(X_test, pipeline.predict(X_test[:, np.newaxis]), label="Model") plt.plot(X_test, true_fun(X_test), label="True function") plt.scatter(X, y, label="Samples") plt.xlabel("x") plt.ylabel("y") plt.xlim((0, 1)) plt.ylim((-2, 2)) plt.legend(loc="best") plt.title("Degree {}\nMSE = {:.2e}(+/- {:.2e})".format( degrees[i], -scores.mean(), scores.std()))plt.show()展示如下:
參考文件
《機器學習實戰》
《統計學習方法》等。
總結
以上是生活随笔為你收集整理的eclipse的jsp第一行代码报错_机器学习之AdaBoost算法及纯python代码手工实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 如何删除frame 中的
- 下一篇: 岳西中自机器人_中国科学院