sklearn集成方法
bagging
常見變體(按照樣本採樣方式的不一樣劃分)
- Pasting:直接從樣本集裏隨機抽取的到訓練樣本子集
- Bagging:自助採樣(有放回的抽樣)獲得訓練子集
- Random Subspaces:列採樣,按照特徵進行樣本子集的切分
- Random Patches:同時進行行採樣、列採樣獲得樣本子集
sklearn-bagging
學習器html
- BaggingClassifier
- BaggingRegressor
參數node
- 可自定義基學習器
- max_samples,max_features控制樣本子集的大小
- bootstrap,bootstrap_features控制是否使用自助採樣法
- 當使用自助採樣法時,能夠設置參數
oob_score=True
來經過包外估計來估計模型的泛化偏差(也就不須要進行交叉驗證了)
- 當使用自助採樣法時,能夠設置參數
Note:方差的產生主要是不一樣的樣本訓練獲得的學習器對於同一組測試集作出分類、預測結果的波動性,究其緣由是基學習器可能學到了所供學習的訓練樣本中的局部特徵或者說是擬合了部分噪聲數據,這樣綜合不一樣的學習器的結果,採起多數表決(分類)或者平均(迴歸)的方法能夠有效改善這一情況python
sklearn-forests of randomized trees
學習器git
- RandomForest: 採起自主採樣法構造多個基學習器,而且在學習基學習器時,不是使用所有的特徵來選擇最優切分點,而是先隨機選取一個特徵子集隨後在特徵子集裏挑選最優特徵進行切分;這種作法會使得各個基學習器的誤差略微提高,但在總體上下降了集成模型的方差,因此會獲得總體上不錯的模型
- RandomForestClassifier
- RandomForestRegressor
Notes:web
- 不一樣於原始的模型實現(讓各個基學習器對樣本的分類進行投票),sklearn裏隨機森林的實現是經過將各個基學習器的預測機率值取平均來獲得最終分類
-
隨機森林的行採樣(bagging)和列採樣(feature bagging)都是爲了減少模型之間的相關性使基學習器變得不一樣從而減少集成模型的方差算法
-
Extra-Trees(extremely randomized trees):相較於rf進一步加強了隨機性,rf是對各個基學習器隨機挑選了部分特徵來作維特徵子集從中挑選最佳的特徵切分,而Extra-Trees更進一步,在特徵子集裏挑選最佳特徵時不是選擇最有區分度的特徵值,而是隨機選擇這一劃分的閾值(該閾值在子特徵集裏的特徵對應的採樣後的樣本取值範圍裏隨機選取),而不一樣的隨機閾值下的特徵中表現最佳的做爲劃分特徵,這樣其實加強了隨機性,更進一步整大了基學習器的誤差但下降了總體的方差bootstrap
- ExtraTreesClassifier
- ExtraTreesRegressor
調參緩存
- 最重要的兩個參數
- n_estimators:森林中樹的數量,初始越多越好,可是會增長訓練時間,到達必定數量後模型的表現不會再有顯著的提高
- max_features:各個基學習器進行切分時隨機挑選的特徵子集中的特徵數目,數目越小模型總體的方差會越小,可是單模型的誤差也會上升,經驗性的設置迴歸問題的max_features爲總體特徵數目,而分類問題則設爲總體特徵數目開方的結果
- 其餘參數
- max_depth:樹的最大深度,經驗性的設置爲None(即不設限,徹底生長)
- min_samples_split,節點最小分割的樣本數,表示當前樹節點還能夠被進一步切割的含有的最少樣本數;經驗性的設置爲1,緣由同上
- bootstrap,rf裏默認是True也就是採起自助採樣,而Extra-Trees則是默認關閉的,是用整個數據集的樣本,當bootstrap開啓時,一樣能夠設置oob_score爲True進行包外估計測試模型的泛化能力
- n_jobs,並行化,能夠在機器的多個核上並行的構造樹以及計算預測值,不過受限於通訊成本,可能效率並不會說分爲k個線程就獲得k倍的提高,不過總體而言相對須要構造大量的樹或者構建一棵複雜的樹而言仍是高效的
- criterion:切分策略:gini或者entropy,默認是gini,與樹相關
- min_impurity_split–>min_impurity_decrease:用來進行早中止的參數,判斷樹是否進一步分支,原先是比較不純度是否仍高於某一閾值,0.19後是判斷不純度的下降是否超過某一閾值
- warm_start:若設爲True則能夠再次使用訓練好的模型並向其中添加更多的基學習器
- class_weight:設置數據集中不一樣類別樣本的權重,默認爲None,也就是全部類別的樣本權重均爲1,數據類型爲字典或者字典列表(多類別)
- balanced:根據數據集中的類別的佔比來按照比例進行權重設置n_samples/(n_classes*np.bincount(y))
- balanced_subsamples:相似balanced,不過權重是根據自助採樣後的樣原本計算
方法安全
- predict(X):返回輸入樣本的預測類別,返回類別爲各個樹預測機率均值的最大值
- predict_log_proba(X):
- predict_proba(X):返回輸入樣本X屬於某一類別的機率,經過計算隨機森林中各樹對於輸入樣本的平均預測機率獲得,每棵樹輸出的機率由葉節點中類別的佔比獲得
- score(X,y):返回預測的平均準確率
特徵選擇性能優化
特徵重要性評估:一棵樹中的特徵的排序(好比深度)能夠用來做爲特徵相對重要性的一個評估,居於樹頂端的特徵相對而言對於最終樣本的劃分貢獻最大(通過該特徵劃分所涉及的樣本比重最大),這樣能夠經過對比各個特徵所劃分的樣本比重的一個指望值來評估特徵的相對重要性,而在隨機森林中,經過對於不一樣樹的特徵的指望取一個平都可以減少評估結果的方差,以供特徵選擇;在sklearn中這些評估最後被保存在訓練好的模型的參數featureimportances裏,是各個特徵的重要性值通過歸一化的結果,越高表明特徵越匹配預測函數
Notes:
- 此外sklearn還有一種RandomTreesEmbedding的實現,不是很清楚有何特殊用途
隨機森林與KNN
- 類似之處:均屬於所謂的權重近鄰策略(weighted neighborhoods schemes):指的是,模型經過訓練集來經過輸入樣本的近鄰樣本點對輸入樣本做出預測,經過一個帶權重的函數關係
boosting
sklearn-AdaBoost
- AdaBoost可用於分類和迴歸
- AdaBoostClassifier
- AdaBoostRegressor
- 參數
- n_estimators:基學習器數目
- learning_rate:學習率,對應在最終的繼承模型中各個基學習器的權重
- base_estimator:基學習器默認是使用決策樹樁
_Notes:調參的關鍵參數是基學習器的數量n_estimators
以及基學習器自己的複雜性好比深度max_depth
或者葉節點所需的最少樣本數min_samples_leaf
_
sklearn-GBRT
概述
Gradient Tree Boosting或者說GBRT是boosting的一種推廣,是的能夠應用通常的損失函數,能夠處理分類問題和迴歸問題,應用普遍,常見應用場景好比網頁搜索排序和社會生態學
優缺點
- 優勢:
- 可以直接處理混合類型的特徵
- 對輸出空間的異常值的魯棒性(經過魯棒的損失函數)
- 缺點:
- 難以並行,由於自己boosting的思想是一個接一個的訓練基學習器
學習器
-
GradientBoostingClassifier
- 支持二分類和多分類
- 參數控制:
- 基學習器的數量
n_estimators
- 每棵樹的大小能夠經過樹深
max_depth
或者葉節點數目max_leaf_nodes
來控制(注意兩種樹的生長方式不一樣,max_leaf_nodes
是針對葉節點優先挑選不純度降低最多的葉節點,這裏有點LightGBM的’leaf-wise’的意味,而按樹深分裂則更相似於原始的以及XGBoost的分裂方式) - 學習率
learning_rate
對應取值範圍在(0,1]之間的超參數對應GBRT裏的shrinkage來避免過擬合(是sklearn裏的GBDT用來進行正則化的一種策略); - 對於須要多分類的問題須要設置參數
n_classes
對應每輪迭代的迴歸樹,這樣整體樹的數目是n_classes*n_estimators
criterion
用來設置迴歸樹的切分策略friedman_mse
,對應的最小平方偏差的近似,加入了Friedman的一些改進mse
對應最小平方偏差mae
對應平均絕對值偏差
subsample
:行採樣,對樣本採樣,即訓練每一個基學習器時再也不使用原始的所有數據集,而是使用一部分,而且使用隨機梯度上升法來作集成模型的訓練- 列採樣:
max_features
在訓練基學習器時使用一個特徵子集來訓練,相似隨機森林的作法 - early stopping:經過參數
min_impurity_split
(原始)以及min_impurity_decrease
來實現,前者的是根據節點的不純度是否高於閾值,若不是則中止增加樹,做爲葉節點;後者則根據分裂不純度降低值是否超過某一閾值來決定是否分裂(此外這裏的early stopping彷佛與XGBoost裏顯示設置的early stopping不一樣,這裏是控制樹的切分生長,而XGBoost則是控制基學習器的數目)
另一點,有說這裏的early_stopping起到了一種正則化的效果,由於控制了葉節點的切分閾值從而控制了模型的複雜度(可參考李航《統計學習方法》P213底部提高方法沒有顯式的正則化項,一般經過早中止的方法達到正則化的效果) - 基學習器的初始化:
init
,用來計算初始基學習器的預測,須要具有fit
和predict
方法,若未設置則默認爲loss.init_estimator
- 模型的重複使用(熱啓動):
warm_start
,若設置爲True則能夠使用已經訓練好的學習器,而且在其上添加更多的基學習器 - 預排序:
presort
,默認設置爲自動,對樣本按特徵值進行預排序從而提升尋找最優切分點的效率,自動模式下對稠密數據會使用預排序,而對稀疏數據則不會 - 損失函數(
loss
)- 二分類的對數損失函數(Binomial deviance,’deviance’),提供機率估計,模型初值設爲對數概率
- 多分類的對數損失(Multinomial deviance,’deviance’),針對
n_classes
互斥的多分類,提供機率估計,初始模型值設爲各種別的先驗機率,每一輪迭代須要構建n類迴歸樹可能會使得模型對於多類別的大數據集不過高效 - 指數損失函數(Exponential loss),與AdaBoostClassifier的損失函數一致,相對對數損失來講對錯誤標籤的樣本不夠魯棒,只可以被用來做二分類
- 基學習器的數量
- 經常使用方法
- 特徵重要性(
feature_importances_
):進行特徵重要性的評估 - 包外估計(
oob_improvement_
),使用包外樣原本計算每一輪訓練後模型的表現提高 - 訓練偏差(
train_score_
) - 訓練好的基學習器集合(
estimators_
) fit
方法裏能夠設置樣本權重sample_weight
,monitor
能夠用來回調一些方法好比包外估計、早中止等
- 特徵重要性(
-
GradientBoostingRegressor
- 支持不一樣的損失函數,經過參數loss設置,默認的損失函數是最小均方偏差
ls
- 經過屬性
train_score_
可得到每輪訓練的訓練偏差,經過方法staged_predict
能夠得到每一階段的測試偏差,經過屬性feature_importances_
能夠輸出模型判斷的特徵相對重要性 - 損失函數:
- 最小均方偏差(Least squares,’ls’),計算方便,通常初始模型爲目標均值
- 最小絕對值偏差(Least absolute deviation,’lad’),初始模型爲目標中位值
- Huber,一種結合了最小均方偏差和最小絕對值偏差的方法,使用參數alpha來控制對異常點的敏感狀況
- 支持不一樣的損失函數,經過參數loss設置,默認的損失函數是最小均方偏差
正則化
- Shrinkage,對應參數
learning rate
一種簡單的正則化的策略,經過控制每個基學習器的貢獻,會影響到基學習器的數目即n_estimators
,經驗性的設置爲一個較小的值,好比不超過0.1的常數值,而後使用early stopping來控制基學習器的數目 - 行採樣,使用隨機梯度上升,將gradient boosting與bagging相結合,每一次迭代經過採樣的樣本子集來訓練基學習器(對應參數
subsample
),通常設置shrinkage比不設置要好,而加上行採樣會進一步提高效果,而僅使用行採樣可能效果反而不佳;並且進行行採樣後可以使用包外估計來計算模型每一輪訓練的效果提高,保存在屬性oob_improvement_
裏,能夠用來作模型選擇,可是包外預估的結果一般比較悲觀,因此除非交叉驗證太過耗時,不然建議結合交叉驗證一塊兒進行模型選擇 - 列採樣,相似隨機森林的作法,經過設置參數
max_features
來實現
可解釋性
單一的決策樹能夠經過將樹結構可視化來分析和解釋,而梯度上升模型由於由上百課迴歸樹組成所以他們很難像單獨的決策樹同樣被可視化,不過也有一些技術來輔助解釋模型
- 特徵重要性(featureimportances屬性),決策樹在選擇最佳分割點時間接地進行了特徵的選擇,而這一信息能夠用來評估每個特徵的重要性,基本思想是一個特徵越常常地被用來做爲樹的切分特徵(更加說明使用的是CART樹或其變體,由於ID3,C4.5都是特徵用過一次後就再也不用了),那麼這個特徵就越重要,而對於基於樹的集成模型而言能夠經過對各個樹判斷的特徵重要性作一個平均來表示特徵的重要性
- PDP(Partial dependence plots),能夠用來繪製目標響應與目標特徵集的依賴關係(控制其餘的特徵的值),受限於人類的感知,目標特徵集合通常設置爲1或2才能繪製對應的圖形(plot_partial_dependence),也能夠經過函數partial_dependence來輸出原始的值
Notes:
- GradientBoostingClassifier和GradientBoostingRegressor均支持對訓練好的學習器的複用,經過設置warm_start=True能夠在已經訓練好的模型上添加更多的基學習器
VotingClassifier
Voting的基本思想是將不一樣學習器的結果進行硬投票(多數表決)或者軟投票(對預測機率加權平均)來對樣本類別作出預估,其目的是用來平衡一些表現至關且都還不錯的學習器的表現,以消除它們各自的缺陷
- 硬投票(
voting
=’hard’):按照多數表決原則,根據分類結果中多數預測結果做爲輸入樣本的預測類別,若是出現類別數目相同的狀況,會按照預測類別的升序排序取前一個預測類別(好比模型一預測爲類別‘2’,模型二預測爲類別‘1’則樣本會被判爲類別1) - 軟投票:對不一樣基學習器的預測機率進行加權平均(所以使用軟投票的基學習器須要可以預測機率),需設置參數
wights
爲一個列表表示各個基學習器的權重值
XGBoost
過擬合
XGBoost裏能夠使用兩種方式防止過擬合
- 直接控制模型複雜度
max_depth
,基學習器的深度,增長該值會使基學習器變得更加複雜,榮易過擬合,設爲0表示不設限制,對於depth-wise的基學習器學習方法須要控制深度min_child_weight
,子節點所需的樣本權重和(hessian)的最小閾值,如果基學習器切分後獲得的葉節點中樣本權重和低於該閾值則不會進一步切分,在線性模型中該值就對應每一個節點的最小樣本數,該值越大模型的學習約保守,一樣用於防止模型過擬合gamma
,葉節點進一步切分的最小損失降低的閾值(超過該值才進一步切分),越大則模型學習越保守,用來控制基學習器的複雜度(有點LightGBM裏的leaf-wise切分的意味)
- 給模型訓練增長隨機性使其對噪聲數據更加魯棒
- 行採樣:
subsample
- 列採樣:
colsample_bytree
- 步長:
eta
即shrinkage
- 行採樣:
數據類別分佈不均
對於XGBoost來講一樣是兩種方式
- 若只關注預測的排序表現(auc)
- 調整正負樣本的權重,使用
scale_pos_weight
- 使用auc做爲評價指標
- 調整正負樣本的權重,使用
- 若關注預測出正確的機率值,這種狀況下不能調整數據集的權重,能夠經過設置參數
max_delta_step
爲一個有限值好比1來加速模型訓練的收斂
調參
通常參數
主要用於設置基學習器的類型
- 設置基學習器
booster
- 基於樹的模型
- gbtree
- dart
- 線性模型
- gblinear
- 基於樹的模型
- 線程數
nthread
,設置並行的線程數,默認是最大線程數
基學習器參數
在基學習器肯定後,根據基學習器來設置的一些個性化的參數
eta
,步長、學習率,每一輪boosting訓練後能夠獲得新特徵的權重,能夠經過eta來適量縮小權重,使模型的學習過程更加保守一點,以防止過擬合gamma
,葉節點進一步切分的最小損失降低的閾值(超過該值才進一步切分),越大則模型學習越保守,用來控制基學習器的複雜度(有點LightGBM裏的leaf-wise切分的意味)max_depth
,基學習器的深度,增長該值會使基學習器變得更加複雜,榮易過擬合,設爲0表示不設限制,對於depth-wise的基學習器學習方法須要控制深度min_child_weight
,子節點所需的樣本權重和(hessian)的最小閾值,如果基學習器切分後獲得的葉節點中樣本權重和低於該閾值則不會進一步切分,在線性模型中該值就對應每一個節點的最小樣本數,該值越大模型的學習約保守,一樣用於防止模型過擬合max_delta_step
,樹的權重的最大估計值,設爲0則表示不設限,設爲整數會是模型學習相對保守,通常該參數沒必要設置,可是對於基學習器是LR時,在針對樣本分佈極爲不均的狀況控制其值在1~10之間能夠控制模型的更新- 行採樣:
subsample
,基學習器使用樣本的比重 - 列採樣:
colsample_bytree
,用於每棵樹劃分的特徵比重colsample_bylevel
,用於每層劃分的特徵比重
- 顯式正則化,增長該值是模型學習更爲保守
- L1:
alpha
- L2:
lambda
- L1:
tree_method
,樹的構建方法,準確的說應該是切分點的選擇算法,包括原始的貪心、近似貪心、直方圖算法(可見LightGBM這裏並非一個區別)auto
,啓發式地選擇分割方法,近似貪心或者貪心exact
,原始的貪心算法,既針對每個特徵值切分一次approx
,近似的貪心算法選取某些分位點進行切分,使用sketching和histogramhist
,直方圖優化的貪心算法,對應的參數有grow_policy
,max_bin
gpu_exact
gpu_hist
scale_pos_weight
,針對數據集類別分佈不均,典型的值可設置爲sum(negativecases)sum(positivecases)sum(negativecases)sum(positivecases)
grow_policy
,控制樹的生長方式,目前只有當樹的構建方法tree_method
設置爲hist
時才能夠使用所謂的leaf-wise
生長方式depthwise
,按照離根節點最近的節點進行分裂lossguide
,優先分裂損失變化大的節點,對應的一個參數還有max_leaves
,表示可增長的最大的節點數
max_bin
,一樣針對直方圖算法tree_method
設置爲hist
時用來控制將連續特徵離散化爲多個直方圖的直方圖數目predictor
,選擇使用GPU或者CPUcpu_predictor
gpu_predictor
任務參數
根據任務、目的設置的參數,好比迴歸任務與排序任務的目的是不一樣的
- objective,訓練目標,分類仍是迴歸
reg:linear
,線性迴歸reg:logistic
,邏輯迴歸binary:logistic
,使用LR二分類,輸出機率binary:logitraw
,使用LR二分類,但在進行logistic轉換以前直接輸出分類得分count:poisson
,泊松迴歸multi:softmax
,使用softmax進行多分類,須要設置類別數num_class
multi:softprob
rank:pairwise
,進行排序任務,最小化pairwise損失reg:gamma
,gamma迴歸reg:tweedie
,tweedie迴歸
- 評價指標
eval_metric
,默認根據目標函數設置,針對驗證集,默認狀況下,最小均方偏差用於迴歸,錯分用於分類,平均精確率用於排序等,能夠同時使用多個評估指標,在python裏使用列表來放置- 均方偏差
rmse
- 平均絕對值偏差
mae
- 對數損失
logloss
,負的對數似然 - 錯誤率
error
,根據0.5做爲閾值判斷的錯分率 - 自定義閾值錯分率
error@t
- 多分類錯分率
merror
- 多分類對數損失
mlogloss
auc
主要用來排序ndcg
,normalized discounted cumulative gain及其餘的一些針對泊松迴歸等問題的評價指標
- 均方偏差
命令行參數
num_round
迭代次數,也對應基學習器數目task
當前對模型的任務,包括- 訓練
train
- 預測
pred
- 評估/驗證
eval
- 導出模型
dump
- 訓練
- 導入導出模型的路徑
model_in
和model_out
fmap
,feature map用來導出模型
LightGBM
特色
效率和內存上的提高
直方圖算法,LightGBM提供一種數據類型的封裝相對Numpy,Pandas,Array等數據對象而言節省了內存的使用,緣由在於他只須要保存離散的直方圖,LightGBM裏默認的訓練決策樹時使用直方圖算法,XGBoost裏如今也提供了這一選項,不過默認的方法是對特徵預排序,直方圖算法是一種犧牲了必定的切分準確性而換取訓練速度以及節省內存空間消耗的算法
- 在訓練決策樹計算切分點的增益時,預排序須要對每一個樣本的切分位置計算,因此時間複雜度是O(#data)而LightGBM則是計算將樣本離散化爲直方圖後的直方圖切割位置的增益便可,時間複雜度爲O(#bins),時間效率上大大提升了(初始構造直方圖是須要一次O(#data)的時間複雜度,不過這裏只涉及到加和操做)
- 直方圖作差進一步提升效率,計算某一節點的葉節點的直方圖能夠經過將該節點的直方圖與另外一子節點的直方圖作差獲得,因此每次分裂只需計算分裂後樣本數較少的子節點的直方圖而後經過作差的方式得到另外一個子節點的直方圖,進一步提升效率
- 節省內存
- 將連續數據離散化爲直方圖的形式,對於數據量較小的情形能夠使用小型的數據類型來保存訓練數據
- 沒必要像預排序同樣保留額外的對特徵值進行預排序的信息
- 減小了並行訓練的通訊代價
稀疏特徵優化
對稀疏特徵構建直方圖時的時間複雜度爲O(2*#非零數據)
準確率上的優化
LEAF-WISE(BEST-FIRST)樹生長策略
相對於level-wise的生長策略而言,這種策略每次都是選取當前損失降低最多的葉節點進行分割使得總體模型的損失降低得更多,可是容易過擬合(特別當數據量較小的時候),能夠經過設置參數max_depth
來控制樹身防止出現過擬合
Notes:XGBoost如今兩種方式都是支持的
直接支持類別特徵
對於類別類型特徵咱們原始的作法是進行獨熱編碼,可是這種作法對於基於樹的模型而言不是很好,對於基數較大的類別特徵,可能會生成很是不平衡的樹而且須要一顆很深的樹才能達到較好的準確率;比較好的作法是將類別特徵劃分爲兩個子集,直接劃分方法衆多(2^(k-1)-1),對於迴歸樹而言有一種較高效的方法只須要O(klogk)的時間複雜度,基本思想是對類別按照與目標標籤的相關性進行重排序,具體一點是對於保存了類別特徵的直方圖根據其累計值(sum_gradient/sum_hessian)重排序,在排序好的直方圖上選取最佳切分位置
網絡通訊優化
使用collective communication算法替代了point-to-point communication算法提高了效率
並行學習優化
特徵並行
特徵並行是爲了將尋找決策樹的最佳切分點這一過程並行化
- 傳統作法
- 對數據列採樣,即不一樣的機器上保留不一樣的特徵子集
- 各個機器上的worker根據所分配的特徵子集尋找到局部的最優切分點(特徵、閾值)
- 互相通訊來從局部最佳切分點裏獲得最佳切分點
- 擁有最佳切分點的worker執行切分操做,而後將切分結果傳送給其餘的worker
- 其餘的worker根據接收到的數據來切分數據
- 傳統作法的缺點
- 計算量太大,並無提高切分的效率,時間複雜度爲O(#data)(由於每一個worker持有全部行,須要處理所有的記錄),當數據量較大時特徵並行並不能提高速度
- 切分結果的通訊代價,大約爲O(#data/8)(若一個數據樣本爲1bit)
- LightGBM的作法
讓每一個機器保留整個完整的數據集(並非通過列採樣的數據),這樣就沒必要在切分後傳輸切分結果數據,由於每一個機器已經持有完整的數據集- 各個機器上的worker根據所分配的特徵子集尋找到局部的最優切分點(特徵、閾值)
- 互相通訊來從局部最佳切分點裏獲得最佳切分點
- 執行最優切分操做
Notes:典型的空間換時間,差異就是減小了傳輸切分結果的步驟,節省了這裏的通訊消耗
數據並行
上述特徵並行的方法並無根本解決尋找切分點的計算效率問題,當記錄數過大時須要考慮數據並行的方法
- 傳統作法
- 行採樣,對數據進行橫向切分
- worker使用分配到的局部數據構建局部的直方圖
- 合併局部直方圖獲得全局的直方圖
- 對全局直方圖尋找最優切分點,而後進行切分
- 缺點:通訊代價太高,若使用point-to-point的通訊算法,每一個機器的通訊代價時間複雜度爲O(#machine*#feature*#bin),若使用collective通訊算法則通訊代價爲O(2*#feature*#bin)
- LightGBM的作法(依然是下降通訊代價)
- 不一樣於合併全部的局部直方圖得到全局的直方圖,LightGBM經過Reduce Scatter方法來合併不一樣worker的無交叉的不一樣特徵的直方圖,這樣找到該直方圖的局部最優切分點,最後同步到全局最優切分點
- 基於直方圖作差的方法,在通訊的過程當中能夠只傳輸某一葉節點的直方圖,而對於其鄰居可經過作差的方式獲得
- 通訊的時間複雜度爲O(0.5*#feature*#bin)
並行投票
進一步減少了數據並行中的通訊代價,經過兩輪的投票來減少特徵直方圖中的通訊消耗
其餘特色
直接支持類別(標稱)特徵
LightGBM能夠直接用類別特徵進行訓練,沒必要預先進行獨熱編碼,速度會提高很多,參數設置categorical_feature
來指定數據中的類別特徵列
早中止
sklearn-GBDT,XGBoost,LightGBM都支持早中止,不過在細節上略有不一樣
- sklearn-GBDT中的early stopping是用來控制基學習器的生長的:經過參數
min_impurity_split
(原始)以及min_impurity_decrease
來實現,前者的是根據節點的不純度是否高於閾值,若不是則中止增加樹,做爲葉節點;後者則根據分裂不純度降低值是否超過某一閾值來決定是否分裂(此外這裏的early stopping彷佛與XGBoost裏顯示設置的early stopping不一樣,這裏是控制樹的切分生長,而XGBoost則是控制基學習器的數目) - XGBoost和LightGBM裏的early_stopping則都是用來控制基學習器的數目的
- 二者均可以使用多組評價指標,可是不一樣之處在於XGBoost會根據指標列表中的最後一項指標控制模型的早中止,而LightGBM則會受到全部的評估指標的影響
- 在使用early stopping控制迭代次數後,模型直接返回的是最後一輪迭代的學習器不必定是最佳學習器,而在作出預測時能夠設置參數選擇某一輪的學習器做出預測
- XGBoost裏保存了三種狀態的學習器,分別是
bst.best_score, bst.best_iteration, bst.best_ntree_limit
,官方的建議是在作預測時設置爲bst.best_ntree_limit
,實際使用時感受bst.best_iteration
和bst.best_ntree_limit
的表現上區別不大 - LightGBM則僅提供了
bst.best_iteration
這一種方式
- XGBoost裏保存了三種狀態的學習器,分別是
實踐上
- 內置cv
- 支持帶權重的數據輸入
- 能夠保留模型
- DART
- L1/L2迴歸
- 保存模型進行進一步訓練
- 多組驗證集
支持的任務
- 迴歸任務
- 分類(二分類、多分類)
- 排序
支持的評價指標METRIC
- 絕對值偏差
l1
- 平方偏差
l2
- 均方偏差
l2_root
- 對數損失
binary_logloss
,multi_logloss
- 分類偏差率
binary_error
,multi_error
- auc
- ndcg
- 多分類對數損失
- 多分類分類偏差率
調參
核心參數
- 葉節點數
num_leaves
,與模型複雜度直接相關(leaf-wise) - 任務目標
- 迴歸
regression
,對應的損失函數以下regression_l1
,加了l1正則的迴歸,等同於絕對值偏差regression_l2
,等同於均方偏差huber
,Huber Lossfair
,Fair Losspoisson
,泊松迴歸
- 分類
binary
,二分類multiclass
,多分類
- 排序
lambdarank
- 迴歸
- 模型
boosting
gbdt
,傳統的梯度提高決策樹rf
,隨機森林dart
,Dropouts meet Multiple Additive Regression Treesgoss
,Gradient-based One-Side Sampling
- 迭代次數
num_iterations
,對於多分類問題,LightGBM會構建num_class*num_iterations的樹 - 學習率/步長
learning_rate
,即shrinkage - 樹的訓練方式
tree_learner
,主要用來控制樹是否並行化訓練serial
,單機的樹學習器feature
,特徵並行的樹學習器data
,數據並行的樹學習器
- 線程數
num_threads
- 設備
device
,使用cpu仍是gpucpu
gpu
訓練控制參數
防止過擬合
- 樹的最大深度
max_depth
,主要用來避免模型的過擬合,設爲負數值則代表不限制 - 葉節點的最少樣本數
min_data_in_leaf
- 葉節點的最小海森值之和
min_sum_hessian_in_leaf
- 列採樣
feature_fraction
,每棵樹的特徵子集佔比,設置在0~1之間,能夠加快訓練速度,避免過擬合 - 行採樣
bagging_fraction
,不進行重採樣的隨機選取部分樣本數據,此外須要設置參數bagging_freq
來做爲採樣的頻率,即多少輪迭代作一次bagging; - 早中止
early_stopping_roung
,在某一驗證數據的某一驗證指標當前最後一輪迭代沒有提高時中止迭代 - 正則化
lambda_l1
lambda_l2
- 切分的最小收益
min_gain_to_split
IO參數
直方圖相關
- 最大直方圖數
max_bin
,特徵值裝載的最大直方圖數目,通常較小的直方圖數目會下降訓練的準確性但會提高總體的表現,處理過擬合 - 直方圖中最少樣本數
min_data_in_bin
,設置每一個直方圖中樣本數的最小值,一樣防止過擬合
特徵相關
- 是否預排序
is_pre_partition
- 是否稀疏
is_sparse
- 類別特徵列
categorical_feature
,聲明類別特徵對應的列(經過索引標記),僅支持int類型 - 聲明權重列
weight
,指定一列做爲權重列
內存相關
- 分階段加載數據
two_round
,通常LightGBM將數據載入內存進行處理,這樣會提高數據的加載速度,可是對於數據量較大時會形成內存溢出,因此此時須要分階段載入 - 保存數據爲二進制
save_binary
,將數據文件導出爲二進制文件,下次加載數據時就會更快一些
缺失值
- 是否處理缺失值
use_missing
- 是否將0值做爲缺失值
zeros_as_missing
目標參數
sigmoid
,sigmoid函數中的參數,用於二分類和排序任務scale_pos_weight
,設置正例在二分類任務中的樣本佔比- 初始化爲均值
boost_from_average
,調整初始的分數爲標籤的均值,加速模型訓練的收斂速度,僅用於迴歸任務 - 樣本類別是否不平衡
is_unbalance
num_class
,用於多分類
調參小結
LEAF-WISE
num_leaves
,對於leaf-wise的模型而言該參數是用來控制模型複雜度的主要參數,理論上能夠經過設置num_leaves
=2^(max_depth)來設置該參數值,實際是不可取的,由於在節點數目相同的前提下,對於leaf-wise的模型會傾向於生成深度更深的模型,若是生硬的設置爲2^(max_depth)可能會形成模型的過擬合,通常設置的值小於2^(max_depth),min_data_in_leaf
,在設置了葉節點數後,該值會對模型複雜度形成影響,若設的較大則樹不會生長的很深,但可能形成模型的欠擬合max_depth
效率
bagging_fraction
和bagging_freq
,使用bagging進行行採樣提高訓練速度(減少了數據集)feature_fraction
,列採樣- 設置較少的直方圖數目,
max_bin
- 保存數據爲二進制文件以便於將來訓練時能快速加載,
save_binary
- 經過並行訓練來提速
準確率
- 設置較大的直方圖數目
max_bin
,固然這樣會犧牲訓練速度 - 使用較小的學習率
learning_rate
,這樣會增長迭代次數 - 設置較大的葉節點數
num_leaves
,可能形成模型過擬合 - 使用較大的訓練數據
- 嘗試
dart
模型
過擬合
- 設置較少的直方圖數目,
max_bin
- 設置較小的葉節點數
num_leaves
- 設置參數
min_data_in_leaf
和min_sum__hessian_in_leaf
- 使用bagging進行行採樣
bagging_fraction
和bagging_freq
feature_fraction
,列採樣- 使用較大的訓練數據
- 正則化
lambda_l1
lambda_l2
- 切分的最小收益
min_gain_to_split
- 控制樹深
max_depth
總結
GBDT vs. XGBoost vs. LightGBM(論文層面)
GBDT vs. XGBoost
- GBDT是機器學習算法,XGBoost是該算法的工程實現
- GBDT無顯式正則化;在使用CART做爲基分類器時,XGBoost顯式地加入了正則項來控制模型的複雜度,有利於防止過擬合,提升模型的泛化性能。
- GBDT僅使用了目標函數一階泰勒展開,而XGBoost使用了二階的泰勒展開值
- 一說加快收斂速度
- 另外有說自己模型訓練的學習率shrinkage能夠經過二階導數作一個逼近,而原始的GBDT沒有計算這個,因此通常是經過預設的超參數eta人爲指定
- GBDT採用CART做爲基分類器,XGBoost支持多種類型的基分類器,好比線性分類器
- GBDT在每輪迭代中使用所有數據,XGBoost採用了與隨機森林類似的策略,支持對數據進行採樣
- GBDT沒有設計對缺失值進行處理,XGBoost能自動學習出缺失值的處理策略
- XGBoost經過預排序的方法來實現特徵並行,提升模型訓練效率
- XGBoost支持分佈式計算
XGBoost vs. LightGBM
- 樹的切分策略不一樣
- XGBoost是level-wise而LightGBM是leaf-wise
- 實現並行的方式不一樣
- XGBoost是經過預排序的方式
- LightGBM則是經過直方圖算法
- LightGBM直接支持類別特徵,對類別特徵沒必要進行獨熱編碼處理
sklearn GBDT vs. XGBoost vs. LightGBM(實現層面)
實際在庫的實現層面原始論文裏的不少區別是不存在的,差別更多在一些工程上的性能優化
sklearn GBDT vs. XGBoost
- 正則化方式不一樣
- sklearn GBDT中僅僅經過學習率來作一個正則化(影響到基學習器的數目),此外gbdt裏的early stopping也達到了一個正則化的效果,對應的主要參數是
min_impurity_split
即控制了判斷葉節點是否進一步切分的不純度的閾值,若超過該閾值則能夠進一步切分,不然不行,故而控制了樹的深度即控制了基學習器的複雜度 - XGBoost除了學習率之外還有顯示的設置正則化項l1,l2以及對應論文裏的葉節點數(對應參數gamma)以及節點權重和(參數min_child_weight)來控制模型複雜度
- sklearn GBDT中僅僅經過學習率來作一個正則化(影響到基學習器的數目),此外gbdt裏的early stopping也達到了一個正則化的效果,對應的主要參數是
- GBDT僅使用了目標函數一階泰勒展開,而XGBoost使用了二階的泰勒展開值
- XGBoost自有一套對缺失值的處理方法
- early-stopping意義不一樣
- sklearn GBDT中控制基學習器進一步切分、生長
- XGBoost控制基學習器的數目
- 特徵重要性的判斷標準
- sklearn GBDT是根據樹的節點特徵對應的深度來判斷
- XGBoost則有三種方法(get_score)
- weight:特徵用來做爲切分特徵的次數
- gain:使用特徵進行切分的平均增益
- cover:各個樹中該特徵平均覆蓋狀況(根據樣本?)
- 樹的切分算法
- XGBoost存在三種切分方法,
- 原始的貪心算法(每一個特徵值切分)
- 近似貪心(分位點切分)(使得對於大量的特徵取值尤爲是連續變量時XGBoost會比sklearn-gbdt快不少)
- 直方圖算法
- XGBoost存在三種切分方法,
- XGBoost支持level-wise和leaf-wise兩種樹的生長方式
- XGBoost支持GPU
- XGBoost支持多種評價標準、支持多種任務(迴歸、分類、排序)
XGBoost vs. LightGBM
XGBoost目前已經實現了LightGBM以前不一樣的一些方法好比直方圖算法,二者的區別更多的在與LightGBM優化通訊的的一些處理上
- LightGBM直接支持類別特徵,能夠沒必要預先進行獨熱編碼,提升效率(categorical_feature)
- 優化通訊代價
- 特徵並行
- 數據並行
- point to point communication–>collective communication
- 使用多項評價指標同時評價時二者的早中止策略不一樣,XGBoost是根據評價指標列表中的最後一項來做爲中止標準,而LightGBM則受到全部評價指標的影響
lightGBM與XGBoost的區別:
(1)xgboost採用的是level-wise的分裂策略,而lightGBM採用了leaf-wise的策略,區別是xgboost對每一層全部節點作無差異分裂,可能有些節點的增益很是小,對結果影響不大,可是xgboost也進行了分裂,帶來了務必要的開銷。 leaft-wise的作法是在當前全部葉子節點中選擇分裂收益最大的節點進行分裂,如此遞歸進行,很明顯leaf-wise這種作法容易過擬合,由於容易陷入比較高的深度中,所以須要對最大深度作限制,從而避免過擬合。
(2)lightgbm使用了基於histogram的決策樹算法,這一點不一樣與xgboost中的 exact 算法,histogram算法在內存和計算代價上都有不小優點。
-. 內存上優點:很明顯,直方圖算法的內存消耗爲(#data* #features * 1Bytes)(由於對特徵分桶後只需保存特徵離散化以後的值),而xgboost的exact算法內存消耗爲:(2 * #data * #features* 4Bytes),由於xgboost既要保存原始feature的值,也要保存這個值的順序索引,這些值須要32位的浮點數來保存。
-. 計算上的優點,預排序算法在選擇好分裂特徵計算分裂收益時須要遍歷全部樣本的特徵值,時間爲(#data),而直方圖算法只須要遍歷桶就好了,時間爲(#bin)
(3)直方圖作差加速
-. 一個子節點的直方圖能夠經過父節點的直方圖減去兄弟節點的直方圖獲得,從而加速計算。
(4)lightgbm支持直接輸入categorical 的feature
-. 在對離散特徵分裂時,每一個取值都看成一個桶,分裂時的增益算的是」是否屬於某個category「的gain。相似於one-hot編碼。
(5)但實際上xgboost的近似直方圖算法也相似於lightgbm這裏的直方圖算法,爲何xgboost的近似算法比lightgbm仍是慢不少呢?
-. xgboost在每一層都動態構建直方圖, 由於xgboost的直方圖算法不是針對某個特定的feature,而是全部feature共享一個直方圖(每一個樣本的權重是二階導),因此每一層都要從新構建直方圖,而lightgbm中對每一個特徵都有一個直方圖,因此構建一次直方圖就夠了。
-. lightgbm作了cache優化?
(6)lightgbm哪些方面作了並行?
-. feature parallel
通常的feature parallel就是對數據作垂直分割(partiion data vertically,就是對屬性分割),而後將分割後的數據分散到各個workder上,各個workers計算其擁有的數據的best splits point, 以後再彙總獲得全局最優分割點。可是lightgbm說這種方法通信開銷比較大,lightgbm的作法是每一個worker都擁有全部數據,再分割?(沒懂,既然每一個worker都有全部數據了,再彙總有什麼意義?這個並行體如今哪裏??)
-. data parallel
傳統的data parallel是將對數據集進行劃分,也叫 平行分割(partion data horizontally), 分散到各個workers上以後,workers對獲得的數據作直方圖,彙總各個workers的直方圖獲得全局的直方圖。 lightgbm也claim這個操做的通信開銷較大,lightgbm的作法是使用」Reduce Scatter「機制,不彙總全部直方圖,只彙總不一樣worker的不一樣feature的直方圖(原理?),在這個彙總的直方圖上作split,最後同步。
XGBoost
XGBoost(eXtreme Gradient Boosting)全名叫極端梯度提高
目錄
1. 最優模型的構建方法
2. Boosting的迴歸思想
3. XGBoost的目標函數推導
4. XGBoost的迴歸樹構建方法
5. XGBoost與GDBT的區別
最優模型的構建方法
構建最優模型的通常方法是最小化訓練數據的損失函數,咱們用字母 L表示,以下式:
式(1)稱爲經驗風險最小化,訓練獲得的模型複雜度較高。當訓練數據較小時,模型很容易出現過擬合問題。
所以,爲了下降模型的複雜度,常採用下式:
其中J(f)爲模型的複雜度,式(2)稱爲結構風險最小化,結構風險最小化的模型每每對訓練數據以及未知的測試數據都有較好的預測 。
應用:決策樹的生成和剪枝分別對應了經驗風險最小化和結構風險最小化,XGBoost的決策樹生成是結構風險最小化的結果
Boosting方法的迴歸思想
Boosting法是結合多個弱學習器給出最終的學習結果,無論任務是分類或迴歸,咱們都用迴歸任務的思想來構建最優Boosting模型 。
迴歸思想:把每一個弱學習器的輸出結果當成連續值,這樣作的目的是能夠對每一個弱學習器的結果進行累加處理,且能更好的利用損失函數來優化模型。
假設是第 t 輪弱學習器的輸出結果,
是模型的輸出結果,
是實際輸出結果,表達式以下:
上面兩式就是加法模型,都默認弱學習器的輸出結果是連續值。由於迴歸任務的弱學習器自己是連續值,因此不作討論,下面詳細介紹分類任務的迴歸思想。
分類任務的迴歸思想:
根據2.1式的結果,獲得最終的分類器:
分類的損失函數通常選擇指數函數或對數函數,這裏假設損失函數爲對數函數,學習器的損失函數是
若實際輸出結果yi=1,則:
求(2.5)式對的梯度,得:
負梯度方向是損失函數降低最快的方向,(2.6)式取反的值大於0,所以弱學習器是往增大的方向迭代的,圖形表示爲:
如上圖,當樣本的實際標記 yi 是 1 時,模型輸出結果隨着迭代次數的增長而增長(紅線箭頭),模型的損失函數相應的減少;當樣本的實際標記 yi 是 -1時,模型輸出結果
隨着迭代次數的增長而減少(紅線箭頭),模型的損失函數相應的減少 。這就是加法模型的原理所在,經過屢次的迭代達到減少損失函數的目的。
小結:Boosting方法把每一個弱學習器的輸出當作是連續值,使得損失函數是個連續值,所以能夠經過弱學習器的迭代達到優化模型的目的,這也是集成學習法加法模型的原理所在 。
XGBoost算法的目標函數推導
目標函數,即損失函數,經過最小化損失函數來構建最優模型,由第一節可知, 損失函數應加上表示模型複雜度的正則項,且XGBoost對應的模型包含了多個CART樹,所以,模型的目標函數爲:
(3.1)式是正則化的損失函數,等式右邊第一部分是模型的訓練偏差,第二部分是正則化項,這裏的正則化項是K棵樹的正則化項相加而來的。
CART樹的介紹:
上圖爲第K棵CART樹,肯定一棵CART樹須要肯定兩部分,第一部分就是樹的結構,這個結構將輸入樣本映射到一個肯定的葉子節點上,記爲。第二部分就是各個葉子節點的值,q(x)表示輸出的葉子節點序號,
表示對應葉子節點序號的值。由定義得:
樹的複雜度定義
XGBoost法對應的模型包含了多棵cart樹,定義每棵樹的複雜度:
其中T爲葉子節點的個數,||w||爲葉子節點向量的模 。γ表示節點切分的難度,λ表示L2正則化係數。
以下例樹的複雜度表示:
目標函數推導
根據(3.1)式,共進行t次迭代的學習模型的目標函數爲:
泰勒公式的二階導近似表示:
令爲Δx,則(3.5)式的二階近似展開:
其中:
表示前t-1棵樹組成的學習模型的預測偏差,gi和hi分別表示預測偏差對當前模型的一階導和二階導 ,當前模型往預測偏差減少的方向進行迭代。
忽略(3.8)式常數項,並結合(3.4)式,得:
經過(3.2)式簡化(3.9)式:
(3.10)式第一部分是對全部訓練樣本集進行累加,由於全部樣本都是映射爲樹的葉子節點,咱們換種思惟,從葉子節點出發,對全部的葉子節點進行累加,得:
令
Gj 表示映射爲葉子節點 j 的全部輸入樣本的一階導之和,同理,Hj表示二階導之和。
得:
對於第 t 棵CART樹的某一個肯定結構(可用q(x)表示),其葉子節點是相互獨立的,Gj和Hj是肯定量,所以,(3.12)能夠當作是關於葉子節點的一元二次函數 。最小化(3.12)式,得:
獲得最終的目標函數:
(3.14)也稱爲打分函數(scoring function),它是衡量樹結構好壞的標準,值越小,表明這樣的結構越好 。咱們用打分函數選擇最佳切分點,從而構建CART樹。
CART迴歸樹的構建方法
上節推導獲得的打分函數是衡量樹結構好壞的標準,所以,可用打分函數來選擇最佳切分點。首先肯定樣本特徵的全部切分點,對每個肯定的切分點進行切分,切分好壞的標準以下:
Gain表示單節點obj*與切分後的兩個節點的樹obj*之差,遍歷全部特徵的切分點,找到最大Gain的切分點便是最佳分裂點,根據這種方法繼續切分節點,獲得CART樹。若 γ 值設置的過大,則Gain爲負,表示不切分該節點,由於切分後的樹結構變差了。γ值越大,表示對切分後obj降低幅度要求越嚴,這個值能夠在XGBoost中設定。
XGBoost與GDBT的區別
1. XGBoost生成CART樹考慮了樹的複雜度,GDBT未考慮,GDBT在樹的剪枝步驟中考慮了樹的複雜度。
2. XGBoost是擬合上一輪損失函數的二階導展開,GDBT是擬合上一輪損失函數的一階導展開,所以,XGBoost的準確性更高,且知足相同的訓練效果,須要的迭代次數更少。
3. XGBoost與GDBT都是逐次迭代來提升模型性能,可是XGBoost在選取最佳切分點時能夠開啓多線程進行,大大提升了運行速度。
XGBoost之切分點算法
上文介紹了XGBoost的算法原理並引出了衡量樹結構好壞的打分函數(目標函數),根據特徵切分點先後的打分函數選擇最佳切分點,但並未對節點的切分算法做詳細的介紹。本文詳細的介紹了XGBoost的切分點算法
目錄
-
並行原理
-
切分點算法之貪婪算法
-
切分點算法之分位點算法
-
切分點算法之權重分位點算法
-
稀疏數據的切分算法
-
總結
1. 並行原理
XGBoost是串行生成CART樹,可是XGBoost在處理特徵時能夠作到並行處理,XGBoost並行原理體如今最優切分點的選擇,假設樣本數據共M個特徵,對於某一輪CART樹的構建過程當中,選擇最佳切分點算法以下圖:
1. 紅色框表示根據每一個特徵大小對訓練數據進行排序,保存爲block結構,block個數與特徵數量相等。
2. 綠色寬表示對每一個block結構選擇最佳特徵切分點 ,節點切分標準是目標函數降低的程。
3. 黑色框表示比較每一個block結構的最佳特徵切分點的目標函數降低的增益,選擇最佳切分點。
2. 切分點算法之貪婪算法
每個block結構的切分點算法思路是相同的,所以,我重點介紹某一塊block結構的切分點算法。
XGBoost分位點算法:根據特徵對樣本數據進行排序,而後特徵從小到大進行切分,比較每次切分後的目標函數大小,選擇降低最大的節點做爲該特徵的最優切分點。最後比較不一樣block塊結構最優切分點的目標函數降低值,選擇降低最大的特徵做爲最優切分點。
流程圖以下:
【例】下表表示樣本的某一列特徵數值
根據特徵大小對樣本從新排序:
貪婪算法切分節點:
紅箭頭表示每一次的切分節點,選擇目標函數降低最大的點做爲切分節點。
3. 切分點算法之分位點算法
若特徵是連續值,按照上述的貪婪算法,運算量極大 。當樣本量足夠大的時候,使用特徵分位點來切分特徵。流程圖以下:
【例】下表表示樣本的某一列特徵數值,用三分位做爲切分節點 。
根據特徵大小進行樣本排序:
用特徵的三分位點做切分節點:
紅箭頭表示每一次的切分節點,選擇目標函數降低最大的點做爲切分節點。
4. 切分點算法之權重分位點算法
上節假設樣本權重相等,根據樣本的分位點來均分損失函數存在誤差,本節用樣本權重來均分損失函數。
損失函數以下:
對其變形獲得:
xi損失函數能夠看作是以以−gi/hi做爲label的均方偏差,乘以大小hi的權重,換句話說,xi對loss的貢獻權重爲hi ,構建樣本權重的分位點等於偏差的均分。
上節假設樣本權重相等,特徵值的分位點做爲切分點,本節假設樣本權重是hi,構建樣本權重的均分點步驟:
(1)根據特徵大小對樣本進行排序
(2)定義排序函數:
其中x,z表示特徵
(3)設置排序函數的分位點爲切分點
【例】以下圖
特徵與對應的排序函數值的關係,以下表:
紅色箭頭表示以三分位點做爲切分點。
最後,選擇最優切分點。
5. 稀疏數據的切分算法
稀疏數據在實際項目是很是常見,形成稀疏數據的緣由主要有:1. 數據缺失;2. 統計上的 0;3. one-hot編碼的特徵表示。
稀疏數據的切分點算法:
當出現特徵值缺失時,包含缺失特徵值的樣本被映射到默認的方向分支,而後計算該節點的最優切分點,最優切分點對應的默認切分方向就是特徵值缺失時默認的方向。
XGBoost參數調優小結
目錄
-
XGBoost算法原理簡單回顧
-
XGBoost的優勢
-
XGBoost的參數解釋
-
參數調優實例
-
小結
1. XGBoost算法原理簡單回顧
XGBoost算法的每顆樹都是對前一個模型損失函數的二階導展開式擬合,而後結合多棵樹給出分類或迴歸結果。所以咱們只要知道每棵樹的構建過程,就能很好的理解XGBoost的算法原理。
假設對於前t-1棵樹的預測結果爲,真實結果爲y,用L表示損失函數,那麼當前模型的損失函數爲:
XGBoost法構建樹的同時考慮了正則化,定義每棵樹的複雜度爲:
所以,包含正則化項的損失函數爲:
最小化(1.3)式獲得最終的目標函數:
目標函數也稱爲打分函數,它是衡量樹結構好壞的標準,值越小表明樹的結構越好。所以樹的節點切分規則是選擇樹目標函數值降低最大的點做爲切分點 。
以下圖,對於某一節點切分先後的目標函數之差記爲Gain。
選擇Gain降低最大的切分點對樹分裂,以此類推,獲得完整的樹 。
所以,只要知道(1.5)式的參數值就能基本肯定樹模型,其中表示左子節點損失函數的二階導之和,
表示右子節點損失函數的二階導之和,
表示左子節點損失函數的一階導之和,
表示右子節點損失函數的一階導之和 。
表示正則化係數,
表示切分節點難度,
和
定義了樹的複雜度。再簡單一點,咱們只要設置了損失函數L,正則化係數
和切分節點難度
,就基本肯定了樹模型 。XGBoost參數擇要重點考慮這三個參數 。
2. XGBoost的優勢
1. 正則化
XGBoost切分節點時考慮了正則化項(如圖1.3),減小了過擬合。實際上,XGBoost也稱爲「正則化提高」技術。
2. 並行處理
雖然XGBoost是串行迭代生成各決策樹,可是咱們在切分節點時能夠作到並行處理 ,所以XGBoost支持Hadoop實現 。
3. 高度靈活性
XGBoost支持自定義目標函數和評價函數,評價函數是衡量模型好壞的標準,目標函數是損失函數,如上節討論,只要知道了損失函數,而後求其一階導和二階導,就能肯定節點的切分規則。
4. 缺失值處理
XGBoost內置了處理缺失值的節點切分規則 。用戶須要提供一個和其餘樣本不同的值(如-999), 而後把該值做爲參數的缺失值 。
5. 內置交叉驗證
XGBoost容許每一輪迭代中使用交叉驗證,所以,能夠很方便的得到交叉驗證率,獲得最優boosting迭代次數 ,並不須要傳統的網格搜索法來獲取最優迭代次數 。
6. 在已有的模型基礎上繼續
XGBoost能夠從上一輪的結果上繼續訓練,從而節省了運行時間,經過設置模型參數「process_type」= update來實現 。
3. XGBoost參數解釋
XGBoost參數把全部的參數分爲三類:
1. 通用參數:控制了模型的宏觀功能 。
2. Booster參數:控制每一輪迭代的樹生成。
3. 學習目標參數:決定了學習場景,如損失函數和評價函數 。
3.1 通用參數
-
booster [default = gbtree]
供選擇的模型有gbtree和gblinear,gbtree使用基於樹的模型進行提高,gblinear使用線性模型進行提高,默認是gbtree 。這裏只介紹tree booster,由於它的表現遠遠賽過linear booster
-
silent [default = 0]
取0時表示打印運行信息,取1時表示不打印運行信息。
-
nthread
XGBoost運行時的線程數,默認是當前系統可運行的最大線程數。
-
num_pbuffer
預測數據的緩衝區大小,通常設置成訓練樣本個數的大小 。緩衝區保留最後一次迭代後的預測結果,系統自動設置。
-
num_feature
設置特徵維數來構建樹模型,系統自動設置 。
3.2 booster參數
-
eta [default = 0.3]
控制樹模型的權重,與AdaBoost算法的學習率(learning rate)含義相似,縮小權重以免模型處於過擬合,在對eta進行參數擇優時,須要與迭代次數(num_boosting_rounding)結合在一塊兒考慮 ,如減少學習率,那麼增長最大迭代次數;反之,則減少最大迭代次數 。
範圍:[0,1]
模型迭代公式:
其中表示前t棵樹結合模型的輸出結果,
表示第t棵樹模型,α表示學習率,控制模型更新的權重 。
-
gamma [default = 0]
控制模型切分節點的最小損失函數值,對應(1.5)式的γ,若γ設置的過大(1.5)式小於零,則不進行節點切分,所以下降了模型的複雜度。
-
lambda [default = 1]
表示L2正則化參數,對應(1.5)式中的λ,增大λ的值使模型更保守,避免過擬合 。
-
alpha [default = 0]
表示L1正則化參數,L1正則化的意義在於能夠降維,增大alpha值使模型更保守,避免過擬合
範圍:[0,∞]
-
max_depth [default=6]
表示樹的最大深度,增長樹的深度提升了樹的複雜度,頗有可能會致使過擬合,0表示對樹的最大深度無限制 。
範圍:[0,∞]
-
min_child_weight [default=1]
表示最小葉子節點的樣本權重和,和以前介紹的min_child_leaf參數有差異,min_child_weight表示樣本權重的和,min_child_leaf表示樣本總數和。
範圍:[0,∞]
-
subsample [default=1]
表示隨機採樣必定比例的樣原本構建每棵樹,減少比例參數subsample值,算法會更加保守,避免過擬合
範圍:[0,1]
-
colsample_bytree,colsample_bylevel,colsample_bynode
這個三個參數表示對特徵進行隨機抽樣,且具備累積效應 。
colsample_bytree,表示每棵樹劃分的特徵比重
colsample_bylevel,表示樹的每層劃分的特徵比重
colsample_bynode,表示樹的每一個節點劃分的特徵比重 。
好比,樣本共有64個特徵,設置{'colsample_bytree' : 0.5 , 'colsample_bylevel' : 0.5 , 'colsample_bynode' : 0.5 },那麼隨機採樣4個特徵應用於樹的每個節點切分 。
範圍:[0,1]
-
tree_method string [default = auto ]
表示樹的構建方法,確切來講是切分點的選擇算法,包括貪心算法,近似貪心算法,直方圖算法
exact:貪心算法
aprrox:近似貪心算法,選擇特徵的分位點進行切分
hist:直方圖切分算法,LightGBM算法也採用該切分算法 。
-
scale_pos_weight [default = 1]
當正負樣本不平衡時,設置該參數爲正值 ,能夠使算法更快收斂 。
典型的值可設置爲:(負樣本個數)/(正樣本個數)
-
process_type [default = default]
default:正常的構建提高樹過程
update: 從已有的模型構建提高樹
3.3 學習任務參數
根據任務和目的設置參數
objective,訓練目標,分類仍是迴歸
reg : linear,線性迴歸
reg : logistic,邏輯迴歸
binary : logistic,使用LR二分類,輸出機率
binary : logitraw,使用LR二分類,輸出Logistic轉換以前的分類得分 。
eval_metric,評價驗證集的指標,默認根據目標函數設置,默認狀況下,最小均方差用於迴歸,錯誤率用於分類,平均精確率用於排序 。
rmse:均方差
mae:平均絕對值偏差
error :錯誤率
logloss:負的對數損失
auc : roc曲線下的面積
seed [default=0]
隨機數種子,設置它能夠復現隨機數據結果 。
4. 參數調優實例
原始數據集和通過特徵工程處理後的數據集在開頭的連接部分進行下載,算法在jupter-notebook交互界面開發 。
定義模型評價函數,並根據必定的學習率獲得最優迭代次數 ,函數定義以下:
Step1:
根據經驗設置默認的參數,調用modelfit函數獲得最優迭代次數是198 。
Step2: 樹最大深度和最小葉子節點權重調優
根據第一步獲得的最優迭代次數更新模型參數n_estimators,而後調用model_selection類的GridSearchCV設置交叉驗證模型,最後調用XGBClassifier類的fit函數獲得最優樹的最大深度和最小葉子節點權重 。
a) 設置樹最大深度和最小葉子節點權重範圍:
b) GridSearchCV設置交叉驗證模型:
c) XGBClassfier類的fit函數更新參數:
Step3: gamma參數調優
Step4: subsample and colsample_bytree參數調優
Step5: 正則化參數調優
Step3,Step4和Step5參數調優思想Step2一致,這裏再也不展開,可參考代碼去理解 。
Step6: 減少學習率,增大對應的最大迭代次數 。參數調優思想與Step1一致,獲得最優的迭代次數 ,並輸出交叉驗證率結果。
迭代次數爲2346時,獲得最優分類結果(以下圖)。
5. XGBoost參數調優小結
XGBoost是一個高性能的學習模型算法,當你不知道怎麼對模型進行參數調優時,可參考上一節的步驟去進行參數調優 。本節根據上節的內容,以及本身的項目經驗闡述一下本人對XGBoost算法參數調優的一些理解,如有錯誤之處,還忘指正 。
(1)模型初始化 。在初始化模型參數時,咱們儘可能讓模型的複雜度較高,而後一步一步的經過參數調優來下降模型複雜度 。如上節初始化參數:葉子節點最小權重爲0,最大樹深度爲5,最小損失函數降低值爲0,這些參數初始化都是複雜化模型 。
(2) 學習率和最大迭代次數 。這兩個參數的調優必定是聯繫在一塊兒的,學習率越大,達到相同性能的模型所須要的最大迭代次數越小;學習率越小,達到相同性能的模型所須要的最大迭代次數越大 。XGBoost每一個參數的更新都須要進行屢次迭代,所以,學習率和最大迭代次數是首先須要考慮的參數 ,且學習率和最大迭代參數的重點不是提升模型的分類準確率,而是提升模型的泛化能力,所以,當模型的分類準確率很高時,咱們最後一步應減少學習率的大小,以提升模型的泛化能力 。
(3) 逐步下降模型複雜度 。樹的最大深度,葉子節點最小權重等參數都是影響模型複雜度的因素,這個看本身經驗,第四節的調參順序是:樹的最大深度和葉子節點最小權重->最小損失函數降低值->行採樣和列採樣->正則化參數 。實際項目中,我通常按照這個順序去調參 ,如有不一樣的理解,歡迎交流。
(4) 特徵工程:若模型的準確率在很低的範圍,那麼我建議先不用去調參了,去重點關注特徵和訓練數據。特徵和數據決定模型上限,模型只是逼近這個上限 。
LightGBM
提高樹是利用加法模型和前向分佈算法實現學習的優化過程,它有一些高效的實現,如GBDT,XGBoost和pGBRT,其中GBDT是經過損失函數的負梯度擬合殘差,XGBoost則是利用損失函數的二階導展開式擬合殘差。可是,當面對大量數據集和高維特徵時,其擴展性和效率很難使人滿意,最主要的緣由是對於每個特徵,它們須要掃描全部的樣本數據來得到最優切分點,這個過程是很是耗時的 。而基於GBDT的另外一種形式LightGBM基於直方圖的切分點算法,其很好的解決了這些問題
目錄
- 基於直方圖的切分點算法
- 直方圖算法改進
- 直方圖作差優化
- 樹的生長策略
- 支持類別特徵
- 支持高效並行
- 與XGBoost的對比
1. 基於直方圖的切分點算法
算法流程圖以下:
流程解釋:LightGBM經過直方圖算法把連續的特徵值離散化成對應的bin(能夠理解成桶),而後累加每一個bin對應特徵的梯度值並計數,最後遍歷全部特徵和數據,尋找最優切分點 。下面詳細解釋這一過程 。
1) 直方圖算法:
直方圖經過分段函數把連續值離散化成對應的bin。
如分段函數爲:
那麼,對於連續值≥0的特徵分紅四個桶,特徵的全部可能切分點個數降爲4,即bin的個數 ,所以大大加快了訓練速度。
直方圖每一個bin包含了兩類信息,分別是每一個bin樣本中的梯度之和與每一個bin中的樣本數量,對應於流程圖的表達式:
每一個bin累加的梯度包含了 一階梯度與二階梯度
2)切分點算法:
LightGBM和XGBoost的切分點算法思想是同樣的,比較切分後的增益與設定的最小增益的大小,若大於,則切分;反之,則不切分該節點。下面詳細敘述這一過程(該節代碼實現均在LightGBM/src/treelearner/feature_histogram.hpp):
(1)計算每一個葉子節點的輸出wj;
根據上面兩圖的代碼,可知lightGBM的葉子節點輸出與XGBoost相似,即:
其中,Gj爲葉子節點包含全部樣本的一階梯度之和,Hj爲二階梯度之和 。
(2)計算節點切分後的分數
葉子節點分數爲GetLeafSplitGainGivenOutput函數:
其中output表明葉子節點輸出Wj 。考慮通常狀況,假如葉子節點的樣本一階梯度和大於l1,那麼,葉子節點分數的表達式爲:
節點切分前的分數:
所以,計算節點切分增益:
節點切分增益= 節點分數 - (左葉子節點分數 + 右葉子節點分數)
比較切分增益與設置的最小增益大小,記爲Gain:
Gain = 節點切分增益 — 最小切分增益
最後獲得與XGBoost相似的形式,XGBoost爲以下形式:
LightGBM的最小切分增益對應於XGBoost的γ 。
2.直方圖算法改進
直方圖算法經過分段函數把連續值離散化成對應的bin的複雜度爲O(#feature×#data),若下降feature或data的大小,那麼直方圖算法的複雜度也相應的下降,微軟開源的LightGBM提供了兩個算法分別下降feature和data的大小:
1. GOSS(減小樣本角度):保留梯度較大的樣本數,減小梯度較小的樣本個數 。樣本訓練偏差小,表示該樣本獲得了很好的訓練,對應的梯度亦越小 。一種直接的想法是拋棄這些梯度較小的樣本,可是這種處理方法會改變樣本集的分佈,下降了訓練模型的準確率(由於丟棄的都是損失偏差較小的樣本) 。所以,咱們建議採用一種名爲GOSS的方法,即GOSS保留具備大梯度的樣本數,對梯度較小的樣本進行隨機採樣,爲了彌補數據集分佈改變的影響,GOSS對小梯度的樣本數增長了權重常數 。
GOSS僞代碼以下:
參考GOSS的解釋,僞代碼應該比較容易理解吧!
僞代碼中損失函數的梯度g表明的含義是一階梯度和二階梯度的乘積,見Github的實現( LightGBM/src/boosting/goss.hpp)。
2. EFB(從減小特徵角度):捆綁(bundling)互斥特徵,用一個特徵代替多個互斥特徵,達到減小特徵個數的目的 。EFB算法須要解決兩個問題,(1)捆綁互斥特徵,(2)合併互斥特徵 。這裏就不詳細介紹了。
3. 直方圖作差優化
一個葉子節點的直方圖能夠由父親節點的直方圖與它兄弟的直方圖作差獲得 。利用這個方法,LightGBM能夠用父親節點的直方圖減去數據量比較小的葉子節點直方圖,獲得數據量比較大的葉子節點直方圖,由於該直方圖是作差獲得的,時間複雜度僅爲O(#bins),比起不作差獲得的兄弟節點的直方圖,速度上能夠提高一倍。
直方圖作差示意圖以下:
4. 樹的生長策略
XGBoost是按層生長(level-wise)的方式展開節點,優勢是不容易過擬合,缺點是它對每一層葉子節點不加區分的進行展開,實際上某些葉子節點的分裂增益較低,不必進行搜索和分裂。以下圖所示:
LightGBM是按最大增益的節點(葉子明智,Leaf-wise)進行展開,這樣作的好處是找到分裂增益最大的葉子節點進行分裂,如此循環 。優勢是效率高,在分裂次數相同的狀況下,Leaf-wise能夠獲得更高的準確率 。缺點是可能會產生過擬合,經過設置樹的最大生長深度避免 。以下圖所示:
5. 支持類別特徵
類別特徵在實際項目中比較常見,XGBoost經過one-hot編碼把類別特徵轉化爲多維特徵,下降了算法運行效率,LightGBM優化了類別特徵的支持,不須要對類別特徵進行one-hot編碼 。
6. 支持高效並行
LightGBM支持特徵並行和數據並行 。
特徵並行:在不一樣機器選擇局部不一樣特徵對應的最優切分點,而後同步各機器結果,選擇最優切分點 。以下圖:
LightGBM對特徵並行進行了優化,經過在本地保存所有數據避免對數據切分結果的通訊 。
數據並行:不一樣機器在本地構造直方圖,而後進行全局的合併,最後在合併的直方圖上尋找最優分割點。以下圖:
LightGBM有下面兩種優化數據並行的方法:
(1)LightGBM經過"Reduce Scatter"將把直方圖合併的任務分攤到不一樣的機器,下降通訊和計算,並利用直方圖作差,進一步減小了一半的通訊量 。
(2)LightGBM經過「PV-Tree」的算法進行投票並行(Voting Parallel),使通訊開銷變成常數級別,在數據量很大的時候,使用投票並行能夠獲得很是好的加速效果。以下圖:
7. 與XGBoost的對比
LightGBM相對於XGboost具備更快的訓練效率和更低的內存使用,以下對比圖:
LightGBM內存開銷下降到原來的1/8倍 ,在Expo數據集上速度快了8倍和在Higg數據集上加速了40%,
LightGBM原理之論文詳解
【Abstract】
Gradient Boosting Decision Tree (GBDT)很是流行卻鮮有實現,只有像XGBoost和pGBRT。當特徵維度較高和數據量巨大的時候,其實現中仍然存在效率和可擴展性的問題。一個主要緣由就是對於每個特徵的每個分裂點,都須要遍歷所有數據計算信息增益,這一過程很是耗時。針對這一問題,本文提出兩種新方法:Gradient-based One-Side Sampling (GOSS) 和Exclusive Feature Bundling (EFB)(基於梯度的one-side採樣和互斥的特徵捆綁)。在GOSS中,咱們排除了重要的比例-具備小梯度的實例,只用剩下的來估計信息增益,咱們證實,這些梯度大的實例在計算信息增益中扮演重要角色,GOSS能夠用更小的數據量對信息增益進行至關準確的估計。對於EFB,咱們捆綁互斥的特徵(什麼是互斥特徵:例如特徵間不多同時非零。),來下降特徵的個數。咱們證實完美地捆綁互斥特徵是NP難的,但貪心算法可以實現至關好的逼近率,所以咱們可以在不損害分割點準確率許多,有效減小特徵的數量。(犧牲一點分割準確率下降特徵數量),這一算法命名爲LightGBM。在多個公共數據集實驗證實,LightGBM加速了傳統GBDT訓練過程20倍以上,同時達到了幾乎相同的精度 。
1. Introduction
GBDT由於其的有效性、準確性、可解釋性,成爲了普遍使用的機器學習算法。GBDT在許多機器學習任務上取得了最好的效果( state-of-the-art),例如多分類,點擊預測,排序。但最近幾年隨着大數據的爆發(特徵量和數據量),GBDT面臨平衡準確率和效率的調整。
GBDT缺點:對於每個特徵的每個分裂點,都須要遍歷所有數據來計算信息增益。所以,其計算複雜度將受到特徵數量和數據量雙重影響,形成處理大數據時十分耗時。
解決這個問題的直接方法就是減小特徵量和數據量並且不影響精確度,有部分工做根據數據權重採樣來加速boosting的過程,但因爲gbdt沒有樣本權重不能應用。而本文提出兩種新方法實現此目標。
Gradient-based One-Side Sampling (GOSS):GBDT雖然沒有數據權重,但每一個數據實例有不一樣的梯度,根據計算信息增益的定義,梯度大的實例對信息增益有更大的影響,所以在下采樣時,咱們應該儘可能保留梯度大的樣本(預先設定閾值,或者最高百分位間),隨機去掉梯度小的樣本。咱們證實此措施在相同的採樣率下比隨機採樣得到更準確的結果,尤爲是在信息增益範圍較大時。
Exclusive Feature Bundling (EFB):一般在真實應用中,雖然特徵量比較多,可是因爲特徵空間十分稀疏,是否能夠設計一種無損的方法來減小有效特徵呢?特別在稀疏特徵空間上,許多特徵幾乎是互斥的(例如許多特徵不會同時爲非零值,像one-hot),咱們能夠捆綁互斥的特徵。最後,咱們將捆綁問題歸約到圖着色問題,經過貪心算法求得近似解。
2. Preliminaries
2.1 GBDT and Its Complexity Analysis
GBDT是一種集成模型的決策樹,順序訓練決策樹。每次迭代中,GBDT經過擬合負梯度(殘差)來學到決策樹。
學習決策樹是GBDT主要的時間花銷,而學習決策樹中找到最優切分點最消耗時間。普遍採用的預排序算法來找到最優切分點,這種方法會列舉預排序中全部可能的切分點。這種算法雖然可以找到最優的切分點,但對於訓練速度和內存消耗上都效率低。另外一種流行算法是直方圖算法(histogram-based algorithm)。直方圖算法並不經過特徵排序找到最優的切分點,而是將連續的特徵值抽象成離散的分箱,並使用這些分箱在訓練過程當中構建特徵直方圖,這種算法更加訓練速度和內存消耗上都更加高效,lightGBM使用此種算法。
histogram-based算法經過直方圖尋找最優切分點,其建直方圖消耗O(#data * #feature),尋找最優切分點消耗O(#bin * # feature),而#bin的數量遠小於#data,因此建直方圖爲主要時間消耗。若是可以減小數據量或特徵量,那麼還可以夠加速GBDT的訓練。
2.2 Related Work
GBDT有許多實現,如XGBoost,PGBRT,Scikit-learn,gbm in R。Scikit-learn和gbm in R實現都用了預排序,pGBRT使用了直方圖算法,XGBoost支持預排序和直方圖算法,因爲XGBoost賽過其餘算法,咱們用它做爲baseline。
爲了減少訓練數據集,一般作法是下采樣。例如過濾掉權重小於閾值的數據。SGB每次迭代中用隨機子集訓練弱學習器。或者採樣率基於訓練過程動態調整。除了基於AdaBoost的SGB不能直接應用於GBDT,由於GBDT中沒有原始的權重。雖然SGB也能間接應用於GBDT,但每每會影響精度。
一樣,過濾掉弱特徵(什麼是弱特徵)來減小特徵量。一般用主成分分析或者投影法。固然,這些方法依賴於一個假設-特徵包含高度的冗餘,但實際中每每不是。(設計特徵來自於其獨特的貢獻,移除任一維度均可以某種程度上影響精度)。
實際中大規模的數據集一般都是很是稀疏的,使用預排序算法的GBDT可以經過無視爲0的特徵來下降訓練時間消耗。而後直方圖算法沒有優化稀疏的方案。由於直方圖算法不管特徵值是否爲0,都須要爲每一個數據檢索特徵區間值。若是基於直方圖的GBDT可以有效利用稀疏特徵將是最優。
下圖是兩個算法的對比:
3. Gradient-based One-Side Sampling
GOSS是一種在減小數據量和保證精度上平衡的算法。
3.1 Algorithm Description
AdaBoost中,樣本權重是數據實例重要性的指標。然而在GBDT中沒有原始樣本權重,不能應用權重採樣。幸運的事,咱們觀察到GBDT中每一個數據都有不一樣的梯度值,對採樣十分有用,即實例的梯度小,實例訓練偏差也就較小,已經被學習得很好了,直接想法就是丟掉這部分梯度小的數據。然而這樣作會改變數據的分佈,將會影響訓練的模型的精確度,爲了不此問題,咱們提出了GOSS。
GOSS保留全部的梯度較大的實例,在梯度小的實例上使用隨機採樣。爲了抵消對數據分佈的影響,計算信息增益的時候,GOSS對小梯度的數據引入常量乘數。GOSS首先根據數據的梯度絕對值排序,選取top a個實例。而後在剩餘的數據中隨機採樣b個實例。接着計算信息增益時爲採樣出的小梯度數據乘以(1-a)/b,這樣算法就會更關注訓練不足的實例,而不會過多改變原數據集的分佈。
3.2 Theoretical Analysis
GBDT使用決策樹,來學習得到一個將輸入空間映射到梯度空間的函數。假設訓練集有n個實例x1,...,xn,特徵維度爲s。每次梯度迭代時,模型數據變量的損失函數的負梯度方向爲g1,...,gn,決策樹經過最優切分點(最大信息增益點)將數據分到各個節點。GBDT經過分割後的方差衡量信息增益。
定義3.1:O表示某個固定節點的訓練集,分割特徵 j 的分割點d定義爲:
其中,
遍歷每一個特徵分裂點 j,找到
對應最大的分裂節點,並計算最大的信息增益。而後,將數據根據特徵
的分裂點
將數據分到左右節點。
在GOSS中,
-
1. 首先根據數據的梯度將訓練降序排序。
-
2. 保留top a個數據實例,做爲數據子集A。
-
3. 對於剩下的數據的實例,隨機採樣得到大小爲b的數據子集B。
-
4. 最後咱們經過如下方程估計信息增益:
-
此處GOSS經過較小的數據集估計信息增益,將大大地減少計算量。更重要的是,咱們接下來理論代表GOSS不會丟失許多訓練精度,賽過(outperform)隨機採樣。理論的證實再附加材料。
Theorem 3.2 咱們定義GOSS近似偏差爲:,且
,
機率至少是1−δ,有:
其中:
根據理論3.2,咱們得出如下結論:
1. GOSS的漸進逼近比率是:
若是數據分割不是極不平衡,好比:
且
近似偏差主要由第二項主導,當n趨於無窮(數據量很大)時,
趨於0。即數據量越大,偏差越小,精度越高。
2. 隨機採樣是GOSS在a=0的一種狀況。多數狀況下,GOSS性能優於隨機採樣,即如下狀況:
即:
其中,
下面分析GOSS的泛化性。考慮GOSS泛化偏差:
這是GOSS抽樣的的實例計算出的方差增益與實際樣本方差增益之間的差距。
變換爲:
所以,在GOSS準確的狀況下,GOSS泛化偏差近似於全數據量的真實數據。另外一方面,採樣將增長基學習器的多樣性(由於每次採樣得到的數據可能會不一樣),這將提升泛化性。
4. Exclusive Feature Bundling
這一章介紹如何有效減小特徵的數量
高維的數據一般是稀疏的,這種稀疏性啓發咱們設計一種無損地方法來減小特徵的維度。特別的,稀疏特徵空間中,許多特徵是互斥的,例如他們從不一樣時爲非零值。咱們能夠綁定互斥的特徵爲單一特徵,經過仔細設計特徵搜尋算法,咱們從特徵捆綁中構建了與單個特徵相同的特徵直方圖。這種方式的間直方圖時間複雜度從O(#data * #feature)降到O(#data * #bundle),因爲#bundle << # feature,咱們可以極大地加速GBDT的訓練過程並且損失精度。
有兩個問題:
-
1. 怎麼斷定那些特徵應該綁在一塊兒(build bundled)?
-
2. 怎麼把特徵綁爲一個(merge feature)?
4.1 bundle(什麼樣的特徵被綁定)?
**理論 4.1:**將特徵分割爲較小量的互斥特徵羣是NP難的。
證實:將圖着色問題歸約爲此問題,而圖着色是NP難的,因此此問題就是NP難的。
給定圖着色實例G=(V, E)。以G的關聯矩陣的每一行爲特徵,獲得咱們問題的一個實例有|V|個特徵。 很容易看到,在咱們的問題中,一個獨特的特徵包與一組具備相同顏色的頂點相對應,反之亦然。
理論4.1說明多項式時間中求解這個NP難問題不可行。爲了尋找好的近似算法,咱們將最優捆綁問題歸結爲圖着色問題,若是兩個特徵之間不是相互排斥,那麼咱們用一個邊將他們鏈接,而後用合理的貪婪算法(具備恆定的近似比)用於圖着色來作特徵捆綁。 此外,咱們注意到一般有不少特徵,儘管不是100%相互排斥的,也不多同時取非零值。 若是咱們的算法能夠容許一小部分的衝突,咱們能夠獲得更少的特徵包,進一步提升計算效率。通過簡單的計算,隨機污染小部分特徵值將影響精度最多爲:
γ是每一個綁定中的最大沖突比率,當其相對較小時,可以完成精度和效率之間的平衡。
**算法3:**基於上面的討論,咱們設計了算法3,僞代碼見下圖,具體算法:
-
1.創建一個圖,每一個點表明特徵,每一個邊有權重,其權重和特徵之間整體衝突相關。
-
2. 按照降序排列圖中的度數來排序特徵。
-
3. 檢查排序以後的每一個特徵,對他進行特徵綁定或者創建新的綁定使得操做以後的整體衝突最小。
算法3的時間複雜度是O(#feature^2),訓練以前只處理一次,其時間複雜度在特徵不是特別多的狀況下是能夠接受的,但難以應對百萬維的特徵。爲了繼續提升效率,咱們提出了一個更加高效的無圖的排序策略:將特徵按照非零值個數排序,這和使用圖節點的度排序類似,由於更多的非零值一般會致使衝突,新算法在算法3基礎上改變了排序策略。
4.2 merging features(特徵合併)
如何合併同一個bundle的特徵來下降訓練時間複雜度。關鍵在於原始特徵值能夠從bundle中區分出來。鑑於直方圖算法存儲離散值而不是連續特徵值,咱們經過將互斥特徵放在不一樣的箱中來構建bundle。這能夠經過將偏移量添加到特徵原始值中實現,例如,假設bundle中有兩個特徵,原始特徵A取值[0, 10],B取值[0, 20]。咱們添加偏移量10到B中,所以B取值[10, 30]。經過這種作法,就能夠安全地將A、B特徵合併,使用一個取值[0, 30]的特徵取代AB。算法見算法4,
EFB算法可以將許多互斥的特徵變爲低維稠密的特徵,就可以有效的避免沒必要要0值特徵的計算。實際,經過用表記錄數據中的非零值,來忽略零值特徵,達到優化基礎的直方圖算法。經過掃描表中的數據,建直方圖的時間複雜度將從O(#data)降到O(#non_zero_data)。固然,這種方法在構建樹過程當中須要而額外的內存和計算開銷來維持預特徵表。咱們在lightGBM中將此優化做爲基本函數,由於當bundles是稀疏的時候,這個優化與EFB不衝突(能夠用於EFB)。
5. Experiments
這部分主要寫了lightGBM的實驗結果,主要用了五個公開數據集,以下
微軟的排序數據集(LETOR)包括30K的網頁搜索,數據集幾乎都是稠密的數值特徵。
Allstate是保險和航空延誤數據都包含了大量的one-hot特徵。
後兩個是KDD CUP2010和KDD CPU2012數據集,使用了冠軍解決方案中的特徵,其中包含了稀疏和稠密的特徵,而且這兩個數據集特別大。
這些數據集都比較大,並且包含了稀疏和稠密的特徵,涵蓋了不少真實的業務,所以它們可以徹底地測試lightGBM的性能。
5.1 Overall Comparison
XGBoost和lightGBM without GOSS 和EFB(lgb baseline),做爲比較的基準。XGBoost使用了兩個版本:xgb_exa(預排序)和xgb_his(直方圖算法)。對於xgb_exa作了參數調整,使XGBoost長成和其餘算法類似的樹。而且調整參數在速度和準確率間平衡。對於Allstate、KDD10 和 KDD2012,設置a = 0.05 , b = 0.05 ,對於航空延誤和LETOR,咱們設置a = 0.1 , b = 0.1 ,數據集EFB咱們設置γ = 0 。全部的算法有固定迭代次數。在必定迭代次數內,咱們取最高的分數。
下表是訓練時間對比(時間是每次迭代的平均時間)
下表是精確度對比,分類使用AUC評價,排序使用NDCG評價。
下圖是飛行延時和LETOR的訓練曲線。
5.2 Analysis on GOSS
**速度上:**GOSS具備加速訓練的能力,表2中能夠看出GOSS幾乎加速了兩倍。雖然GOSS用了10%-20%的數據訓練,可是因爲有一些額外的計算,因此加速並不和數據量成反比,可是GOSS仍然極大加速了訓練。
**精度上:**從表4中能夠看出,一樣採樣率,GOSS精度總比SGB好。
5.3 Analysis on EFB
表2代表,EFB在大數據集上可以極大加速訓練。由於EFB合併大量的稀疏特徵到低維稠密的特徵,而且因爲以前的孤立的特徵被bundle到一塊兒,能可以極大提升緩存的命中率,所以,它所有的效率提升是動態的。
綜上這些分析,EFB是改進直方圖算法稀疏性的很是高效的算法,可以極大地加速GBDT訓練。
6. Conclusion
本文提出了新穎的GBDT算法–LightGBM,它包含了連個新穎的技術:Gradient-based One-Side Sampling (GOSS) 和Exclusive Feature Bundling (EFB)(基於梯度的one-side採樣和互斥的特徵捆綁)來處理大數據量和高維特徵的場景。咱們在理論分析和實驗研究代表,GOSS和EFB使得LightGBM在計算速度和內存消耗上明顯優於XGBoost和SGB。
將來,咱們將研究優化如何在GOSS中選擇a,b。繼續提升EFB在高維特徵上的性能,不管其是不是稀疏的。
LightGBM介紹及參數調優
一、LightGBM簡介
LightGBM是一個梯度Boosting框架,使用基於決策樹的學習算法。它能夠說是分佈式的,高效的,有如下優點:
1)更快的訓練效率
2)低內存使用
3)更高的準確率
4)支持並行化學習
5)能夠處理大規模數據
與常見的機器學習算法對比,速度是很是快的
二、XGboost的缺點
在討論LightGBM時,不可避免的會提到XGboost,關於XGboost能夠參考此博文
關於XGboost的不足之處主要有:
1)每輪迭代時,都須要遍歷整個訓練數據屢次。若是把整個訓練數據裝進內存則會限制訓練數據的大小;若是不裝進內存,反覆地讀寫訓練數據又會消耗很是大的時間。
2)預排序方法的時間和空間的消耗都很大
三、LightGBM原理
1)直方圖算法
直方圖算法的基本思想是先把連續的浮點特徵值離散化成k個整數,同時構造一個寬度爲k的直方圖。在遍歷數據的時候,根據離散化後的值做爲索引在直方圖中累積統計量,當遍歷一次數據後,直方圖累積了須要的統計量,而後根據直方圖的離散值,遍歷尋找最優的分割點。
使用直方圖算法有不少優勢。首先,最明顯就是內存消耗的下降,直方圖算法不只不須要額外存儲預排序的結果,並且能夠只保存特徵離散化後的值,而這個值通常用8位整型存儲就足夠了,內存消耗能夠下降爲原來的1/8。
而後在計算上的代價也大幅下降,預排序算法每遍歷一個特徵值就須要計算一次分裂的增益,而直方圖算法只須要計算k次(k能夠認爲是常數),時間複雜度從O(#data * #feature) 優化到O(k* #features)。
固然,Histogram算法並非完美的。因爲特徵被離散化後,找到的並非很精確的分割點,因此會對結果產生影響。但在不一樣的數據集上的結果代表,離散化的分割點對最終的精度影響並非很大,甚至有時候會更好一點。緣由是決策樹原本就是弱模型,分割點是否是精確並非過重要;較粗的分割點也有正則化的效果,能夠有效地防止過擬合;即便單棵樹的訓練偏差比精確分割的算法稍大,但在梯度提高(Gradient Boosting)的框架下沒有太大的影響。
2)LightGBM的直方圖作差加速
一個容易觀察到的現象:一個葉子的直方圖能夠由它的父親節點的直方圖與它兄弟的直方圖作差獲得。一般構造直方圖,須要遍歷該葉子上的全部數據,但直方圖作差僅需遍歷直方圖的k個桶。利用這個方法,LightGBM能夠在構造一個葉子的直方圖後,能夠用很是微小的代價獲得它兄弟葉子的直方圖,在速度上能夠提高一倍。
3)帶深度限制的Leaf-wise的葉子生長策略
Level-wise過一次數據能夠同時分裂同一層的葉子,容易進行多線程優化,也好控制模型複雜度,不容易過擬合。但實際上Level-wise是一種低效的算法,由於它不加區分的對待同一層的葉子,帶來了不少不必的開銷,由於實際上不少葉子的分裂增益較低,不必進行搜索和分裂。
Leaf-wise則是一種更爲高效的策略,每次從當前全部葉子中,找到分裂增益最大的一個葉子,而後分裂,如此循環。所以同Level-wise相比,在分裂次數相同的狀況下,Leaf-wise能夠下降更多的偏差,獲得更好的精度。Leaf-wise的缺點是可能會長出比較深的決策樹,產生過擬合。所以LightGBM在Leaf-wise之上增長了一個最大深度的限制,在保證高效率的同時防止過擬合。
4)直接支持類別特徵(即不須要作one-hot編碼)
實際上大多數機器學習工具都沒法直接支持類別特徵,通常須要把類別特徵,轉化到多維的one-hot編碼特徵,下降了空間和時間的效率。而類別特徵的使用是在實踐中很經常使用的。基於這個考慮,LightGBM優化了對類別特徵的支持,能夠直接輸入類別特徵,不須要額外的one-hot編碼展開。並在決策樹算法上增長了類別特徵的決策規則。在Expo數據集上的實驗,相比0/1展開的方法,訓練速度能夠加速8倍,而且精度一致。
5)直接支持高效並行
LightGBM還具備支持高效並行的優勢。LightGBM原生支持並行學習,目前支持特徵並行和數據並行的兩種。
特徵並行的主要思想是在不一樣機器在不一樣的特徵集合上分別尋找最優的分割點,而後在機器間同步最優的分割點。
數據並行則是讓不一樣的機器先在本地構造直方圖,而後進行全局的合併,最後在合併的直方圖上面尋找最優分割點。
LightGBM針對這兩種並行方法都作了優化,在特徵並行算法中,經過在本地保存所有數據避免對數據切分結果的通訊;在數據並行中使用分散規約 (Reduce scatter) 把直方圖合併的任務分攤到不一樣的機器,下降通訊和計算,並利用直方圖作差,進一步減小了一半的通訊量。
四、LightGBM參數調優
下面幾張表爲重要參數的含義和如何應用
接下來是調參
下表對應了Faster Spread,better accuracy,over-fitting三種目的時,能夠調整的參數
CatBoost
CatBoost是俄羅斯的搜索巨頭Yandex在2017年開源的機器學習庫,是Gradient Boosting(梯度提高) + Categorical Features(類別型特徵),也是基於梯度提高決策樹的機器學習框架。
1、CatBoost技術介紹
1,類別型特徵的處理
CatBoost採用了一種有效的策略,下降過擬合的同時也保證了所有數據集均可用於學習。也就是對數據集進行隨機排列,計算相同類別值的樣本的平均標籤值時,只是將這個樣本以前的樣本的標籤值歸入計算。
2,特徵組合
爲當前樹構造新的分割點時,CatBoost會採用貪婪的策略考慮組合。對於樹的第一次分割,不考慮任何組合。對於下一個分割,CatBoost將當前樹的全部組合、類別型特徵與數據集中的全部類別型特徵相結合。組合被動態地轉換爲數字。CatBoost還經過如下方式生成數值型特徵和類別型特徵的組合:樹選擇的全部分割點都被視爲具備兩個值的類別型特徵,而且組合方式和類別型特徵同樣。
3,克服梯度誤差
CatBoost,和全部標準梯度提高算法同樣,都是經過構建新樹來擬合當前模型的梯度。然而,全部經典的提高算法都存在由有偏的點態梯度估計引發的過擬合問題。許多利用GBDT技術的算法(例如,XGBoost、LightGBM),構建一棵樹分爲兩個階段:選擇樹結構和在樹結構固定後計算葉子節點的值。爲了選擇最佳的樹結構,算法經過枚舉不一樣的分割,用這些分割構建樹,對獲得的葉子節點中計算值,而後對獲得的樹計算評分,最後選擇最佳的分割。兩個階段葉子節點的值都是被當作梯度[8]或牛頓步長的近似值來計算。CatBoost第一階段採用梯度步長的無偏估計,第二階段使用傳統的GBDT方案執行。
4,快速評分
CatBoost使用oblivious樹做爲基本預測器,這種樹是平衡的,不太容易過擬合。oblivious樹中,每一個葉子節點的索引能夠被編碼爲長度等於樹深度的二進制向量。CatBoost首先將全部浮點特徵、統計信息和獨熱編碼特徵進行二值化,而後使用二進制特徵來計算模型預測值。
5基於GPU實現快速學習
5.1 密集的數值特徵
任何GBDT算法,對於密集的數值特徵數據集來講,搜索最佳分割是創建決策樹時的主要計算負擔。CatBoost利用oblivious決策樹做爲基礎模型,並將特徵離散化到固定數量的箱子中以減小內存使用。就GPU內存使用而言,CatBoost至少與LightGBM同樣有效。主要改進之處就是利用了一種不依賴於原子操做的直方圖計算方法。
5.2 類別型特徵
CatBoost使用完美哈希來存儲類別特徵的值,以減小內存使用。因爲GPU內存的限制,在CPU RAM中存儲按位壓縮的完美哈希,以及要求的數據流、重疊計算和內存等操做。經過哈希來分組觀察。在每一個組中,咱們須要計算一些統計量的前綴和。該統計量的計算使用分段掃描GPU圖元實現。
5.3 多GPU支持
CatBoost中的GPU實現可支持多個GPU。分佈式樹學習能夠經過數據或特徵進行並行化。CatBoost採用多個學習數據集排列的計算方案,在訓練期間計算分類特徵的統計數據。
2、CatBoost的優勢
性能卓越:在性能方面能夠匹敵任何先進的機器學習算法;
魯棒性/強健性:它減小了對不少超參數調優的需求,並下降了過分擬合的機會,這也使得模型變得更加具備通用性;
易於使用:提供與scikit集成的Python接口,以及R和命令行界面;
實用:能夠處理類別型、數值型特徵;可擴展:支持自定義損失函數;
誰是數據競賽王者?CatBoost vs. Light GBM vs. XGBoost
最近我參加了一個Kaggle比賽(斯坦福大學的WIDS Datathon),依靠各類boosting算法,我最後擠進了前十名。雖然成績很好,但從那以後我就對模型集成學習的細節感到十分好奇:那些模型是怎麼組合的?參數怎麼調整?它們各自的優勢和缺點又是什麼?
考慮到本身曾經用過許多boosting算法,我決定寫一篇文章來重點分析XGBoost、LGBM和CatBoost的綜合表現。雖然最近神經網絡很流行,但就我我的的觀點來看,boosting算法在訓練數據有限時更好用,訓練時間更短,調參所需的專業知識也較少。
XGBoost是陳天奇於2014年提出的一種算法,被稱爲GBM Killer,由於介紹它的文章有不少,因此本文會在介紹CatBoost和LGBM上用更大的篇幅。如下是咱們將要討論的幾個主題:
-
結構差別
-
處理分類變量
-
參數簡介
-
數據集實現
-
算法性能
LightGBM和XGBoost的結構差別
雖然LightGBM和XGBoost都是基於決策樹的boosting算法,但它們之間存在很是顯著的結構差別。
LGBM採用leaf-wise生長策略,也就是基於梯度的單側採樣(GOSS)來找出用於分裂的數據實例,當增加到相同的葉子節點時,LGBM會直接找出分裂增益最大的葉子(一般是數據最大坨的那個),只分裂一個。
LightGBM
而XGBoost採用的則是level(depth)-wise生長策略,它用預排序算法+直方圖算法爲每一層的葉子找出最佳分裂,簡而言之,就是它是不加區分地分裂同一層全部葉子。
XGBoost
咱們先來看看預排序算法(pre-sorted)的工做方式:
-
對每一個葉子(分割點)遍歷全部特徵;
-
對每一個特徵,按特徵值對數據點進行排序;
-
肯定當前特徵的基本分裂增益,用線性掃描決定最佳分裂方法;
-
基於全部特徵採起最佳分裂方法。
而直方圖算法的工做方式則是根據當前特徵把全部數據點分割稱離散區域,而後利用這些區域查找直方圖的分割值。雖然比起預排序算法那種在排序好的特徵值上枚舉全部可能的分割點的作法,直方圖算法的效率更高,但它在速度上仍是落後於GOSS。
那麼爲何GOSS這麼高效呢?
這裏咱們須要提到經典的AdaBoost。在AdaBoost中,數據點的權重是數據點重要與否的一個直觀指標,但梯度提高決策樹(GBDT)不自帶這種權重,所以也就沒法沿用AdaBoost的採樣方法。
基於梯度的採樣:梯度指的是損失函數切線的斜率,因此從邏輯上說,若是一些數據點的梯度很大,那它們對於找到最佳分裂方法來講就很重要,由於它們具備較高的偏差。
GOSS保留了全部具備大梯度的數據點,並對梯度小的數據點進行隨機採樣。例如,假設我有50萬行數據,其中1萬行梯度高,剩下的49萬行梯度低,那個人算法就會選擇1萬行+49萬行×x%(隨機)。設x=10,最終算法選出的就是50萬行數據中的5.9萬行。
這裏存在一個基本假設,即梯度較小的數據點具備更低的偏差,並且已經訓練好了
爲了保持相同的數據分佈,在計算分裂增益時,GOSS會爲這些梯度小的數據點引入一個常數乘數。以上就是它能在減小數據點數量和保證決策樹準確性之間取得平衡的方法。
處理分類變量
CatBoost
CatBoost在分類變量索引方面具備至關的靈活性,它能夠用在各類統計上的分類特徵和數值特徵的組合將分類值編碼成數字(one_hot_max_size
:若是feature包含的不一樣值的數目超過了指定值,將feature轉化爲float)。
若是你沒有在cat_features
語句中傳遞任何內容,CatBoost會把全部列視爲數值變量。
注:若是在
cat_features
中未提供具備字符串值的列,CatBoost會報錯。此外,具備默認int類型的列在默認狀況下也會被視爲數字,因此你要提早手動定義。
對於分類值大於one_hot_max_size
的那些分類變量,CatBoost也有一種有效的方法。它和均值編碼相似,但能夠防止過擬合:
-
對輸入樣本從新排序,並生成多個隨機排列;
-
將label值從浮點或類別轉換爲整型;
-
用如下公式把全部分類特徵值轉換爲數值,其中CountInClass表示截至當前樣本,label值=1的次數(相一樣本總數);Prior表示平滑因子,它由起始參數肯定;而TotalCount則表明截至當前樣本,全部樣本的總數。
若是轉換爲數學公式,它長這樣:
LightGBM
和CatBoost相似,LightGBM也能夠經過輸入特徵名稱來處理分類特徵。它無需進行獨熱編碼(one-hot coding),而是使用一種特殊的算法直接查找分類特徵的拆分值,最後不只效果類似,並且速度更快。
注:在爲LGBM構造數據集以前,應將分類特徵轉換爲整型數據,即使你用了categorical_feature參數,算法也沒法識別字符串值。
XGBoost
XGBoost沒法單獨處理分類特徵,它是基於CART的,因此只接收數值。在把分類數據提供給算法前,咱們先得執行各類編碼,如標籤編碼、均值編碼、獨熱編碼等。
類似的超參數
這三種算法涉及的超參數有不少,這裏咱們只介紹幾個重要的。下表是它們的對比:
數據集實現
我使用的是2015年航班延誤的Kaggle數據集,由於它同時包含分類特徵和數字特徵,並且大約有500萬行數據,不管是從訓練速度上看仍是從模型的準確率上看,它均可以做爲一個很好的性能判斷工具。
我從數據集中抽取10%(50萬行)做爲實驗數據,如下是建模使用的特徵:
-
MONTH,DAY,DAYOFWEEK:整型數據
-
AIRLINE和FLIGHT_NUMBER:整型數據
-
ORIGINAIRPORT和DESTINATIONAIRPORT:字符串
-
DEPARTURE_TIME:float
-
ARRIVAL_DELAY:預測目標,航班延遲是否超過10分鐘?
-
DISTANCE和AIR_TIME:float
-
import pandas as pd, numpy as np, time
-
from sklearn.model_selection import train_test_split
-
data = pd.read_csv("flights.csv")
-
data = data.sample(frac = 0.1, random_state=10)
-
data = data[["MONTH","DAY","DAY_OF_WEEK","AIRLINE","FLIGHT_NUMBER","DESTINATION_AIRPORT",
-
"ORIGIN_AIRPORT","AIR_TIME", "DEPARTURE_TIME","DISTANCE","ARRIVAL_DELAY"]]
-
data.dropna(inplace=True)
-
data["ARRIVAL_DELAY"] = (data["ARRIVAL_DELAY"]>10)*1
-
cols = [ "AIRLINE","FLIGHT_NUMBER","DESTINATION_AIRPORT","ORIGIN_AIRPORT"]
-
for item in cols:
-
data[item] = data[item].astype("category").cat.codes +1
-
train, test, y_train, y_test = train_test_split( data.drop(["ARRIVAL_DELAY"], axis=1), data["ARRIVAL_DELAY"],
-
random_state= 10, test_size=0.25)
XGBoost
-
import xgboost as xgb
-
from sklearn import metrics
-
def auc(m, train, test):
-
return (metrics.roc_auc_score(y_train,m.predict_proba(train)[:,1]),
-
metrics.roc_auc_score(y_test,m.predict_proba(test)[:, 1]))
-
# Parameter Tuning
-
model = xgb.XGBClassifier()
-
param_dist = { "max_depth": [10,30,50],
-
"min_child_weight" : [1,3,6],
-
"n_estimators": [200],
-
"learning_rate": [0.05, 0.1,0.16],}
-
grid_search = GridSearchCV(model, param_grid=param_dist, cv = 3,
-
verbose= 10, n_jobs=-1)
-
grid_search.fit(train, y_train)
-
grid_search.best_estimator_
-
model = xgb.XGBClassifier(max_depth= 50, min_child_weight=1, n_estimators=200,\
-
n_jobs= -1 , verbose=1,learning_rate=0.16)
-
model.fit(train,y_train)
-
auc(model, train, test)
Light GBM
-
import lightgbm as lgb
-
from sklearn import metrics
-
def auc2(m, train, test):
-
return (metrics.roc_auc_score(y_train,m.predict(train)),
-
metrics.roc_auc_score(y_test,m.predict(test)))
-
lg = lgb.LGBMClassifier(silent= False)
-
param_dist = { "max_depth": [25,50, 75],
-
"learning_rate" : [0.01,0.05,0.1],
-
"num_leaves": [300,900,1200],
-
"n_estimators": [200]
-
}
-
grid_search = GridSearchCV(lg, n_jobs= -1, param_grid=param_dist, cv = 3, scoring="roc_auc", verbose=5)
-
grid_search.fit(train,y_train)
-
grid_search.best_estimator_
-
d_train = lgb.Dataset(train, label=y_train)
-
params = { "max_depth": 50, "learning_rate" : 0.1, "num_leaves": 900, "n_estimators": 300}
-
# Without Categorical Features
-
model2 = lgb.train(params, d_train)
-
auc2(model2, train, test)
-
#With Catgeorical Features
-
cate_features_name = [ "MONTH","DAY","DAY_OF_WEEK","AIRLINE","DESTINATION_AIRPORT",
-
"ORIGIN_AIRPORT"]
-
model2 = lgb.train(params, d_train, categorical_feature = cate_features_name)
-
auc2(model2, train, test)
CatBoost
在爲CatBoost調參時,我發現它很難爲分類特徵傳遞索引。因此我針對沒傳遞的特徵調整了參數,最後有了兩個模型:一個包含分類特徵,一個不包含。由於onehotmax_size不影響其餘參數,因此我單獨對它作了調整。
-
import catboost as cb
-
cat_features_index = [ 0,1,2,3,4,5,6]
-
def auc(m, train, test):
-
return (metrics.roc_auc_score(y_train,m.predict_proba(train)[:,1]),
-
metrics.roc_auc_score(y_test,m.predict_proba(test)[:, 1]))
-
params = { 'depth': [4, 7, 10],
-
'learning_rate' : [0.03, 0.1, 0.15],
-
'l2_leaf_reg': [1,4,9],
-
'iterations': [300]}
-
cb = cb.CatBoostClassifier()
-
cb_model = GridSearchCV(cb, params, scoring= "roc_auc", cv = 3)
-
cb_model.fit(train, y_train)
-
With Categorical features
-
clf = cb.CatBoostClassifier(eval_metric= "AUC", depth=10, iterations= 500, l2_leaf_reg= 9, learning_rate= 0.15)
-
clf.fit(train,y_train)
-
auc(clf, train, test)
-
With Categorical features
-
clf = cb.CatBoostClassifier(eval_metric= "AUC",one_hot_max_size=31, \
-
depth= 10, iterations= 500, l2_leaf_reg= 9, learning_rate= 0.15)
-
clf.fit(train,y_train, cat_features= cat_features_index)
-
auc(clf, train, test)
結果
如今咱們就能從訓練速度和準確率兩個維度對3種算法進行評價了。
如上表所示,CatBoost在測試集上的準確率高達0.816,同時過擬合程度最低,訓練時長短,預測時間也最少。但它真的戰勝其餘兩種算髮了嗎?很惋惜,沒有。0.816這個準確率的前提是咱們考慮了分類變量,並且單獨調整了onehotmax_size。若是沒有充分利用算法的特性,CatBoost的表現是最差的,準確率只有0.752。
因此咱們能夠得出這樣一個結論:若是數據中存在分類變量,咱們能夠充分利用CatBoost的特性獲得一個更好的訓練結果。
接着就是咱們的數據競賽王者XGBoost。它的表現很穩定,若是忽略以前的數據轉換工做,單從準確率上看它和CatBoost很是接近。可是XGBoost的缺點是太慢了,尤爲是調參過程,簡直使人絕望(我花了6小時擺弄GridSearchCV)。
最後就是Light GBM,這裏我想提一點,就是用cat_features時它的速度和準確率會很是糟糕,我猜想這多是由於這時算法會在分類數據中用某種改良過的均值編碼,以後就過擬合了。若是咱們能像XGBoost同樣操做,它也許能夠在速度秒殺XGBoost的同時達到後者的精度。
綜上所述,這些觀察結果都是對應這個數據集得出的結論,它們可能不適用於其餘數據集。我在文中沒有展現交叉驗證過程,但我確實嘗試了,結果差很少。話雖如此,但有一個結果是千真萬確的:XGBoost確實比其餘兩種算法更慢。
-
import numpy as np
-
from catboost import CatBoostClassifier,CatBoostRegressor,Pool
-
-
-
#####¥##################分類#################################
-
train_data=np.random.randint( 0,100,size=(100,10))
-
train_label=np.random.randint( 0,2,size=(100))
-
test_data=np.random.randint( 0,100,size=(50,10))
-
model=CatBoostClassifier(iterations= 2,depth=2,learning_rate=1,loss_function='Logloss', logging_level='Verbose')
-
model.fit(train_data,train_label,cat_features=[ 0,2,5])
-
preds_class=model.predict(test_data)
-
preds_proba=model.predict_proba(test_data)
-
print( "class=",preds_class)
-
print( "proba=",preds_proba)
-
-
-
#####¥##################迴歸#################################
-
train_data = np.random.randint( 0, 100, size=(100, 10))
-
train_label = np.random.randint( 0, 1000, size=(100))
-
test_data = np.random.randint( 0, 100, size=(50, 10))
-
# initialize Pool
-
train_pool = Pool(train_data, train_label, cat_features=[ 0,2,5])
-
test_pool = Pool(test_data, cat_features=[ 0,2,5])
-
-
# specify the training parameters
-
model = CatBoostRegressor(iterations= 2, depth=2, learning_rate=1, loss_function='RMSE')
-
#train the model
-
model.fit(train_pool)
-
# make the prediction using the resulting model
-
preds = model.predict(test_pool)
-
print(preds)