數學推導+純Python實現機器學習算法18:LightGBM

2021-02-25 機器學習實驗室

Python機器學習算法實現

Author:louwill

Machine Learning Lab

     

    第17講我們談到了競賽大殺器XGBoost,本篇我們來看一種比XGBoost還要犀利的Boosting算法——LightGBM。LightGBM全稱為輕量的梯度提升機(Light Gradient Boosting Machine),由微軟於2017年開源出來的一款SOTA Boosting算法框架。跟XGBoost一樣,LightGBM也是GBDT算法框架的一種工程實現,不過更加快速和高效。

XGBoost可優化的地方

    XGBoost通過預排序的算法來尋找特徵的最佳分裂點,雖然預排序算法能夠準確的找出特徵的分裂點,但該方法佔用空間的代價太大,在數據量和特徵量都比較多的情況下,會嚴重影響算法性能。XGBoost尋找最佳分裂點的算法複雜度可以估計為:

複雜度=特徵數量*特徵分裂點的數量*樣本數量

    既然XGBoost的複雜度是由特徵數量、特徵分裂點的數量和樣本數量所決定的,那麼LightGBM的優化空間自然是從這三個角度來考慮。LightGBM總體上仍然屬於GBDT算法框架,關於GBDT算法特徵我們已經在第15篇的時候重點敘述過,這裡不再重複。我們重點梳理上述三個優化角度的基本原理即可。

Histogram算法

    為了減少特徵分裂點的數量和更加高效尋找最佳特徵分裂點,LightGBM區別於XGBoost的預排序算法,採用Histogram直方圖的算法尋找最佳特徵分裂點。其基本想法是將連續的浮點特徵值進行離散化為k個整數並構造一個寬度為k的直方圖。對某個特徵數據進行遍歷的時候,將離散化後的值用為索引作為直方圖的累積統計量。遍歷完一次後,直方圖便可累積對應的統計量,然後根據該直方圖尋找最佳分裂點。直方圖算法如下圖所示。

    直方圖算法並不什麼特別的創新之舉,本質上就是一種數據離散化和分箱操作,但架不住速度快性能優,計算代價和內存佔用都大大減少。

    直方圖另外一個好處在於差加速。一個葉子節點的直方圖可由其父節點的直方圖與其兄弟節點的直方圖做差得到,這也可以加速特徵節點分裂。

    所以,從特徵尋找最優分裂點角度,LightGBM使用了直方圖算法進行優化。完整的直方圖算法流程如下偽代碼所示:

GOSS算法

    GOSS全稱為單邊梯度抽樣算法(Gradient-based One-Side Sampling),是LightGBM從減少樣本角度進行優化還設計的算法,算是LightGBM的核心原理之一。單邊梯度抽樣算法的主要思路是從減少樣本的角度出發,將訓練過程中大部分權重較小的樣本剔除,僅對剩餘樣本數據計算信息增益。

    第16講我們談到了Adaboost算法,該算法的一個關鍵要素就是樣本權重,通過在訓練過程不斷調整樣本分類權重而達到最優分類效果的過程。但在GBDT系列中並沒有樣本權重的相關設計,GBDT採用樣本梯度來代替權重的概念。一般來說,訓練梯度小的樣本,其經驗誤差也相對較小,說明這部分數據已經獲得了較好的訓練,GBDT的想法就是再一下的殘差擬合中丟棄掉這部分樣本,但這樣做可能會改變訓練樣本的數據分布,對最終的訓練精度有影響。

    針對以上問題,LightGBM提出採用GOSS採樣算法。其目的就是最大效率的保留對計算信息增益有幫助的樣本,提高模型訓練速度。GOSS的基本做法是先將需要進行分裂的特徵按絕對值大小降序排序,取絕對值最大的前a%個數據,假設樣本大小為n,在剩下的(1-a)%個數據中隨機選擇b%個數據,將這b%個數據乘以一個常數(1-a)/b,這種做法會使得算法更加關注訓練不夠充分的樣本,並且原始的數據分布不會有太大改變。最後使用a+b個數據來計算該特徵的信息增益。GOSS算法流程偽代碼如下所示。

    GOSS算法主要是從減少樣本的角度來對GBDT進行優化的。丟棄梯度較小的樣本並且在不損失太多精度的情況下提升模型訓練速度,這使得LightGBM速度較快的原因之一。

