30分鐘學(xué)會LightGBM
一,LightGBM和XGBoost對比
LightGBM可以看成是XGBoost的升級加強(qiáng)版本,2017年經(jīng)微軟推出后,便成為各種數(shù)據(jù)競賽中刷分奪冠的神兵利器。
正如其名字中的Light所蘊(yùn)含的那樣,和XGBoost相比,LightGBM在大規(guī)模數(shù)據(jù)集上跑起來更加輕盈。
公眾號后臺回復(fù)關(guān)鍵字:"源碼",獲取本文全部代碼和對應(yīng)插圖PPT。
模型精度:XGBoost和LightGBM相當(dāng)。
訓(xùn)練速度:LightGBM遠(yuǎn)快于XGBoost。
內(nèi)存消耗:LightGBM遠(yuǎn)小于XGBoost。
缺失值特征:XGBoost和LightGBM都可以自動處理特征缺失值。
分類特征:XGBoost不支持類別特征,需要OneHot編碼預(yù)處理。
LightGBM直接支持類別特征。


公眾號后臺回復(fù)關(guān)鍵字:"源碼",獲取本文全部代碼和對應(yīng)插圖PPT。
二,LightGBM性能優(yōu)化原理概述
LightGBM在XGBoost上主要有3方面的優(yōu)化。
1,Histogram算法:直方圖算法。
2,GOSS算法:基于梯度的單邊采樣算法。
3,EFB算法:互斥特征捆綁算法。
可以用如下一個簡單公式來說明LightGBM和XGBoost的關(guān)系:
LightGBM = XGBoost + Histogram + GOSS + EFB。
那么,Histogram算法,GOSS算法,和EFB算法分別從什么角度對XGBoost進(jìn)行性能優(yōu)化呢?我們先概括性地從全局進(jìn)行分析,然后再逐個加以介紹。
XGBoost模型訓(xùn)練的總體的復(fù)雜度可以粗略估計為:
訓(xùn)練復(fù)雜度 = 樹的棵數(shù)??每棵樹上葉子的數(shù)量??生成每片葉子的復(fù)雜度。
由于XGBoost采用的基模型是二叉樹,因此生成每片葉子需要分裂一次。而每次分裂,需要遍歷所有特征上所有候選分裂點位,計算按照這些候選分裂點位分裂后的全部樣本的目標(biāo)函數(shù)增益,找到最大的那個增益對應(yīng)的特征和候選分裂點位,從而生成一片新葉子。
生成一片葉子的復(fù)雜度可以粗略估計為:
生成一片葉子的復(fù)雜度 = 特征數(shù)量??候選分裂點數(shù)量??樣本的數(shù)量。
而Hitogram算法的主要作用是減少候選分裂點數(shù)量,GOSS算法的作用是減少樣本的數(shù)量,EFB算法的作用是減少特征的數(shù)量。
通過這3個算法的引入,LightGBM生成一片葉子需要的復(fù)雜度大大降低了,從而極大節(jié)約了計算時間。
同時Histogram算法還將特征由浮點數(shù)轉(zhuǎn)換成0~255位的整數(shù)進(jìn)行存儲,從而極大節(jié)約了內(nèi)存存儲。
三,Histogram算法
直方圖算法是替代XGBoost的預(yù)排序(pre-sorted)算法的。
預(yù)排序算法首先將樣本按照特征取值排序,然后從全部特征取值中找到最優(yōu)的分裂點位,該算法的候選分裂點數(shù)量與樣本數(shù)量成正比。
而直方圖算法通過將連續(xù)特征值離散化到固定數(shù)量(如255個)的bins上,使得候選分為點位為常數(shù)個(num_bins -1).
此外,直方圖算法還能夠作直方圖差加速。當(dāng)節(jié)點分裂成兩個時,右邊葉子節(jié)點的直方圖等于其父節(jié)點的直方圖減去左邊葉子節(jié)點的直方圖。從而大大減少構(gòu)建直方圖的計算量。



四,GOSS算法
GOSS算法全稱為Gradient-based One-Side Sampling,即基于梯度的單邊采樣算法。
其主要思想是通過對樣本采樣的方法來減少計算目標(biāo)函數(shù)增益時候的復(fù)雜度。
但如果對全部樣本進(jìn)行隨機(jī)采樣,勢必會對目標(biāo)函數(shù)增益的計算精度造成較大的影響。
GOSS算法的創(chuàng)新之處在于它只對梯度絕對值較小的樣本按照一定比例進(jìn)行采樣,而保留了梯度絕對值較大的樣本。
這就是所謂的單邊采樣。由于目標(biāo)函數(shù)增益主要來自于梯度絕對值較大的樣本,因此這種方法在計算性能和計算精度之間取得了很好的平衡。

五,EFB算法
EFB算法全稱是Exclusive Feature Bundling,即互斥特征綁定算法。
EFB算法可以有效減少用于構(gòu)建直方圖的特征數(shù)量,從而降低計算復(fù)雜度,尤其是特征中包含大量稀疏特征的時候。
在許多應(yīng)用場景下,數(shù)據(jù)集中會有大量的稀疏特征,這些稀疏特征大部分樣本都取值為0,只有少數(shù)樣本取值非0。
通??梢哉J(rèn)為這些稀疏特征是互斥的,即它們幾乎不會同時取非零值。
利用這種特性,可以通過對某些特征的取值重新編碼,將多個這樣互斥的特征捆綁成為一個新的特征。
有趣的是,對于類別特征,如果轉(zhuǎn)換成onehot編碼,則這些onehot編碼后的多個特征相互之間是互斥的,從而可以被捆綁成為一個特征。
因此,對于指定為類別特征的特征,LightGBM可以直接將每個類別取值和一個bin關(guān)聯(lián),從而自動地處理它們,而無需預(yù)處理成onehot編碼多此一舉。

六,LightGBM使用范例
使用pip安裝lightgbm時候如果報錯,可以嘗試使用conda安裝。
conda install lightgbm
以下為lightgbm的使用范例,可以參照修改使用。
import datetimeimport numpy as npimport pandas as pdimport lightgbm as lgbfrom sklearn import datasetsfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import accuracy_scoredef printlog(info):nowtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')print("\n"+"=========="*8 + "%s"%nowtime)print(info+'...\n\n')#================================================================================# 一,讀取數(shù)據(jù)#================================================================================printlog("step1: reading data...")# 讀取dftrain,dftestbreast = datasets.load_breast_cancer()df = pd.DataFrame(breast.data,columns = [x.replace(' ','_') for x in breast.feature_names])df['label'] = breast.targetdf['mean_radius'] = df['mean_radius'].apply(lambda x:int(x))df['mean_texture'] = df['mean_texture'].apply(lambda x:int(x))dftrain,dftest = train_test_split(df)categorical_features = ['mean_radius','mean_texture']lgb_train = lgb.Dataset(dftrain.drop(['label'],axis = 1),label=dftrain['label'],categorical_feature = categorical_features)lgb_valid = lgb.Dataset(dftest.drop(['label'],axis = 1),label=dftest['label'],categorical_feature = categorical_features,reference=lgb_train)#================================================================================# 二,設(shè)置參數(shù)#================================================================================printlog("step2: setting parameters...")boost_round = 50early_stop_rounds = 10params = {'boosting_type': 'gbdt','objective':'binary','metric': ['auc'],'num_leaves': 31,'learning_rate': 0.05,'feature_fraction': 0.9,'bagging_fraction': 0.8,'bagging_freq': 5,'verbose': 0}#================================================================================# 三,訓(xùn)練模型#================================================================================printlog("step3: training model...")results = {}gbm = lgb.train(params,lgb_train,num_boost_round= boost_round,valid_sets=(lgb_valid, lgb_train),valid_names=('validate','train'),early_stopping_rounds = early_stop_rounds,evals_result= results)#================================================================================# 四,評估模型#================================================================================printlog("step4: evaluating model ...")y_pred_train = gbm.predict(dftrain.drop('label',axis = 1), num_iteration=gbm.best_iteration)y_pred_test = gbm.predict(dftest.drop('label',axis = 1), num_iteration=gbm.best_iteration)print('train accuracy: {:.5} '.format(accuracy_score(dftrain['label'],y_pred_train>0.5)))print('valid accuracy: {:.5} \n'.format(accuracy_score(dftest['label'],y_pred_test>0.5)))lgb.plot_metric(results)lgb.plot_importance(gbm,importance_type = "gain")#================================================================================# 五,保存模型#================================================================================printlog("step5: saving model ...")model_dir = "data/gbm.model"print("model_dir: %s"%model_dir)gbm.save_model("data/gbm.model")printlog("task end...")######





公眾號后臺回復(fù)關(guān)鍵字:"源碼",獲取本文全部代碼和對應(yīng)插圖PPT。
