入門 | 從結構到性能,一文概述XGBoost、Light GBM和CatBoost的同與不同

2021-02-19 機器之心

儘管近年來神經網絡復興並大為流行,但是 boosting 算法在訓練樣本量有限、所需訓練時間較短、缺乏調參知識等場景依然有其不可或缺的優勢。本文從算法結構差異、每個算法的分類變量時的處理、算法在數據集上的實現等多個方面對 3 種代表性的 boosting 算法 CatBoost、Light GBM 和 XGBoost 進行了對比;雖然本文結論依據於特定的數據集,但通常情況下,XGBoost 都比另外兩個算法慢。

最近,我參加了 kaggle 競賽 WIDS Datathon,並通過使用多種 boosting 算法,最終排名前十。從那時開始,我就對這些算法的內在工作原理非常好奇,包括調參及其優劣勢,所以有了這篇文章。儘管最近幾年神經網絡復興,並變得流行起來,但我還是更加關注 boosting 算法,因為在訓練樣本量有限、所需訓練時間較短、缺乏調參知識的場景中,它們依然擁有絕對優勢。

2014 年 3 月,XGBOOST 最早作為研究項目,由陳天奇提出

2017 年 1 月,微軟發布首個穩定版 LightGBM

2017 年 4 月,俄羅斯頂尖技術公司 Yandex 開源 CatBoost

由於 XGBoost(通常被稱為 GBM 殺手)已經在機器學習領域出現了很久,如今有非常多詳細論述它的文章,所以本文將重點討論 CatBoost 和 LGBM,在下文我們將談到:

算法結構差異

每個算法的分類變量時的處理

如何理解參數

算法在數據集上的實現

每個算法的表現

LightGBM 和 XGBoost 的結構差異

在過濾數據樣例尋找分割值時,LightGBM 使用的是全新的技術:基於梯度的單邊採樣(GOSS);而 XGBoost 則通過預分類算法和直方圖算法來確定最優分割。這裡的樣例(instance)表示觀測值/樣本。

首先讓我們理解預分類算法如何工作:

簡單說,直方圖算法在某個特徵上將所有數據點劃分到離散區域,並通過使用這些離散區域來確定直方圖的分割值。雖然在計算速度上,和需要在預分類特徵值上遍歷所有可能的分割點的預分類算法相比,直方圖算法的效率更高,但和 GOSS 算法相比,其速度仍然更慢。

為什麼 GOSS 方法如此高效?

在 Adaboost 中,樣本權重是展示樣本重要性的很好的指標。但在梯度提升決策樹(GBDT)中,並沒有天然的樣本權重,因此 Adaboost 所使用的採樣方法在這裡就不能直接使用了,這時我們就需要基於梯度的採樣方法。

梯度表徵損失函數切線的傾斜程度,所以自然推理到,如果在某些意義上數據點的梯度非常大,那麼這些樣本對於求解最優分割點而言就非常重要,因為算其損失更高。

GOSS 保留所有的大梯度樣例,並在小梯度樣例上採取隨機抽樣。比如,假如有 50 萬行數據,其中 1 萬行數據的梯度較大,那麼我的算法就會選擇(這 1 萬行梯度很大的數據+x% 從剩餘 49 萬行中隨機抽取的結果)。如果 x 取 10%,那麼最後選取的結果就是通過確定分割值得到的,從 50 萬行中抽取的 5.9 萬行。

在這裡有一個基本假設:如果訓練集中的訓練樣例梯度很小,那麼算法在這個訓練集上的訓練誤差就會很小,因為訓練已經完成了。

為了使用相同的數據分布,在計算信息增益時,GOSS 在小梯度數據樣例上引入一個常數因子。因此,GOSS 在減少數據樣例數量與保持已學習決策樹的準確度之間取得了很好的平衡。

高梯度/誤差的葉子,用於 LGBM 中的進一步增長

每個模型是如何處理屬性分類變量的?

CatBoost

CatBoost 可賦予分類變量指標,進而通過獨熱最大量得到獨熱編碼形式的結果(獨熱最大量:在所有特徵上,對小於等於某個給定參數值的不同的數使用獨熱編碼)。

如果在 CatBoost 語句中沒有設置「跳過」,CatBoost 就會將所有列當作數值變量處理。

注意,如果某一列數據中包含字符串值,CatBoost 算法就會拋出錯誤。另外,帶有默認值的 int 型變量也會默認被當成數值數據處理。在 CatBoost 中,必須對變量進行聲明,才可以讓算法將其作為分類變量處理。

對於可取值的數量比獨熱最大量還要大的分類變量,CatBoost 使用了一個非常有效的編碼方法,這種方法和均值編碼類似,但可以降低過擬合情況。它的具體實現方法如下:

1. 將輸入樣本集隨機排序,並生成多組隨機排列的情況。

2. 將浮點型或屬性值標記轉化為整數。

3. 將所有的分類特徵值結果都根據以下公式,轉化為數值結果。

其中 CountInClass 表示在當前分類特徵值中,有多少樣本的標記值是「1」;Prior 是分子的初始值,根據初始參數確定。TotalCount 是在所有樣本中(包含當前樣本),和當前樣本具有相同的分類特徵值的樣本數量。

可以用下面的數學公式表示:

LightGBM

和 CatBoost 類似,LighGBM 也可以通過使用特徵名稱的輸入來處理屬性數據;它沒有對數據進行獨熱編碼,因此速度比獨熱編碼快得多。LGBM 使用了一個特殊的算法來確定屬性特徵的分割值。

注意,在建立適用於 LGBM 的數據集之前,需要將分類變量轉化為整型變量;此算法不允許將字符串數據傳給分類變量參數。

XGBoost

和 CatBoost 以及 LGBM 算法不同,XGBoost 本身無法處理分類變量,而是像隨機森林一樣,只接受數值數據。因此在將分類數據傳入 XGBoost 之前,必須通過各種編碼方式:例如標記編碼、均值編碼或獨熱編碼對數據進行處理。

超參數中的相似性

所有的這些模型都需要調節大量參數,但我們只談論其中重要的。以下是將不同算法中的重要參數按照功能進行整理的表格。

實現

在這裡,我使用了 2015 年航班延誤的 Kaggle 數據集,其中同時包含分類變量和數值變量。這個數據集中一共有約 500 萬條記錄,因此很適合用來同時評估比較三種 boosting 算法的訓練速度和準確度。我使用了 10% 的數據:50 萬行記錄。

以下是建模使用的特徵:

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]))


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}


model2 = lgb.train(params, d_train)
auc2(model2, train, test)


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 調參時,很難對分類特徵賦予指標。因此,我同時給出了不傳遞分類特徵時的調參結果,並評估了兩個模型:一個包含分類特徵,另一個不包含。我單獨調整了獨熱最大量,因為它並不會影響其他參數。

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)

結語

為了評估模型,我們應該同時考慮模型的速度和準確度表現。

請記住,CatBoost 在測試集上表現得最好,測試集的準確度最高(0.816)、過擬合程度最小(在訓練集和測試集上的準確度很接近)以及最小的預測和調試時間。但這個表現僅僅在有分類特徵,而且調節了獨熱最大量時才會出現。如果不利用 CatBoost 算法在這些特徵上的優勢,它的表現效果就會變成最差的:僅有 0.752 的準確度。因此我們認為,只有在數據中包含分類變量,同時我們適當地調節了這些變量時,CatBoost 才會表現很好。

第二個使用的是 XGBoost,它的表現也相當不錯。即使不考慮數據集包含有轉換成數值變量之後能使用的分類變量,它的準確率也和 CatBoost 非常接近了。但是,XGBoost 唯一的問題是:它太慢了。尤其是對它進行調參,非常令人崩潰(我用了 6 個小時來運行 GridSearchCV——太糟糕了)。更好的選擇是分別調參,而不是使用 GridSearchCV。

最後一個模型是 LightGBM,這裡需要注意的一點是,在使用 CatBoost 特徵時,LightGBM 在訓練速度和準確度上的表現都非常差。我認為這是因為它在分類數據中使用了一些修正的均值編碼方法,進而導致了過擬合(訓練集準確率非常高:0.999,尤其是和測試集準確率相比之下)。但如果我們像使用 XGBoost 一樣正常使用 LightGBM,它會比 XGBoost 更快地獲得相似的準確度,如果不是更高的話(LGBM—0.785, XGBoost—0.789)。

最後必須指出,這些結論在這個特定的數據集下成立,在其他數據集中,它們可能正確,也可能並不正確。但在大多數情況下,XGBoost 都比另外兩個算法慢。

所以,你更喜歡哪個算法呢?

原文地址:https://towardsdatascience.com/catboost-vs-light-gbm-vs-xgboost-5f93620723db

本文為機器之心編譯,轉載請聯繫本公眾號獲得授權

✄---

加入機器之心(全職記者/實習生):hr@jiqizhixin.com

投稿或尋求報導:editor@jiqizhixin.com

廣告&商務合作:bd@jiqizhixin.com

相關焦點

  • 從結構到性能,一文概述XGBoost、Light GBM和CatBoost的同與不同
    本文從算法結構差異、每個算法的分類變量時的處理、算法在數據集上的實現等多個方面對 3 種代表性的 boosting 算法 CatBoost、Light GBM 和 XGBoost 進行了對比;雖然本文結論依據於特定的數據集,但通常情況下,XGBoost 都比另外兩個算法慢。
  • 大戰三回合:XGBoost、LightGBM和Catboost一決高低
    Battle 中,根據訓練和預測的時間、預測得分和可解釋性等評測指標,讓三個算法一決高下!但在大訓練樣本和高維度特徵的數據環境下,GBDT 算法的性能以及準確性卻面臨了極大的挑戰,隨後,2017 年 LightGBM 應勢而生,由微軟開源的一個機器學習框架;同年,俄羅斯的搜索巨頭 Yandex 開源 Catboost 框架。
  • 機器學習實戰|GBDT Xgboost LightGBM對比
    XGBoost加入了更多的剪枝策略和正則項,控制過擬合風險。傳統的GBDT用的是CART,Xgboost能支持的分類器更多,也可以是線性的。GBDT只用了一階導,但是xgboost對損失函數做了二階的泰勒展開,並且還可以自定義損失函數。
  • 【機器學習】XGBoost算法學習小結
    XGBoost概述    xgboost 是"極端梯度上升"(Extreme Gradient Boosting)的簡稱,是一種現在在數據科學競賽的獲勝方案很流行的算法,它的流行源於在著名的Kaggle數據科學競賽上被稱為"奧託分類"的挑戰。由於
  • 聊聊lightgbm
    算法偽代碼如下從第一層到最後一層,都需要計算每個特徵的直方圖和標籤的直方圖,進而選擇最優的直方圖分割。這種做法相對而言,計算複雜度低,所需存儲較少。容易看出,構建直方圖的複雜度跟樣本量和特徵個數的乘積同階,尋找最優分割的複雜度跟分箱數和特徵數的乘積同階。
  • 深入理解LightGBM
    我們還得先從xgboost說起談起Lightgbm, 我們已經知道了是xgboost的強化版本, 關於xgboost,從其工作原理到數學推導再到優化策略最後到實戰應用,【白話機器學習】算法理論+實戰之Xgboost算法都已經描述過了,這裡只進行簡單的回憶和梳理,在這次回憶中我們看看xgboost在某些策略上是不是依然存在一些問題?
  • 聊聊CatBoost
    在GBDT中,構建下一棵樹包含兩步,即選擇樹的結構以及樹結構固定之後設置葉子節點的值。在CatBoost中,對於每個樣本Sample,都單獨構建一個利用該樣本之前的樣本點的梯度估計得到的模型Model,針對這些模型Model,估計該樣本Sample的梯度,然後利用新模型Model_new重新對樣本Sample打分。算法偽代碼示例如下:
  • python金融風控評分卡模型和數據分析
    針對銀行,消費金融的現金貸等線上貸款場景,金融信貸領域建模型和數據分析很難?邏輯回歸評分卡/catboost/xgboost/lightgbm/等模型用python一次全部搞定!由易到難,帶你從菜鳥輕鬆晉級kaggle級建模高手。
  • 深入理解CatBoost
    Catboost還使用了組合類別特徵,可以利用到特徵之間的聯繫,這極大的豐富了特徵維度。採用排序提升的方法對抗訓練集中的噪聲點,從而避免梯度估計的偏差,進而解決預測偏移的問題。2.第三,考慮使用categorical features的不同組合。例如顏色和種類組合起來,可以構成類似於blue dog這樣的特徵。當需要組合的categorical features變多時,CatBoost只考慮一部分combinations。在選擇第一個節點時,只考慮選擇一個特徵,例如A。在生成第二個節點時,考慮A和任意一個categorical feature的組合,選擇其中最好的。
  • 從零解讀 Xgboost 算法 (原理+代碼)
    文中涉及到的公式和註解都可以左右滑動查看全部,涉及到的代碼去這裡下載:https://github.com/DA-southampton/NLP_ability全文目錄如下:0.提升樹1. xgboost原理解讀1.0 學習路徑:1.1
  • Python XGBoost算法代碼實現和篩選特徵應用
    XGBoost算法的步驟和GB基本相同,都是首先初始化為一個常數,gb是根據一階導數ri,xgboost是根據一階導數gi和二階導數hi,迭代生成基學習器,相加更新學習器。—可以通過booster [default=gbtree]設置參數:gbtree: tree-based models/gblinear: linear models2.傳統GBDT在優化時只用到一階導數信息,xgboost則對代價函數進行了二階泰勒展開,同時用到了一階和二階導數。
  • 資源 | XGBoost 中文文檔開放:上去就是一把梭
    中文文檔地址:http://xgboost.apachecn.org/cn/latest/英文文檔地址:http://xgboost.apachecn.org/en/latest/中文文檔 GitHub 地址:https://github.com/apachecn/xgboost-doc-zh梯度提升樹已經在實踐中證明可以有效地用於分類和回歸任務的預測挖掘
  • CatBoost:專治類別型特徵的Boosting算法
    4.1 建立新樹的基本思想CatBoost 建模過程與其他 GBDT 算法一樣分為兩個階段:選擇樹結構 和在樹結構固定後計算葉子節點的值 。每一輪循環的輸出結果都是一個樹結構 和更新後的模型 。
  • 資料|陳天奇介紹Xgboost原理的PPT
    from=leiphonecolumn_res0929【 圖片來源:https://xgboost.apachecn.org/所有者:https://xgboost.apachecn.org/ 】內容簡介陳天奇介紹Xgboost原理的PPT,用於學習xgboost原理。XGBoost是一個優化的分布式梯度增強庫,旨在實現高效,靈活和便攜。
  • 劍指LightGBM和XGboost!斯坦福發表NGBoost算法
    該算法利用自然梯度將不確定性估計引入到梯度增強中。本文試圖了解這個新算法,並與其他流行的 boosting 算法 LightGBM 和 XGboost 進行比較,以了解它在實踐中是如何工作的。lightgbm as lgb import xgboost as xgb from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error
  • 我的XGBoost學習經歷及動手實踐
    最終,將這些技術進行結合來做一個端到端的系統以最少的集群系統來擴展到更大的數據集上。XGBoost原理介紹從0開始學習,經歷過推導公式的波瀾曲折,下面展示下我自己的推公式的手稿吧,希望能激勵到大家能夠對機器學習數據挖掘更加熱愛!
  • 第113天: Python XGBoost 算法項目實戰
    XGBoost 算法說到XGBoost,不得不提GBDT(Gradient Boosting Decision Tree)。因為XGBoost本質上還是一個GBDT,但是力爭把速度和效率發揮到極致,所以叫X (Extreme) GBoosted。
  • 2小時入門Spark之MLlib
    眾所周知,目前工業界應用最主流的機器學習模型是xgboost,lightgbm,以及深度學習那一套。遺憾的是,MLlib原生並不帶xgboost和lightgbm,對深度學習的支持也不多。但MLlib提供非常豐富的基礎模型諸如決策樹,隨機森林,梯度提升樹,樸素貝葉斯等,這些簡單易用的模型可以提供一個基本的baseline。
  • 技術詳解 | catboost完全指南(下)
    接上篇——技術詳解 | catboost完全指南(中),介紹了catboost的基學習器、模型、模型的學習、樹的生成、分裂查找算法,以及一些重要改進後,今天繼續往下。這裡舉個例子詳細解釋一下,catboost的ordered boosint type在一些地方被稱為引入了online learning的思路,啥意思呢,假設我們要計算x5的負梯度,則我們使用x1,x2,x3,x4訓練一棵樹
  • 【機器學習基礎】xgboost系列丨xgboost建樹過程分析及代碼實現
    ,其餘樣本劃分到了右側。<<  左右滑動查看更多  >>import xgboost as xgbmodel = xgb.XGBClassifier(n_estimators=2,max_depth=3,learning_rate=0.1,random_state=1,reg_lambda=1,gamma=0,objective='binary:logistic