我今天主要介紹機器學習集成學習方法中三巨頭之一的XGBoost,這個算法在早些時候機器學習比賽內曾經大放異彩,是很是好用的一個機器學習集成算法。
git
XGBoost是一個優化的分佈式梯度加強庫,旨在實現高效,靈活和便攜。它在Gradient Boosting框架下實現機器學習算法。XGBoost提供了並行樹提高(也稱爲GBDT,GBM),能夠快速準確地解決許多數據科學問題。算法
相同的代碼在主要的分佈式環境(Hadoop,SGE,MPI)上運行,而且能夠解決超過數十億個樣例的問題。XGBoost利用了核外計算而且可以使數據科學家在一個主機上處理數億的樣本數據。最終,將這些技術進行結合來作一個端到端的系統以最少的集羣系統來擴展到更大的數據集上。數組
從0開始學習,經歷過推導公式的波瀾曲折,下面展現下我本身的推公式的手稿吧,但願能激勵到你們可以對機器學習數據挖掘更加熱愛!多線程
XGBoost公式1app
XGBoost公式2框架
如今咱們對手稿的內容進行詳細的講解:
dom
1. 優化目標: 咱們的任務是找到一組樹使得OBj最小,很明顯這個優化目標OBj能夠當作是樣本的損失和模型的複雜度懲罰相加組成。2. 使用追加法訓練(Additive Training Boosting)機器學習
核心思想是:在已經訓練好了 棵樹後再也不調整前 棵樹,那麼第t棵樹能夠表示爲:分佈式
(1). 那此時若是咱們對第t棵樹訓練,則目標函數爲:ide
對上式進行泰勒二階展開:
因爲前t-1棵樹已知,那麼
(2). 咱們已經對前半部分的損失函數作出了充分的討論,可是後半部分的 還只是個符號並未定義,那咱們如今就來定義 :假設咱們待訓練的第t棵樹有T個葉子結點:葉子結點的輸出向量表示以下:
假設 表示樣本到葉子結點的映射,那麼 。那麼咱們定義 :
(3). 咱們的目標函數最終化簡爲:
咱們找到了目標函數就須要對目標函數進行優化:
3. 生成樹的策略:咱們剛剛的假設前提是已知前t-1棵樹,所以咱們如今來探討怎麼生成樹。根據決策樹的生成策略,再每次分裂節點的時候咱們須要考慮能使得損失函數減少最快的節點,也就是分裂後損失函數減去分裂前損失函數咱們稱之爲Gain:
Gain越大越能說明分裂後目標函數值減少越多。(由於從式子來看: 越大,反而OBj越小)
4. 尋找最優節點:
精確貪心算法(Basic Exact Greedy Algorithm)
近似算法(Approximate Algorithm)
在決策樹(CART)裏面,咱們使用的是精確貪心算法(Basic Exact Greedy Algorithm),也就是將全部特徵的全部取值排序(耗時耗內存巨大),而後比較每個點的Gini,找出變化最大的節點。當特徵是連續特徵時,咱們對連續值離散化,取兩點的平均值爲分割節點。能夠看到,這裏的排序算法須要花費大量的時間,由於要遍歷整個樣本全部特徵,並且還要排序!!
論文的精確貪心算法的僞代碼
所以在XGBoost裏面咱們使用的是近似算法(Approximate Algorithm):該算法首先根據特徵分佈的百分位數(percentiles)提出候選分裂點,將連續特徵映射到由這些候選點分割的桶中,彙總統計信息並根據彙總的信息在提案中找到最佳解決方案。對於某個特徵k,算法首先根據特徵分佈的分位數找到特徵切割點的候選集合 ,而後將特徵k的值根據集合 劃分到桶(bucket)中,接着對每一個桶內的樣本統計值G、H進行累加,最後在這些累計的統計量上尋找最佳分裂點。
論文的近似算法的僞代碼
1. 引入基本工具庫:
# 引入基本工具庫import numpy as npimport pandas as pdimport xgboost as xgbimport matplotlib.pyplot as pltplt.style.use("ggplot")%matplotlib inline
2. XGBoost原生工具庫的上手:
import xgboost as xgb # 引入工具庫# read in datadtrain = xgb.DMatrix('demo/data/agaricus.txt.train') # XGBoost的專屬數據格式,可是也能夠用dataframe或者ndarraydtest = xgb.DMatrix('demo/data/agaricus.txt.test') # # XGBoost的專屬數據格式,可是也能夠用dataframe或者ndarray# specify parameters via mapparam = {'max_depth':2, 'eta':1, 'objective':'binary:logistic' } # 設置XGB的參數,使用字典形式傳入num_round = 2 # 使用線程數bst = xgb.train(param, dtrain, num_round) # 訓練# make predictionpreds = bst.predict(dtest) # 預測
XGBoost的參數分爲三種:
1. 通用參數
booster:使用哪一個弱學習器訓練,默認gbtree,可選gbtree,gblinear 或dart
nthread:用於運行XGBoost的並行線程數,默認爲最大可用線程數
verbosity:打印消息的詳細程度。有效值爲0(靜默),1(警告),2(信息),3(調試)。
Tree Booster的參數:
eta(learning_rate):learning_rate,在更新中使用步長收縮以防止過分擬合,默認= 0.3,範圍:[0,1];典型值通常設置爲:0.01-0.2
gamma(min_split_loss):默認= 0,分裂節點時,損失函數減少值只有大於等於gamma節點才分裂,gamma值越大,算法越保守,越不容易過擬合,但性能就不必定能保證,須要平衡。範圍:[0,∞]
max_depth:默認= 6,一棵樹的最大深度。增長此值將使模型更復雜,而且更可能過分擬合。範圍:[0,∞]
min_child_weight:默認值= 1,若是新分裂的節點的樣本權重和小於min_child_weight則中止分裂 。這個能夠用來減小過擬合,可是也不能過高,會致使欠擬合。範圍:[0,∞]
max_delta_step:默認= 0,容許每一個葉子輸出的最大增量步長。若是將該值設置爲0,則表示沒有約束。若是將其設置爲正值,則能夠幫助使更新步驟更加保守。一般不須要此參數,可是當類極度不平衡時,它可能有助於邏輯迴歸。將其設置爲1-10的值可能有助於控制更新。範圍:[0,∞]
subsample:默認值= 1,構建每棵樹對樣本的採樣率,若是設置成0.5,XGBoost會隨機選擇一半的樣本做爲訓練集。範圍:(0,1]
sampling_method:默認= uniform,用於對訓練實例進行採樣的方法。
uniform:每一個訓練實例的選擇機率均等。一般將subsample> = 0.5 設置 爲良好的效果。
gradient_based:每一個訓練實例的選擇機率與規則化的梯度絕對值成正比,具體來講就是 ,subsample能夠設置爲低至0.1,而不會損失模型精度。
colsample_bytree:默認= 1,列採樣率,也就是特徵採樣率。範圍爲(0,1]
lambda(reg_lambda):默認=1,L2正則化權重項。增長此值將使模型更加保守。
alpha(reg_alpha):默認= 0,權重的L1正則化項。增長此值將使模型更加保守。
tree_method:默認=auto,XGBoost中使用的樹構建算法。
auto:使用啓發式選擇最快的方法。
對於小型數據集,exact將使用精確貪婪()。
對於較大的數據集,approx將選擇近似算法()。它建議嘗試hist,gpu_hist,用大量的數據可能更高的性能。(gpu_hist)支持。external memory外部存儲器。
exact:精確的貪婪算法。枚舉全部拆分的候選點。
approx:使用分位數和梯度直方圖的近似貪婪算法。
hist:更快的直方圖優化的近似貪婪算法。(LightGBM也是使用直方圖算法)
gpu_hist:GPU hist算法的實現。
scale_pos_weight:控制正負權重的平衡,這對於不平衡的類別頗有用。Kaggle競賽通常設置sum(negative instances) / sum(positive instances),在類別高度不平衡的狀況下,將參數設置大於0,能夠加快收斂。
num_parallel_tree:默認=1,每次迭代期間構造的並行樹的數量。此選項用於支持加強型隨機森林。
monotone_constraints:可變單調性的約束,在某些狀況下,若是有很是強烈的先驗信念認爲真實的關係具備必定的質量,則可使用約束條件來提升模型的預測性能。(例如params_constrained['monotone_constraints'] = "(1,-1)",(1,-1)咱們告訴XGBoost對第一個預測變量施加增長的約束,對第二個預測變量施加減少的約束。)
Linear Booster的參數:
lambda(reg_lambda):默認= 0,L2正則化權重項。增長此值將使模型更加保守。歸一化爲訓練示例數。
alpha(reg_alpha):默認= 0,權重的L1正則化項。增長此值將使模型更加保守。歸一化爲訓練示例數。
updater:默認= shotgun。
shotgun:基於shotgun算法的平行座標降低算法。使用「 hogwild」並行性,所以每次運行都產生不肯定的解決方案。
coord_descent:普通座標降低算法。一樣是多線程的,但仍會產生肯定性的解決方案。
feature_selector:默認= cyclic。特徵選擇和排序方法
cyclic:經過每次循環一個特徵來實現的。
shuffle:相似於cyclic,可是在每次更新以前都有隨機的特徵變換。
random:一個隨機(有放回)特徵選擇器。
greedy:選擇梯度最大的特徵。(貪婪選擇)
thrifty:近似貪婪特徵選擇(近似於greedy)
top_k:要選擇的最重要特徵數(在greedy和thrifty內)
通用參數有兩種類型的booster,由於tree的性能比線性迴歸好得多,所以咱們不多用線性迴歸。
2. 任務參數
objective:默認=reg:squarederror,表示最小平方偏差。
reg:squarederror,最小平方偏差。
reg:squaredlogerror,對數平方損失。
reg:logistic,邏輯迴歸
reg:pseudohubererror,使用僞Huber損失進行迴歸,這是絕對損失的兩倍可微選擇。
binary:logistic,二元分類的邏輯迴歸,輸出機率。
binary:logitraw:用於二進制分類的邏輯迴歸,邏輯轉換以前的輸出得分。
binary:hinge:二進制分類的鉸鏈損失。這使預測爲0或1,而不是產生機率。(SVM就是鉸鏈損失函數)
count:poisson –計數數據的泊松迴歸,泊松分佈的輸出平均值。
survival:cox:針對正確的生存時間數據進行Cox迴歸(負值被視爲正確的生存時間)。
survival:aft:用於檢查生存時間數據的加速故障時間模型。
aft_loss_distribution:survival:aft和aft-nloglik度量標準使用的機率密度函數。
multi:softmax:設置XGBoost以使用softmax目標進行多類分類,還須要設置num_class(類數)
multi:softprob:與softmax相同,但輸出向量,能夠進一步重整爲矩陣。結果包含屬於每一個類別的每一個數據點的預測機率。
rank:pairwise:使用LambdaMART進行成對排名,從而使成對損失最小化。
rank:ndcg:使用LambdaMART進行列表式排名,使標準化折讓累積收益(NDCG)最大化。
rank:map:使用LambdaMART進行列表平均排名,使平均平均精度(MAP)最大化。
reg:gamma:使用對數連接進行伽馬迴歸。輸出是伽馬分佈的平均值。
reg:tweedie:使用對數連接進行Tweedie迴歸。
自定義損失函數和評價指標:
eval_metric:驗證數據的評估指標,將根據目標分配默認指標(迴歸均方根,分類偏差,排名的平均平均精度),用戶能夠添加多個評估指標
rmse,均方根偏差;rmsle:均方根對數偏差;mae:平均絕對偏差;mphe:平均僞Huber錯誤;logloss:負對數似然;error:二進制分類錯誤率;
merror:多類分類錯誤率;mlogloss:多類logloss;auc:曲線下面積;aucpr:PR曲線下的面積;ndcg:歸一化累計折扣;map:平均精度;
seed :隨機數種子,[默認= 0]。
這個參數用來控制理想的優化目標和每一步結果的度量方法。
3. 命令行參數
這裏不說了,由於不多用命令行控制檯版本
4. XGBoost的調參說明:
參數調優的通常步驟:
1.肯定(較大)學習速率和提高參數調優的初始值
2.max_depth 和 min_child_weight 參數調優
3.gamma參數調優
4.subsample 和 colsample_bytree 參數優
5.正則化參數alpha調優
6.下降學習速率和使用更多的決策樹
5. XGBoost詳細攻略:
1). 安裝XGBoost
方式1:
pip3 install xgboost
方式2:
pip install xgboost
2). 數據接口(XGBoost可處理的數據格式DMatrix)
# 1.LibSVM文本格式文件dtrain = xgb.DMatrix('train.svm.txt')dtest = xgb.DMatrix('test.svm.buffer')# 2.CSV文件(不能含類別文本變量,若是存在文本變量請作特徵處理如one-hot)dtrain = xgb.DMatrix('train.csv?format=csv&label_column=0')dtest = xgb.DMatrix('test.csv?format=csv&label_column=0')# 3.NumPy數組data = np.random.rand(5, 10) # 5 entities, each contains 10 featureslabel = np.random.randint(2, size=5) # binary targetdtrain = xgb.DMatrix(data, label=label)# 4.scipy.sparse數組csr = scipy.sparse.csr_matrix((dat, (row, col)))dtrain = xgb.DMatrix(csr)# pandas數據框dataframedata = pandas.DataFrame(np.arange(12).reshape((4,3)), columns=['a', 'b', 'c'])label = pandas.DataFrame(np.random.randint(2, size=4))dtrain = xgb.DMatrix(data, label=label)
筆者推薦:先保存到XGBoost二進制文件中將使加載速度更快,而後再加載進來
# 1.保存DMatrix到XGBoost二進制文件中dtrain = xgb.DMatrix('train.svm.txt')dtrain.save_binary('train.buffer')# 2. 缺乏的值能夠用DMatrix構造函數中的默認值替換:dtrain = xgb.DMatrix(data, label=label, missing=-999.0)# 3.能夠在須要時設置權重:w = np.random.rand(5, 1)dtrain = xgb.DMatrix(data, label=label, missing=-999.0, weight=w)
3). 參數的設置方式:
# 加載並處理數據df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data',header=None)df_wine.columns = ['Class label', 'Alcohol','Malic acid', 'Ash','Alcalinity of ash','Magnesium', 'Total phenols', 'Flavanoids', 'Nonflavanoid phenols','Proanthocyanins','Color intensity', 'Hue','OD280/OD315 of diluted wines','Proline']df_wine = df_wine[df_wine['Class label'] != 1] # drop 1 classy = df_wine['Class label'].valuesX = df_wine[['Alcohol','OD280/OD315 of diluted wines']].valuesfrom sklearn.model_selection import train_test_split # 切分訓練集與測試集from sklearn.preprocessing import LabelEncoder # 標籤化分類變量le = LabelEncoder()y = le.fit_transform(y)X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=1,stratify=y)dtrain = xgb.DMatrix(X_train, label=y_train)dtest = xgb.DMatrix(X_test)# 1.Booster 參數params = { 'booster': 'gbtree', 'objective': 'multi:softmax', # 多分類的問題 'num_class': 10, # 類別數,與 multisoftmax 並用 'gamma': 0.1, # 用於控制是否後剪枝的參數,越大越保守,通常0.一、0.2這樣子。 'max_depth': 12, # 構建樹的深度,越大越容易過擬合 'lambda': 2, # 控制模型複雜度的權重值的L2正則化項參數,參數越大,模型越不容易過擬合。 'subsample': 0.7, # 隨機採樣訓練樣本 'colsample_bytree': 0.7, # 生成樹時進行的列採樣 'min_child_weight': 3, 'silent': 1, # 設置成1則沒有運行信息輸出,最好是設置爲0. 'eta': 0.007, # 如同窗習率 'seed': 1000, 'nthread': 4, # cpu 線程數 'eval_metric':'auc'}plst = params.items()# evallist = [(dtest, 'eval'), (dtrain, 'train')] # 指定驗證集
4). 訓練
# 2.訓練num_round = 10bst = xgb.train( plst, dtrain, num_round)#bst = xgb.train( plst, dtrain, num_round, evallist )
5). 保存模型
# 3.保存模型bst.save_model('0001.model')# dump modelbst.dump_model('dump.raw.txt')# dump model with feature map#bst.dump_model('dump.raw.txt', 'featmap.txt')
6) . 加載保存的模型
# 4.加載保存的模型:bst = xgb.Booster({'nthread': 4}) # init modelbst.load_model('0001.model') # load data
7). 設置早停機制
# 5.也能夠設置早停機制(須要設置驗證集)train(..., evals=evals, early_stopping_rounds=10)
8). 預測
# 6.預測ypred = bst.predict(dtest)
9). 繪圖
# 1.繪製重要性xgb.plot_importance(bst)# 2.繪製輸出樹#xgb.plot_tree(bst, num_trees=2)# 3.使用xgboost.to_graphviz()將目標樹轉換爲graphviz#xgb.to_graphviz(bst, num_trees=2)
6. 實戰案例:
1). 分類案例
from sklearn.datasets import load_irisimport xgboost as xgbfrom xgboost import plot_importancefrom matplotlib import pyplot as pltfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import accuracy_score # 準確率# 加載樣本數據集iris = load_iris()X,y = iris.data,iris.targetX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234565) # 數據集分割
# 算法參數params = { 'booster': 'gbtree', 'objective': 'multi:softmax', 'num_class': 3, 'gamma': 0.1, 'max_depth': 6, 'lambda': 2, 'subsample': 0.7, 'colsample_bytree': 0.75, 'min_child_weight': 3, 'silent': 0, 'eta': 0.1, 'seed': 1, 'nthread': 4,}
plst = params.items()
dtrain = xgb.DMatrix(X_train, y_train) # 生成數據集格式num_rounds = 500model = xgb.train(plst, dtrain, num_rounds) # xgboost模型訓練
# 對測試集進行預測dtest = xgb.DMatrix(X_test)y_pred = model.predict(dtest)
# 計算準確率accuracy = accuracy_score(y_test,y_pred)print("accuarcy: %.2f%%" % (accuracy*100.0))
# 顯示重要特徵plot_importance(model)plt.show()
2). 迴歸案例
import xgboost as xgbfrom xgboost import plot_importancefrom matplotlib import pyplot as pltfrom sklearn.model_selection import train_test_splitfrom sklearn.datasets import load_bostonfrom sklearn.metrics import mean_squared_error
# 加載數據集boston = load_boston()X,y = boston.data,boston.target
# XGBoost訓練過程X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
params = { 'booster': 'gbtree', 'objective': 'reg:squarederror', 'gamma': 0.1, 'max_depth': 5, 'lambda': 3, 'subsample': 0.7, 'colsample_bytree': 0.7, 'min_child_weight': 3, 'silent': 1, 'eta': 0.1, 'seed': 1000, 'nthread': 4,}
dtrain = xgb.DMatrix(X_train, y_train)num_rounds = 300plst = params.items()model = xgb.train(plst, dtrain, num_rounds)
# 對測試集進行預測dtest = xgb.DMatrix(X_test)ans = model.predict(dtest)
# 顯示重要特徵plot_importance(model)plt.show()
7. XGBoost調參(結合sklearn網格搜索)
import xgboost as xgbimport pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.model_selection import GridSearchCVfrom sklearn.metrics import roc_auc_score
iris = load_iris()X,y = iris.data,iris.targetcol = iris.target_namestrain_x, valid_x, train_y, valid_y = train_test_split(X, y, test_size=0.3, random_state=1) # 分訓練集和驗證集parameters = { 'max_depth': [5, 10, 15, 20, 25], 'learning_rate': [0.01, 0.02, 0.05, 0.1, 0.15], 'n_estimators': [500, 1000, 2000, 3000, 5000], 'min_child_weight': [0, 2, 5, 10, 20], 'max_delta_step': [0, 0.2, 0.6, 1, 2], 'subsample': [0.6, 0.7, 0.8, 0.85, 0.95], 'colsample_bytree': [0.5, 0.6, 0.7, 0.8, 0.9], 'reg_alpha': [0, 0.25, 0.5, 0.75, 1], 'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1], 'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]
}
xlf = xgb.XGBClassifier(max_depth=10, learning_rate=0.01, n_estimators=2000, silent=True, objective='multi:softmax', num_class=3 , nthread=-1, gamma=0, min_child_weight=1, max_delta_step=0, subsample=0.85, colsample_bytree=0.7, colsample_bylevel=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=0, missing=None)
gs = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)gs.fit(train_x, train_y)
print("Best score: %0.3f" % gs.best_score_)print("Best parameters set: %s" % gs.best_params_ )