0.隨機森林的思考
隨機森林的決策樹是分別采樣建立的,各個決策樹之間是相對獨立的。那么,在我們得到了第k-1棵決策樹之后,能否通過現有的樣本和決策樹的信息, 對第m顆樹的建立產生有益的影響呢?在隨機森林建立之后,采用的投票過程能否增加一定的權值呢?在選取樣本的時候,我們能否對於分類錯誤的樣本給予更大的權值,使之得到更多的重視呢?
1.什么是提升思想
提升是一個機器學習技術,可以用於回歸和分類問題,它每一步產生一個弱預測模型,並加權累加到總的模型之中,如果每一步的弱預測模型生成都是依據損失函數的梯度方向,則稱之為梯度提升。
梯度提升算法首先給定一個目標損失函數,它的定義域是所有可行的弱函數集合(基函數);提升算法通過迭代的選擇一個負梯度方向上的基函數來逐漸畢竟局部極小值。這種在函數域的梯度提升觀點在機器學習的很多領域都用較大的影響。
提升的理論意義是:如果一個問題存在弱分類器,則可以通過提升的辦法得到強分類器。
2.提升算法
給定輸入向量X和輸出變量y組成的若干訓練樣本,(x1,y1),(x2,y2),.....,(xn,yn),目標是找到近似函數F(x),使得損失函數L(y,F(x))的損失值最小。
損失函數的經典定義:
假定最優函數為F*(x),即:
假定F(x)是一族基函數fi(x)的加權和
那么,對於上述的F(x),我們應該如何求解呢?
我們很容易想到貪心的思路,當我們每一步得到的fi(x)都是最小的時候,它們相加的F(x)也應該是最小,即最優解,問題變成了我們應該如何求解fi(x)呢?
貪心法在每次選擇最優基函數f時,仍然比較困難,這時,我們想到了梯度下降的方法進行近似計算,我們將樣本帶入到基函數f得到f(x1),f(x2),f(x3),...,f(xn),從而L退化為向量L(y1,f(x1)),L(y2,f(x2)),L(y3,f(x3)),....,L(yn,f(xn)):
上面的式子中,權值表示的是梯度的步長,我們可以使用線性搜索計算最優的步長:
算法的步驟如下:
初始時,給定模型為常數:
對於m=1-M時:
計算偽殘差:
使用數據計算擬合殘差的基函數fm(x)
計算步長:
更新模型:
在上述的梯度提升的算法中,典型的模型就是梯度提升決策樹GBDT。
3.梯度提升決策樹GBDT
梯度提升的典型基函數即決策樹(尤其是CART)
在第m步的梯度提升是根據偽殘差數據計算決策樹tm(x)。決策樹根據葉子節點的數目,對輸入空間進行划分成不相交的區域,並且在每個區域中,給出某個類型的確定性預測,因此我們可以使用指示函數I(x),對於輸入的x,tm(x)可以表示為:
其中,bjm是樣本在Rjm節點上的預測值,Rjm表示第m顆樹的j葉子節點。
使用線性搜索計算學習率,最小化損失函數:
進一步的,對樹的每個區域分別計算步長,從而系數bjm被合並到步長中:
對於上述的模型,我們也可以采取一些防止過擬合的措施,比如正則化。
4.XGBoost算法
根據Taylor展開式有:
分別計算一階導和二階導:
得到:
對於決策樹的描述
決策樹是從根節點到葉結點的細化過程,落在相同的樣本的預測值是相同的。假定決策樹的葉結點數目為T,每個葉結點的權值構成向量W=(w1,w2,.....,wn),決策樹則是構造如何使用特征得到划分,從而得到這些權值的過程。
樣本X落在葉結點q中,定義f為:ft(x)=wq(x),舉例如下:
對於正則項的定義,我們可以考慮葉結點的數目和葉權值,如使用葉結點總數和也權值平方和的加權,則也不是唯一的定義方式:
由此,我們就能夠計算目標函數了:
目標函數的簡化
上述的過程就是XGBoost的主要推導過程,相比於GDBT,XGBoost使用的是二階的梯度信息,因而可以更快的在訓練集上收斂。
5.Python中的XGBoost
在XGBoost中數據的加載是使用其特有的數據格式進行訓練的,我們可以使用XGBoost中的xgb.DMatrix(x_train, label=y_train)函數進行數據的加載,xgb.DMatrix()也支持libsvm格式的數據,這是一種稀疏數據的存儲方式,xgb.DMatrix()可以直接讀取這種數據格式:
libsvm數據格式是一種稀疏矩陣的表示方法,其中第1列為結果集,后面的每列含義為:該樣本的特征序號:該樣本對應的特征序號的值,對於特征數量多,且稀疏的時候非常的合適。
1 import xgboost as xgb 2 import numpy as np 3 4 #讀取libsvm數據 5 data_train = xgb.DMatrix('12.agaricus_train.txt') 6 data_test = xgb.DMatrix('12.agaricus_test.txt') 7 8 9 #讀取普通的數據 10 data_train = xgb.DMatrix(x_train, label=y_train) 11 data_test = xgb.DMatrix(x_test, label=y_test)
使用xgb.train()對模型進行訓練,我們 XGBoost 之前, 我們必須設置三種類型的參數: (常規參數)general parameters,(提升器參數)booster parameters和(任務參數)task parameters。
參數的含義如下:
1 params = { 2 'booster':'gbtree', 3 'min_child_weight': 100, 4 'eta': 0.1, 5 'colsample_bytree': 0.7, 6 'max_depth': 12, 7 'subsample': 0.7, 8 'alpha': 1, 9 'gamma': 1, 10 'silent': 0, 11 'objective': 'reg:linear', 12 'verbose_eval': True, 13 'seed': 1 14 }
General Parameters
booster [default=gbtree]
有兩中模型可以選擇gbtree和gblinear。gbtree使用基於樹的模型進行提升計算,gblinear使用線性模型進行提升計算。缺省值為gbtree。
silent [default=0]
取0時表示打印出運行時信息,取1時表示以緘默方式運行,不打印運行時信息。缺省值為0。
nthread [default to maximum number of threads available if not set]
XGBoost運行時的線程數。缺省值是當前系統可以獲得的最大線程數
num_pbuffer [set automatically by xgboost, no need to be set by user]
size of prediction buffer, normally set to number of training instances. The buffers are used to save the prediction results of last boosting step.
num_feature [set automatically by xgboost, no need to be set by user]
boosting過程中用到的特征維數,設置為特征個數。XGBoost會自動設置,不需要手工設置。
Booster Parameters
eta [default=0.3]
為了防止過擬合,更新過程中用到的收縮步長。在每次提升計算之后,算法會直接獲得新特征的權重。 eta通過縮減特征的權重使提升計算過程更加保守。缺省值為0.3
取值范圍為:[0,1]
gamma [default=0]
minimum loss reduction required to make a further partition on a leaf node of the tree. the larger, the more conservative the algorithm will be.
range: [0,∞]
max_depth [default=6]
樹的最大深度。缺省值為6
取值范圍為:[1,∞]
min_child_weight [default=1]
孩子節點中最小的樣本權重和。如果一個葉子節點的樣本權重和小於min_child_weight則拆分過程結束。在現行回歸模型中,這個參數是指建立每個模型所需要的最小樣本數。
取值范圍為: [0,∞]
max_delta_step [default=0]
Maximum delta step we allow each tree’s weight estimation to be. If the value is set to 0, it means there is no constraint. If it is set to a positive value, it can help making the update step more conservative. Usually this parameter is not needed, but it might help in logistic regression when class is extremely imbalanced. Set it to value of 1-10 might help control the update
取值范圍為:[0,∞]
subsample [default=1]
用於訓練模型的子樣本占整個樣本集合的比例。如果設置為0.5則意味着XGBoost將隨機的沖整個樣本集合中隨機的抽取出50%的子樣本建立樹模型,這能夠防止過擬合。
取值范圍為:(0,1]
colsample_bytree [default=1]
在建立樹時對特征采樣的比例。缺省值為1
取值范圍:(0,1]
Task Parameters
objective [ default=reg:linear ]
定義學習任務及相應的學習目標,可選的目標函數如下:
“reg:linear” –線性回歸。
“reg:logistic” –邏輯回歸。
“binary:logistic”–二分類的邏輯回歸問題,輸出為概率。
“binary:logitraw”–二分類的邏輯回歸問題,輸出的結果為wTx。
“count:poisson”–計數問題的poisson回歸,輸出結果為poisson分布。在poisson回歸中,max_delta_step的缺省值為0.7。(used to safeguard optimization)
“multi:softmax” –讓XGBoost采用softmax目標函數處理多分類問題,同時需要設置參數num_class(類別個數)
“multi:softprob” –和softmax一樣,但是輸出的是ndata * nclass的向量,可以將該向量reshape成ndata行nclass列的矩陣。沒行數據表示樣本所屬於每個類別的概率。
“rank:pairwise”–set XGBoost to do ranking task by minimizing the pairwise loss
base_score [ default=0.5 ]
the initial prediction score of all instances, global bias
eval_metric [ default according to objective ]
校驗數據所需要的評價指標,不同的目標函數將會有缺省的評價指標(rmse for regression, and error for classification, mean average precision for ranking)
用戶可以添加多種評價指標,對於Python用戶要以list傳遞參數對給程序,而不是map參數list參數不會覆蓋’eval_metric’
The choices are listed below:
“rmse”: root mean square error
“logloss”: negative log-likelihood
“error”: Binary classification error rate. It is calculated as #(wrong cases)/#(all cases). For the predictions, the evaluation will regard the instances with prediction value larger than 0.5 as positive instances, and the others as negative instances.
“merror”: Multiclass classification error rate. It is calculated as #(wrong cases)/#(all cases).
“mlogloss”: Multiclass logloss
“auc”: Area under the curve for ranking evaluation.
“ndcg”:Normalized Discounted Cumulative Gain
“map”:Mean average precision
“ndcg@n”,”map@n”: n can be assigned as an integer to cut off the top positions in the lists for evaluation.
“ndcg-”,”map-”,”ndcg@n-”,”map@n-”: In XGBoost, NDCG and MAP will evaluate the score of a list without any positive samples as 1. By adding “-” in the evaluation metric XGBoost will evaluate these score as 0 to be consistent under some conditions. training repeatively
“gamma-deviance”: [residual deviance for gamma regression]
seed[ default=0 ]
random number seed.
隨機數的種子。缺省值為0
dtrain:訓練的數據
num_boost_round:這是指提升迭代的次數,也就是生成多少基模型
evals:這是一個列表,用於對訓練過程中進行評估列表中的元素。形式是evals = [(dtrain,'train'),(dval,'val')]或者是evals = [(dtrain,'train')],對於第一種情況,它使得我們可以在訓練過程中觀察驗證集的效果
obj:自定義目的函數
feval:自定義評估函數
maximize:是否對評估函數進行最大化
early_stopping_rounds:早期停止次數 ,假設為100,驗證集的誤差迭代到一定程度在100次內不能再繼續降低,就停止迭代。這要求evals 里至少有 一個元素,如果有多個,按最后一個去執行。返回的是最后的迭代次數(不是最好的)。如果early_stopping_rounds存在,則模型會生成三個屬性,bst.best_score,bst.best_iteration和bst.best_ntree_limit
evals_result:字典,存儲在watchlist中的元素的評估結果。
verbose_eval :(可以輸入布爾型或數值型),也要求evals里至少有 一個元素。如果為True,則對evals中元素的評估結果會輸出在結果中;如果輸入數字,假設為5,則每隔5個迭代輸出一次。
learning_rates:每一次提升的學習率的列表,
xgb_model:在訓練之前用於加載的xgb model。
看起來參數非常的多,但是我們在大部分的時候,只要指定一些調整的參數就行了。
1 data_train = xgb.DMatrix(x_train, label=y_train) 2 data_test = xgb.DMatrix(x_test, label=y_test) 3 watch_list = [(data_test, 'eval'), (data_train, 'train')] 4 param = {'max_depth': 3, 'eta':0.5, 'silent': 0, 'objective': 'multi:softmax', 'num_class': 3} 5 6 bst = xgb.train(param, data_train, num_boost_round=15, evals=watch_list) 7 y_hat = bst.predict(data_test)
我們采用隨機生成的數據使用XGBoost模型來進行測試:
1 import numpy as np 2 import sklearn as sk 3 from sklearn.model_selection import train_test_split 4 import xgboost as xgb 5 import matplotlib.pyplot as plt 6 import matplotlib as mpl 7 8 9 def markData(): 10 11 x1 = 5 + np.random.rand(30)*5 12 y1 = 8 + np.random.rand(30)*5 13 14 x2 = 9 + np.random.rand(30) * 3 15 y2 = 1 + np.random.rand(30) * 5 16 17 x3 = 4 + np.random.rand(30) * 5 18 y3 = 3 + np.random.rand(30) * 5 19 20 x4 = 8 + np.random.rand(30) * 7 21 y4 = 5 + np.random.rand(30) * 5 22 # plt.figure() 23 # plt.plot(x1, y1, 'ro', linewidth=0.8, label='x1') 24 # plt.plot(x2, y2, 'ko', linewidth=0.8, label='x2') 25 # plt.plot(x3, y3, 'bo', linewidth=0.8, label='x3') 26 # plt.plot(x4, y4, 'go', linewidth=0.8, label='x4') 27 # plt.legend(loc="upper right",) 28 # plt.show() 29 # print(x1) 30 x = np.hstack((x1, x2, x3, x4)) 31 y = np.hstack((y1, y2, y3, y4)) 32 x = np.stack((x, y), axis=0).transpose() 33 # print(x) 34 # plt.figure() 35 # plt.plot(x[0:30, 0], x[0:30, 1], 'ro', linewidth=0.8) 36 # plt.plot(x[30:60, 0], x[30:60, 1], 'bo', linewidth=0.8) 37 # plt.plot(x[60:90, 0], x[60:90, 1], 'go', linewidth=0.8) 38 # plt.plot(x[90:120, 0], x[90:120, 1], 'ko', linewidth=0.8) 39 # plt.show() 40 y = np.zeros(120) 41 y[0:30] =0 42 y[30:60] = 1 43 y[60:90] = 2 44 y[90:120] =3 45 # print(y) 46 return x, y 47 48 49 if __name__ == '__main__': 50 x, y = markData() 51 x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.75, random_state=1) 52 # print(x_train) 53 # print(y_train) 54 data_train = xgb.DMatrix(x_train, label=y_train) 55 data_test = xgb.DMatrix(x_test, label=y_test) 56 # print(data_train) 57 # print(data_test) 58 59 # 定義xgb的模型參數 60 parms = {'max_depth': 3, 'eta': 0.5, 'slient': 0, 'objective': 'multi:softmax', 'num_class': 4} 61 watchlist = [(data_train, 'eval'), (data_test, 'train')] 62 bst = xgb.train(parms, data_train, num_boost_round=6, evals=watchlist) 63 y_hat = bst.predict(data_test) 64 65 #計算准確率 66 print(np.mean(y_hat == y_test)) 67 68 # 繪制分類圖片 69 N, M = 200, 200 70 x_min, x_max = np.min(x[:, 0]), np.max(x[:, 0]) 71 y_min, y_max = np.min(x[:, 1]), np.max(x[:, 1]) 72 x1 = np.linspace(x_min, x_max, N) 73 x2 = np.linspace(y_min, y_max, M) 74 tx, ty = np.meshgrid(x1, x2) 75 xx = np.stack((tx.flat, ty.flat), axis=1) 76 data_xx = xgb.DMatrix(xx) 77 yy = bst.predict(data_xx) 78 yy = yy.reshape(tx.shape) 79 80 cmp_light = mpl.colors.ListedColormap(['#33FF33', '#FFCC66', '#FFF500', '#22CFCC']) 81 cmp_drak = mpl.colors.ListedColormap(['r', 'g', 'b', 'k']) 82 83 plt.figure() 84 plt.pcolormesh(tx, ty, yy, cmap=cmp_light) 85 plt.scatter(x[:, 0], x[:, 1], c=y, edgecolors='k', cmap=cmp_drak) 86 plt.xlabel("x1") 87 plt.ylabel("x2") 88 plt.xlim(x_min, x_max) 89 plt.ylim(y_min, y_max) 90 plt.grid(True) 91 plt.show()
運行結果如下: