
lightGBM可以用來解決大多數表格資料問題的演算法,有很多很棒的功能,并且在kaggle這種該資料比賽中會經常使用,
但我一直對了解哪些引數對性能的影響最大以及我應該如何調優lightGBM引數以最大限度地利用它很感興趣,
我想我應該做一些研究,了解更多關于lightGBM的引數…并分享我的旅程,
我希望讀完這篇文章后,你能回答以下問題:
- LightGBM中實作了哪些梯度增強方法,它們有什么區別?
- 一般來說,哪些引數是重要的?
- 哪些正則化引數需要調整?
- 如何調整lightGBM引數在python?
梯度提升的方法
使用LightGBM,你可以運行不同型別的漸變增強提升方法,你有:GBDT、DART和GOSS,這些可以通過“boosting”引數指定,
在下一節中,我將對這些方法進行解釋和比較,
梯度提升決策樹(GBDT)
該方法是本文首先提出的傳統梯度提升決策樹,也是XGBoost和pGBRT等優秀庫背后的演算法,
由于其精度高、效率高、穩定性好,目前已得到廣泛的應用,你可能知道gbdt是一個決策樹的集合模型但是它到底是什么意思呢?
讓我來告訴你要點,
它基于三個重要原則:
- 弱學習者(決策樹)
- 梯度優化
- 提升技術
所以在gbdt方法中,我們有很多決策樹(弱學習者),這些樹是按順序構建的:
- 首先,樹學習如何適應目標變數
- 第二棵樹學習如何適合殘差(差異)之間的預測,第一棵樹和地面真相
- 第三棵樹學習如何匹配第二棵樹的殘差,以此類推,
所有這些樹都是通過傳播整個系統的誤差梯度來訓練的,
gbdt的主要缺點是,在每個樹節點中找到最佳分割點非常耗時,而且會消耗記憶體,其他的提升方法試圖解決這個問題,
DART 梯度提升
在這篇優秀的論文中(arxiv/1505.01866),你可以學習所有關于DART梯度提升的東西,這是一種使用dropout(神經網路中的標準)的方法,來改進模型正則化和處理一些其他不太明顯的問題,
也就是說,gbdt存在過度專門化(over-specialization)的問題,這意味著在以后的迭代中添加的樹往往只會影響對少數實體的預測,而對其余實體的貢獻則可以忽略不計,添加dropout會使樹在以后的迭代中更加難以專門化那些少數的示例,從而提高性能,
lgbm goss 基于梯度的單邊采樣
事實上,將該方法命名為lightgbm的最重要原因就是使用了基于本文的Goss方法,Goss是較新的、較輕的gbdt實作(因此是“light”gbm),
標準的gbdt是可靠的,但在大型資料集上速度不夠快,因此goss提出了一種基于梯度的采樣方法來避免搜索整個搜索空間,我們知道,對于每個資料實體,當梯度很小時,這意味著不用擔心資料是經過良好訓練的,而當梯度很大時,應該重新訓練,這里我們有兩個方面,資料實體有大的和小的漸變,因此,goss以一個大的梯度保存所有資料,并對一個小梯度的資料進行隨機抽樣(這就是為什么它被稱為單邊抽樣),這使得搜索空間更小,goss的收斂速度更快,
讓我們把這些差異放在一個表格中:

注意:如果你將增強設定為RF,那么lightgbm演算法表現為隨機森林而不是增強樹! 根據檔案,要使用RF,必須使用bagging_fraction和feature_fraction小于1,
正則化
在這一節中,我將介紹lightgbm的一些重要的正則化引數,顯然,這些是您需要調優以防止過擬合的引數,
您應該知道,對于較小的資料集(<10000條記錄),lightGBM可能不是最佳選擇,在這里,調優lightgbm引數可能沒有幫助,
此外,lightgbm使用葉向樹生長演算法,而xgboost使用深度樹生長演算法,葉向方法使樹的收斂速度更快,但過擬合的幾率增加,
注意:如果有人問您LightGBM和XGBoost之間的主要區別是什么?你可以很容易地說,它們的區別在于它們是如何實作的,
根據lightGBM檔案,當面臨過擬合時,您可能需要做以下引數調優:
- 使用更小的max_bin
- 使用更小的num_leaves
- 使用min_data_in_leaf和min_sum_hessian_in_leaf
- 通過設定bagging_fraction和bagging_freq使用bagging_freq
- 通過設定feature_fraction使用特征子采樣
- 使用更大的訓練資料
- 嘗試lambda_l1、lambda_l2和min_gain_to_split進行正則化
- 嘗試max_depth以避免樹的深度增長
在下面的部分中,我將更詳細地解釋這些引數,
lambda_l1
Lambda_l1(和lambda_l2)控制l1/l2,以及min_gain_to_split用于防止過擬合,我強烈建議您使用引數調優(在后面的小節中討論)來確定這些引數的最佳值,
num_leaves
num_leaves無疑是控制模型復雜性的最重要引數之一,通過它,您可以設定每個弱學習者擁有的葉子的最大數量,較大的num_leaves增加了訓練集的精確度,也增加了因過度擬合而受傷的幾率,根據檔案,一個簡單的方法是num_leaves = 2^(max_depth)但是,考慮到在lightgbm中葉狀樹比層次樹更深,你需要小心過度擬合!因此,必須同時使用max_depth調優num_leaves,

子采樣
通過子樣例(或bagging_fraction),您可以指定每個樹構建迭代使用的行數百分比,這意味著將隨機選擇一些行來匹配每個學習者(樹),這不僅提高了泛化能力,也提高了訓練速度,

我建議對基線模型使用更小的子樣本值,然后在完成其他實驗(不同的特征選擇,不同的樹結構)時增加這個值,
feature_fraction
特征分數或子特征處理列采樣,LightGBM將在每次迭代(樹)上隨機選擇特征子集,例如,如果將其設定為0.6,LightGBM將在訓練每棵樹之前選擇60%的特性,
這個功能有兩種用法:
- 可以用來加速訓練嗎
- 可以用來處理過擬合嗎

max_depth
該引數控制每棵經過訓練的樹的最大深度,將對:
- num_leaves引數的最佳值
- 模型的性能
- 訓練時間
注意,如果您使用較大的max_depth值,那么您的模型可能會對于訓練集過擬合,
max_bin
裝箱是一種用離散視圖(直方圖)表示資料的技術,Lightgbm在創建弱學習者時,使用基于直方圖的演算法來尋找最優分割點,因此,每個連續的數字特性(例如視頻的視圖數)應該被分割成離散的容器,

此外,在這個GitHub repo(huanzhang12/lightgbm-gpu)中,你可以找到一些全面的實驗,完全解釋了改變max_bin對CPU和GPU的影響,

如果你定義max_bin 255,這意味著我們可以有255個唯一的值每個特性,那么,較小的max_bin會導致更快的速度,較大的值會提高準確性,
訓練引數
當你想用lightgbm訓練你的模型時,一些典型的問題可能會出現:
- 訓練是一個耗時的程序
- 處理計算復雜度(CPU/GPU RAM約束)
- 處理分類特征
- 擁有不平衡的資料集
- 定制度量的需要
- 需要對分類或回歸問題進行的調整
在本節中,我們將嘗試詳細解釋這些要點,
num_iterations
Num_iterations指定增強迭代的次數(要構建的樹),你建立的樹越多,你的模型就越精確,代價是:
- 較長的訓練時間
- 過擬合的可能性更高
從較少的樹開始構建基線,然后當您想從模型中擠出最后的%時增加基線,
建議使用更小的learning_rate和更大的num_iteration,此外,如果您想要更高的num_iteration,那么您應該使用early_stopping_rounds,以便在無法學習任何有用的內容時停止訓練,
early_stopping_rounds
如果驗證度量在最后一輪停止后沒有改進,此引數將停止訓練,這應該與一些迭代成對地進行定義,如果你把它設定得太大,你就增加了過擬合的變化(但你的模型可以更好),
經驗法則是讓它占num_iterations的10%,
lightgbm categorical_feature
使用lightgbm的優勢之一是它可以很好地處理分類特性,是的,這個演算法非常強大,但是你必須小心如何使用它的引數,lightgbm使用一種特殊的整數編碼方法(由Fisher提出)來處理分類特征
實驗表明,該方法比常用的單熱編碼方法具有更好的性能,
它的默認值是“auto”,意思是:讓lightgbm決定哪個表示lightgbm將推斷哪些特性是絕對的,
它并不總是作業得很好,我強烈建議您簡單地用這段代碼手動設定分類特性
cat_col = dataset_name.select_dtypes(‘object’).columns.tolist()
但是在幕后發生了什么,lightgbm是如何處理分類特征的呢?
根據lightgbm的檔案,我們知道樹學習器不能很好地使用一種熱編碼方法,因為它們在樹中深度生長,在提出的替代方法中,樹形學習器被最優構造,例如,一個特征有k個不同的類別,有2^(k-1) -1個可能的劃分,通過fisher方法,可以改進到k * log(k),通過找到分類特征中值排序直方圖的最佳分割方式,
is_unbalance vs scale_pos_weight
其中一個問題,你可能面臨的二分類問題是如何處理不平衡的資料集,顯然,您需要平衡正/負樣本,但如何在lightgbm中做到這一點呢?
lightgbm中有兩個引數允許你處理這個問題,那就是is_unbalance和scale_pos_weight,但是它們之間有什么區別呢?
當您設定Is_unbalace: True時,演算法將嘗試自動平衡占主導地位的標簽的權重(使用列集中的pos/neg分數)
如果您想改變scale_pos_weight(默認情況下是1,這意味著假設正負標簽都是相等的),在不平衡資料集的情況下,您可以使用以下公式來正確地設定它
sample_pos_weight = number of negative samples / number of positive samples
lgbm函式宏指令(feaval)
有時你想定義一個自定義評估函式來測量你的模型的性能,你需要創建一個“feval”函式,
Feval函式應該接受兩個引數:
preds 、train_data
并回傳
eval_name、eval_result、is_higher_better
讓我們一步一步地創建一個自定義度量函式,
定義一個單獨的python函式
def feval_func(preds, train_data):
# Define a formula that evaluates the results
return ('feval_func_name', eval_result, False)
使用這個函式作為引數:
print('Start training...')
lgb_train = lgb.train(...,
metric=None,
feval=feval_func)
注意:要使用feval函式代替度量,您應該設定度量引數 metric “None”,
分類引數與回歸引數
我之前提到的大多數事情對于分類和回歸都是正確的,但是有些事情需要調整,
具體你應該:

lightgbm最重要的引數
我們已經在前面的部分中回顧并了解了有關lightgbm引數的知識,但是如果不提及Laurae令人難以置信的基準測驗,那么關于增強樹的文章將是不完整的,
您可以了解用于lightGBM和XGBoost的許多問題的最佳默認引數,
你可以查看這里(https://sites.google.com/view/lauraepp/parameters),但一些最重要的結論是:



注意:絕對不要理會任何引數值的默認值,并根據您的問題進行調整, 也就是說,這些引數是超引數調整演算法的一個很好的起點,
Python中的Lightgbm引數調整示例
最后,在解釋完所有重要引數之后,該進行一些實驗了!
我將使用最受歡迎的Kaggle競賽之一:Santander Customer Transaction Prediction. 交易預測
我將使用本文介紹如何在任何腳本中的Python中運行超引數調整,
在開始之前,一個重要的問題! 我們應該調整哪些引數?
請注意您要解決的問題,例如,Santander 資料集高度不平衡,在調整時應考慮到這一點!
一些引數是相互依賴的,必須一起調整, 例如,min_data_in_leaf取決于訓練樣本和num_leaves的數量,
注意:為超引數創建兩個字典是一個好主意,一個字典包含您不想調整的引數和值,另一個字典包含您想要調整的引數和值范圍,
SEARCH_PARAMS = {'learning_rate': 0.4,
'max_depth': 15,
'num_leaves': 20,
'feature_fraction': 0.8,
'subsample': 0.2}
FIXED_PARAMS={'objective': 'binary',
'metric': 'auc',
'is_unbalance':True,
'boosting':'gbdt',
'num_boost_round':300,
'early_stopping_rounds':30}
這樣,您就可以將基線值與搜索空間分開!

如果您查看了上一節,則會發現我在資料集上進行了14個以上的不同實驗, 在這里,我解釋了如何逐步調整超引數的值,
創建基線訓練代碼:
from sklearn.metrics import roc_auc_score, roc_curve
from sklearn.model_selection import train_test_split
import neptunecontrib.monitoring.skopt as sk_utils
import lightgbm as lgb
import pandas as pd
import neptune
import skopt
import sys
import os
SEARCH_PARAMS = {'learning_rate': 0.4,
'max_depth': 15,
'num_leaves': 32,
'feature_fraction': 0.8,
'subsample': 0.2}
FIXED_PARAMS={'objective': 'binary',
'metric': 'auc',
'is_unbalance':True,
'bagging_freq':5,
'boosting':'dart',
'num_boost_round':300,
'early_stopping_rounds':30}
def train_evaluate(search_params):
# you can download the dataset from this link(https://www.kaggle.com/c/santander-customer-transaction-prediction/data)
# import Dataset to play with it
data= https://blog.csdn.net/m0_46510245/article/details/pd.read_csv("sample_train.csv")
X = data.drop(['ID_code', 'target'], axis=1)
y = data['target']
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=1234)
train_data = https://blog.csdn.net/m0_46510245/article/details/lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
params = {'metric':FIXED_PARAMS['metric'],
'objective':FIXED_PARAMS['objective'],
**search_params}
model = lgb.train(params, train_data,
valid_sets=[valid_data],
num_boost_round=FIXED_PARAMS['num_boost_round'],
early_stopping_rounds=FIXED_PARAMS['early_stopping_rounds'],
valid_names=['valid'])
score = model.best_score['valid']['auc']
return score
使用您選擇的超引數優化庫(例如scikit-optimize),
neptune.init('mjbahmani/LightGBM-hyperparameters')
neptune.create_experiment('lgb-tuning_final', upload_source_files=['*.*'],
tags=['lgb-tuning', 'dart'],params=SEARCH_PARAMS)
SPACE = [
skopt.space.Real(0.01, 0.5, name='learning_rate', prior='log-uniform'),
skopt.space.Integer(1, 30, name='max_depth'),
skopt.space.Integer(10, 200, name='num_leaves'),
skopt.space.Real(0.1, 1.0, name='feature_fraction', prior='uniform'),
skopt.space.Real(0.1, 1.0, name='subsample', prior='uniform')
]
@skopt.utils.use_named_args(SPACE)
def objective(**params):
return -1.0 * train_evaluate(params)
monitor = sk_utils.NeptuneMonitor()
results = skopt.forest_minimize(objective, SPACE,
n_calls=100, n_random_starts=10,
callback=[monitor])
sk_utils.log_results(results)
neptune.stop()
注,本文代碼使用了neptune.ai平臺,所以有一些neptune的api
完整代碼在這里 https://ui.neptune.ai/mjbahmani/LightGBM-hyperparameters/experiments?viewId=standard-view&utm_source=medium&utm_medium=crosspost&utm_campaign=blog-lightgbm-parameters-guide
嘗試不同型別的配置并在Neptune中跟蹤結果

最后,在下表中,您可以看到引數中發生了什么變化,

總結
長話短說,您了解到:
- lightgbm的主要引數是什么,
- 如何使用feval函式創建自定義指標
- 主要引數的默認值是多少
- 看到了如何調整lightgbm引數以改善模型性能的示例
作者:Kamil Kaczmarek
deephub 翻譯組
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/4752.html
標籤:其他
上一篇:MBD開發模式下的XIL仿真測驗