EFB算法

    直方圖算法對應於特徵分裂點的優化、單邊梯度抽樣對應於樣本量的優化,最後還剩下特徵數量的優化沒有談到。而EFB算法就是針對於特徵的優化。EFB算法全稱為互斥特徵捆綁算法(Exclusive Feature Bundling),通過將兩個互斥的特徵捆綁在一起,合為一個特徵,在不丟失特徵信息的前提下,減少特徵數量,從而加速模型訓練。大多數時候兩個特徵都不是完全互斥的,可以用定義一個衝突比率對特徵不互斥程度進行衡量,當衝突比率較小時,可以將不完全互斥的兩個特徵捆綁,對最後的模型精度也沒有太大影響。

    所謂特徵互斥,即兩個特徵不會同時為非零值,這一點跟分類特徵的one-hot表達有點類似。互斥特徵捆綁算法的關鍵問題有兩個,一個是如何判斷將哪些特徵進行綁定,另外一個就是如何將特徵進行綁定,即綁定後的特徵如何進行取值的問題。

    針對第一個問題,EFB算法將其轉化為圖著色(Graph Coloring Problem)的問題來求解。其基本思路是將所有特徵看作為圖的各個頂點,用一條邊連接不相互獨立的兩個特徵,邊的權重則表示為兩個相連接的特徵的衝突比例,需要綁定在一起的特徵就是圖著色問題中要塗上同一種顏色的點(特徵)。基於圖著色問題的EFB求解算法偽代碼如下:

    第二個問題是要確定綁定後的特徵如何進行取值,其關鍵在於能夠將原始的特徵從合併後的特徵中進行分離,也就是說綁定到一個特徵後,我們仍然可以在這個綁定的bundle裡面識別出原始特徵。EFB算法針對該問題嘗試從直方圖的角度來處理,具體做法是將不同特徵值分到綁定的bundle中不同的直方圖箱子中,通過在特徵取值中加一個偏置常量來進行處理。舉個簡單的例子,假設我們要綁定特徵A和特徵B兩個特徵,特徵A的取值區間為[10,20),特徵B的取值範圍為[10,30),我們可以給特徵B的取值範圍加一個偏置量10,則特徵B的取值範圍變成了[20,40),綁定後的特徵取值範圍變成了[10,40),這樣特徵A和特徵B即可進行愉快的融合了。特徵合併算法偽代碼如下所示:

    以上三個算法就是LightGBM在XGBoost基礎上,針對特徵分裂點、樣本數量和特徵數量分別做出的優化處理方法。

Leaf-Wise

    除了Histogram、GOSS和EFB算法之外,LightGBM還提出了區別於XGBoost的按層生長的葉子節點生長方法,即帶有深度限制的按葉子節點生長(Leaf-Wise)的決策樹生成算法。具體如下圖所示:

    XGBoost採用按層生長的Level-Wise算法,好處是可以多線程優化,也方便控制模型複雜度,且不易過擬合。但缺點是不加區分的對待同一層所有葉子節點,大部分的節點分裂和增益計算不是必須的,帶來了多餘的計算開銷。LightGBM提出了按葉子節點生長的Leaf-Wise算法,精度更高且更有效率,能夠節約不必要的計算開銷,同時為防止某一節點過分生長而加上一個深度限制機制,能夠在保證精度的同時一定程度上防止過擬合。

    除了以上四點改進算法之外,LightGBM在工程實現上也有一些改進和優化。比如可以直接支持類別特徵(不需要再對類別特徵進行one-hot等處理)、高效並行和Cache命中率優化等。這裡不做詳述,讀者朋友們可以查找LightGBM原文研讀。

LightGBM實現

    從頭開始實現了一個完整的LightGBM算法是一個複雜的系統性工程,限於時間和精力,這裡筆者就不再進花時間手擼該算法。LightGBM開發團隊提供了該算法的完整實現,這使得我們能夠方便的進行調用。

    pip直接安裝即可:

    LightGBM提供了分類和回歸兩大類接口,下面以分類問題和iris數據集為例給出原生LightGBM接口的一個使用示例:

import pandas as pdimport lightgbm as lgbfrom sklearn.metrics import mean_squared_errorfrom sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom sklearn.datasets import make_classification
iris = load_iris()data = iris.datatarget = iris.targetX_train, X_test, y_train, y_test =train_test_split(data, target, test_size=0.2)
gbm = lgb.LGBMRegressor(objective='regression', num_leaves=31, learning_rate=0.05, n_estimators=20)gbm.fit(X_train, y_train,eval_set=[(X_test, y_test)],eval_metric='l1',early_stopping_rounds=5)y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration_)print(mean_squared_error(y_test, y_pred) ** 0.5)print(list(gbm.feature_importances_))

    下面給出一個LightGBM回歸模型五折交叉驗證訓練的代碼模板,僅供大家參考。

import timeimport numpy as npimport pandas as pdimport lightgbm as lgbfrom sklearn.model_selection import KFoldfrom sklearn.metrics import mean_squared_error
features = [f for f in df.columns if f not in [label]]
def evalerror(pred, df): label = df.get_label().values.copy() score = mean_squared_error(label, pred)*0.5 return ('mse', score, False)
params = { 'learning_rate': 0.01, 'boosting_type': 'gbdt', 'objective': 'regression', 'metric': 'mse', 'sub_feature': 0.7, 'num_leaves': 60, 'colsample_bytree': 0.7, 'feature_fraction': 0.7, 'min_data': 100, 'min_hessian': 1, 'verbose': -1,}
t0 = time.time()train_preds = np.zeros(train.shape[0])
kf = KFold(n_splits=5, shuffle=True, random_state=43)for i, (train_index, valid_index) in enumerate(kf.split(train)): print('train for {} epoch...'.format(i)) train2 = train.iloc[train_index] valid2 = train.iloc[valid_index] lgb_train = lgb.Dataset(train2[features], train2['total_cost'], categorical_feature=['hy', 'sex', 'pay_type']) lgb_valid = lgb.Dataset(valid2[features], valid2['total_cost'], categorical_feature=['hy', 'sex', 'pay_type']) model = lgb.train(params, lgb_train, num_boost_round=3000, valid_sets=lgb_valid, verbose_eval=300, feval=evalerror, early_stopping_rounds=100) feat_importance = pd.Series(model.feature_importance(), index=features).sort_values(ascending=False) train_preds[valid_index] += model.predict(valid2[features], num_iteration=model.best_iteration)
print('Validset score: {}'.format(mean_squared_error(labels, train_preds)*0.5))print('Cross Validation spend {} seconds'.format(time.time() - t0))

    以上就是本篇文章的主要內容。下一篇我們將關注另一種高效的Boosting框架——CatBoost。

參考資料:

LightGBM: A Highly Efficient Gradient BoostingDecision Tree

https://lightgbm.readthedocs.io/en/latest/

往期精彩:

數學推導+純Python實現機器學習算法27:LDA線性判別分析

一個算法工程師的成長之路

長按二維碼.關注機器學習實驗室

相關焦點

  • 數學推導+純Python實現機器學習算法:LightGBM
    LightGBM全稱為輕量的梯度提升機(Light Gradient Boosting Machine),由微軟於2017年開源出來的一款SOTA Boosting算法框架。跟XGBoost一樣,LightGBM也是GBDT算法框架的一種工程實現,不過更加快速和高效。
  • 數學推導+純Python實現機器學習算法30:系列總結與感悟
    實現機器學習算法3:k近鄰數學推導+純Python實現機器學習算法4:決策樹之ID3算法數學推導+純Python實現機器學習算法5:決策樹之CART算法數學推導+純Python實現機器學習算法6:感知機數學推導+純Python實現機器學習算法7:神經網絡數學推導+純Python實現機器學習算法
  • 數學推導+純Python實現機器學習算法12:貝葉斯網絡
    下面我們直接來用pgmpy實現上述貝葉斯網絡。https://github.com/luwill/machine-learning-code-writing參考資料:pgmpy: Probabilistic Graphical Models using Python數據挖掘導論往期精彩:數學推導
  • 【機器學習基礎】數學推導+純Python實現機器學習算法21:馬爾可夫鏈蒙特卡洛
    19:PCA降維數學推導+純Python實現機器學習算法18:奇異值分解SVD數學推導+純Python實現機器學習算法17:XGBoost數學推導+純Python實現機器學習算法16:Adaboost>數學推導+純Python實現機器學習算法15:GBDT數學推導+純Python實現機器學習算法14:Ridge嶺回歸數學推導+純Python實現機器學習算法13:Lasso回歸
  • 數學推導+純Python實現機器學習算法17:XGBoost
    Python機器學習算法實現Author:louwillMachine
  • 數學推導+純Python實現機器學習算法20:隨機森林
    Python機器學習算法實現Author:louwillMachine
  • 【機器學習基礎】數學推導+純Python實現機器學習算法12:貝葉斯網絡
    基於pgmpy的貝葉斯網絡實現     本節我們基於pgmpy來構造貝葉斯網絡和進行建模訓練。pgmpy是一款基於Python的概率圖模型包,主要包括貝葉斯網絡和馬爾可夫蒙特卡洛等常見概率圖模型的實現以及推斷方法。本節使用pgmpy包來實現簡單的貝葉斯網絡。
  • 數學推導+純Python實現機器學習算法28:奇異值分解SVD
    Python機器學習算法實現Author:louwillMachine
  • 【機器學習基礎】數學推導+純Python實現機器學習算法10:線性不可分支持向量機
    雖然凸優化問題可以直接求解,但當數據量很大時,直接求解將會非常低效,這時候可能需要一些高效的訓練算法,比如說SMO(序列最小最優化)算法。關於SMO算法的內容這裡不展開敘述,可參考統計學習方法了解更多內容。
  • 聊聊lightgbm
    LightGBM是一種高效的梯度提升決策樹,是由微軟聯合北京大學於2017年在機器學習頂級會議NIPS(Neural Information Processing
  • 深入理解LightGBM
    寫在前面如果想從事數據挖掘或者機器學習的工作,掌握常用的機器學習算法是非常有必要的,在這簡單的先捋一捋, 常見的機器學習算法:監督學習算法:邏輯回歸,線性回歸,決策樹,樸素貝葉斯,K近鄰,支持向量機,集成算法Adaboost等無監督算法:聚類,降維,關聯規則, PageRank等前面已經嘗試用最白話的語言完成了一個白話機器學習算法理論
  • lightGBM用於排序(Learning to Rank )
    所以打算想利用lightgbm進行排序,但網上關於lightgbm用於排序的代碼很少,關於回歸和分類的倒是一堆。這裡我將貼上python版的lightgbm用於排序的代碼,裡面將包括訓練、獲取葉結點、ndcg評估、預測以及特徵重要度等處理代碼,有需要的朋友可以參考一下或進行修改。
  • 【機器學習基礎】數學推導+純Python實現機器學習算法8-9:線性可分支持向量機和線性支持向量機
    第二步:線性可分支持向量機的簡單實現     這裡我們基採取和之前感知機模型一樣的優化思想來求解線性可分支持向量機的原始問題。完整代碼文件和數據可參考筆者GitHub地址:https://github.com/luwill/machine-learning-code-writing參考資料:https://pythonprogramming.net/https://github.com/SmirkCao/
  • python金融風控評分卡模型和數據分析
    《python信用評分卡建模(附代碼)》:360度講解python信用評分卡構建流程,附代碼和老師答疑。彌補網上信息參差不齊短板《python風控建模實戰lendingClub》此課程是針對集成樹模型,包括catboost,lightgbm,xgboost。這兩個課程算法原理是不同的。
  • 數學推導+純Python實現機器學習算法:Lasso回歸
    總的來說,監督機器學習的核心原理莫過於如下公式:該公式可謂是機器學習中最核心最關鍵最能概述監督學習的核心思想的公式了:所有的有監督機器學習,無非就是正則化參數的同時最小化經驗誤差函數。最小化經驗誤差是為了極大程度的擬合訓練數據,正則化參數是為了防止過分的擬合訓練數據。你看,多麼簡約數學哲學。
  • 【機器學習基礎】數學推導+純Python實現機器學習算法3:k近鄰
    ,k 近鄰在眾多有監督機器學習算法中算是一種比較獨特的方法。說它獨特,是因為 k 近鄰不像其他模型有損失函數、有優化算法、有訓練過程。對於給定的實例數據和實例數據對應所屬類別,當要對新的實例進行分類時,根據這個實例最近的 k 個實例所屬的類別來決定其屬於哪一類。所以相對於其它機器學習模型和算法,k 近鄰總體上而言是一種非常簡單的方法。
  • 如何使用python完成數學建模常見算法
    在數學建模中主流的程式語言是MATLAB,但隨著python/R中數學軟體包的不斷完善,熟悉這兩種程式語言的同學也可以快速數學建模的編程環節。後面我們將介紹幾種常見數學建模算法的python實現,旨在展示python在本領域的強大威力。
  • 機器學習算法推導&實現——k近鄰和kd樹實現
    KNN算法簡單、直觀,是最著名的「惰性學習」算法,不具有顯示的學習過程。K近鄰推導與kd樹過程我們可以用文字簡單描述下KNN算法:給定一個訓練數據集T,對於新的目標實例x,我們在訓練集T中找到與實例x最鄰近的k個實例,這k個實例大多屬於哪一類,目標實例x就被分為這個類。
  • 《深度學習》聖經花書的數學推導、原理與Python代碼實現
    MingchaoZhu同學基於數學推導和產生原理重新描述了書中的概念,並用Python (numpy 庫為主) 復現了書本內容,在Github上開放,歡迎大家查看學習。同時,它還介紹了工業界中實踐者用到的深度學習技術,包括深度前饋網絡、正則化、優化算法、卷積網絡、序列建模和實踐方法等,並且調研了諸如自然語言處理、語音識別、計算機視覺、在線推薦系統、生物信息學以及視頻遊戲方面的應用。
  • 數學推導+純 Python 實現機器學習算法:Kmeans 聚類
    下面我們基於numpy按照前述算法流程來實現一個kmeans算法。回顧上述過程,我們可以先思考一下對算法每個流程該如何定義。首先要定義歐式距離計算函數,然後類中心初始化、根據樣本與類中心的歐式距離劃分類別並獲取聚類結果、根據新的聚類結果重新計算類中心點、重新聚類直到滿足停止條件。