機器學習實戰 | LightGBM建模應用詳解
作者:韓信子@ShowMeAI
教程地址:http://www.showmeai.tech/tutorials/41
本文地址:http://www.showmeai.tech/article-detail/205
宣告:版權所有,轉載請聯絡平臺與作者並註明出處
收藏ShowMeAI檢視更多精彩內容
引言
LightGBM是微軟開發的boosting整合模型,和XGBoost一樣是對GBDT的優化和高效實現,原理有一些相似之處,但它很多方面比XGBoost有著更為優秀的表現。
本篇內容ShowMeAI展開給大家講解LightGBM的工程應用方法,對於LightGBM原理知識感興趣的同學,歡迎參考ShowMeAI的另外一篇文章
1.LightGBM安裝
LightGBM作為常見的強大Python機器學習工具庫,安裝也比較簡單。
1.1 Python與IDE環境設定
python環境與IDE設定可以參考ShowMeAI文章 圖解python | 安裝與環境設定 進行設定。
1.2 工具庫安裝
(1) Linux/Mac等系統
這些系統下的XGBoost安裝,大家只要基於pip就可以輕鬆完成了,在命令列端輸入命令如下命令即可等待安裝完成。
pip install lightgbm
大家也可以選擇國內的pip源,以獲得更好的安裝速度:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple lightgbm
(2) Windows系統
對於windows系統而言,比較高效便捷的安裝方式是:在網址http://www.lfd.uci.edu/~gohlke/pythonlibs/ 中去下載對應版本的的LightGBM安裝包,再通過如下命令安裝。
pip install lightgbm‑3.3.2‑cp310‑cp310‑win_amd64.whl
2.LightGBM引數手冊
在ShowMeAI的前一篇內容 XGBoost工具庫建模應用詳解 中,我們講解到了Xgboost的三類引數通用引數,學習目標引數,Booster引數。而LightGBM可調引數更加豐富,包含核心引數,學習控制引數,IO引數,目標引數,度量引數,網路引數,GPU引數,模型引數,這裡我常修改的便是核心引數,學習控制引數,度量引數等。下面我們對這些模型引數做展開講解,更多的細節可以參考
2.1 引數介紹
(1) 核心引數
-
config
或者config_file
:一個字串,給出了配置檔案的路徑。預設為空字串。 -
task
:一個字串,給出了要執行的任務。可以為:-
train
或者training
:表示是訓練任務。預設為train
。 -
predict
或者prediction
或者test
:表示是預測任務。 -
convert_model
:表示是模型轉換任務。將模型檔案轉換成if-else格式。
-
-
application
或者objective
或者app
:一個字串,表示問題型別。可以為:-
regression
或regression_l2
或mean_squared_error
或mse
或l2_root
或root_mean_squred_error
或rmse
:表示迴歸任務,但是使用L2損失函式。預設為regression
。 -
regression_l1
或者mae
或者mean_absolute_error
:表示迴歸任務,但是使用L1損失函式。 -
huber
:表示迴歸任務,但是使用huber損失函式。 -
fair
:表示迴歸任務,但是使用fair損失函式。 -
poisson
:表示Poisson迴歸任務。 -
quantile
:表示quantile迴歸任務。 -
quantile_l2
:表示quantile迴歸任務,但是使用了L2損失函式。 -
mape
或者mean_absolute_precentage_error
:表示迴歸任務,但是使用MAPE損失函式 -
gamma
:表示gamma迴歸任務。 -
tweedie
:表示tweedie迴歸任務。 -
binary
:表示二分類任務,使用對數損失函式作為目標函式。 -
multiclass
:表示多分類任務,使用softmax函式作為目標函式。必須設定num_class
引數 -
multiclassova
或者multiclass_ova
或者ova
或者ovr
:表示多分類任務,使用one-vs-all
的二分類目標函式。必須設定num_class
引數。 -
xentropy
或者cross_entropy
:目標函式為交叉熵(同時具有可選擇的線性權重)。要求標籤是[0,1]之間的數值。 -
xentlambda
或者cross_entropy_lambda
:替代了引數化的cross_entropy
。要求標籤是[0,1]之間的數值。 -
lambdarank
:表示排序任務。在lambdarank
任務中,標籤應該為整數型別,數值越大表示相關性越高。label_gain
引數可以用於設定整數標籤的增益(權重)。
-
-
boosting
或者boost
或者boosting_type
:一個字串,給出了基學習器模型演算法。可以為:-
gbdt
:表示傳統的梯度提升決策樹。預設值為gbdt
。 -
rf
:表示隨機森林。 -
dart
:表示帶dropout的gbdt。 -
goss
:表示Gradient-based One-Side Sampling 的gbdt。
-
-
data
或者train
或者train_data
:一個字串,給出了訓練資料所在的檔案的檔名。預設為空字串。LightGBM將使用它來訓練模型。 -
valid
或者test
或者valid_data
或者test_data
:一個字串,表示驗證集所在的檔案的檔名。預設為空字串。LightGBM將輸出該資料集的度量。如果有多個驗證集,則用逗號分隔。 -
num_iterations
或者num_iteration
或者num_tree
或者num_trees
或者num_round
或者num_rounds
或者num_boost_round
一個整數,給出了boosting
的迭代次數。預設為100。- 對於Python/R包,該引數是被忽略的。對於Python,使用
train()/cv()
的輸入引數num_boost_round
來代替。 - 在內部,LightGBM對於multiclass問題設定了
num_class*num_iterations
棵樹。
- 對於Python/R包,該引數是被忽略的。對於Python,使用
-
learning_rate
或者shrinkage_rate
:個浮點數,給出了學習率。預設為1。在dart中,它還會影響dropped trees的歸一化權重。 -
num_leaves
或者num_leaf
:一個整數,給出了一棵樹上的葉子數。預設為31。 -
tree_learner
或者tree
:一個字串,給出了tree learner,主要用於並行學習。預設為serial
。可以為:-
serial
:單臺機器的tree learner -
feature
:特徵並行的tree learner -
data
:資料並行的tree learner -
voting
:投票並行的tree learner
-
-
num_threads
或者num_thread
或者nthread
:一個整數,給出了LightGBM的執行緒數。預設為OpenMP_default
。- 為了更快的速度,應該將它設定為真正的CPU核心數,而不是執行緒的數量(大多數CPU使用超執行緒來使每個CPU核心生成2個執行緒)。
- 當資料集較小的時候,不要將它設定的過大。
- 對於並行學習,不應該使用全部的CPU核心,因為這會使得網路效能不佳。
-
device
:一個字串,指定計算裝置。預設為cpu
。可以為gpu
、cpu
。- 建議使用較小的
max_bin
來獲得更快的計算速度。 - 為了加快學習速度,GPU預設使用32位浮點數來求和。你可以設定
gpu_use_dp=True
來啟動64位浮點數,但是它會使得訓練速度降低。
- 建議使用較小的
(2) 學習控制引數
-
max_depth
:一個整數,限制了樹模型的最大深度,預設值為-1。如果小於0,則表示沒有限制。 -
min_data_in_leaf
或者min_data_per_leaf
或者min_data
或者min_child_samples
:一個整數,表示一個葉子節點上包含的最少樣本數量。預設值為20。 -
min_sum_hessian_in_leaf
或者min_sum_hessian_per_leaf
或者min_sum_hessian
或者min_hessian
或者min_child_weight
:一個浮點數,表示一個葉子節點上的最小hessian之和。(也就是葉節點樣本權重之和的最小值)預設為1e-3。 -
feature_fraction
或者sub_feature
或者colsample_bytree
:一個浮點數,取值範圍為[0.0,1.0],預設值為0。如果小於1.0,則LightGBM會在每次迭代中隨機選擇部分特徵。如0.8表示:在每棵樹訓練之前選擇80%的特徵來訓練。 -
feature_fraction_seed
:一個整數,表示feature_fraction
的隨機數種子,預設為2。 -
bagging_fraction
或者sub_row
或者subsample
:一個浮點數,取值範圍為[0.0,1.0],預設值為0。如果小於1.0,則LightGBM會在每次迭代中隨機選擇部分樣本來訓練(非重複取樣)。如0.8表示:在每棵樹訓練之前選擇80%的樣本(非重複取樣)來訓練。 -
bagging_freq
或者subsample_freq
:一個整數,表示每bagging_freq
次執行bagging。如果該引數為0,表示禁用bagging。 -
bagging_seed
或者bagging_fraction_seed
:一個整數,表示bagging的隨機數種子,預設為3。 -
early_stopping_round
或者early_stopping_rounds
或者early_stopping
:一個整數,預設為0。如果一個驗證集的度量在early_stopping_round
迴圈中沒有提升,則停止訓練。如果為0則表示不開啟早停。 -
lambda_l1
或者reg_alpha
:一個浮點數,表示L1正則化係數。預設為0。 -
lambda_l2
或者reg_lambda
:一個浮點數,表示L2正則化係數。預設為0。 -
min_split_gain
或者min_gain_to_split
:一個浮點數,表示執行切分的最小增益,預設為0。 -
drop_rate
:一個浮點數,取值範圍為[0.0,1.0],表示dropout的比例,預設為1。該引數僅在dart中使用。 -
skip_drop
:一個浮點數,取值範圍為[0.0,1.0],表示跳過dropout的概率,預設為5。該引數僅在dart中使用。 -
max_drop
:一個整數,表示一次迭代中刪除樹的最大數量,預設為50。如果小於等於0,則表示沒有限制。該引數僅在dart中使用。 -
uniform_drop
:一個布林值,表示是否想要均勻的刪除樹,預設值為False。該引數僅在dart中使用。 -
xgboost_dart_mode
:一個布林值,表示是否使用xgboost dart模式,預設值為False。該引數僅在dart中使用。 -
drop_seed
:一個整數,表示dropout的隨機數種子,預設值為4。該引數僅在dart中使用。 -
top_rate
:一個浮點數,取值範圍為[0.0,1.0],表示在goss中,大梯度資料的保留比例,預設值為2。該引數僅在goss中使用。 -
other_rate
:一個浮點數,取值範圍為[0.0,1.0],表示在goss中,小梯度資料的保留比例,預設值為1。該引數僅在goss中使用。 -
min_data_per_group
:一個整數,表示每個分類組的最小資料量,預設值為100。用於排序任務 -
max_cat_threshold
:一個整數,表示category特徵的取值集合的最大大小。預設為32。 -
cat_smooth
:一個浮點數,用於category特徵的概率平滑。預設值為10。它可以降低噪聲在category特徵中的影響,尤其是對於資料很少的類。 -
cat_l2
:一個浮點數,用於category切分中的L2正則化係數。預設為10。 -
top_k
或者topk
:一個整數,用於投票並行中。預設為20。將它設定為更大的值可以獲得更精確的結果,但是會降低訓練速度。
(3) IO引數
-
max_bin
:一個整數,表示最大的桶的數量。預設值為255。LightGBM會根據它來自動壓縮記憶體。如max_bin=255
時,則LightGBM將使用uint8來表示特徵的每一個值。 -
min_data_in_bin
:一個整數,表示每個桶的最小樣本數。預設為3。該方法可以避免出現一個桶只有一個樣本的情況。 -
data_random_seed
:一個整數,表示並行學習資料分隔中的隨機數種子。預設為1它不包括特徵並行。 -
output_model
或者model_output
或者model_out
:一個字串,表示訓練中輸出的模型被儲存的檔案的檔名。預設txt。 -
input_model
或者model_input
或者model_in
:一個字串,表示輸入模型的檔案的檔名。預設空字串。對於prediction任務,該模型將用於預測資料,對於train任務,訓練將從該模型繼續 -
output_result
或者predict_result
或者prediction_result
:一個字串,給出了prediction結果存放的檔名。預設為txt。 -
pre_partition
或者is_pre_partition
:一個布林值,指示資料是否已經被劃分。預設值為False。如果為true,則不同的機器使用不同的partition來訓練。它用於並行學習(不包括特徵並行) -
is_sparse
或者is_enable_sparse
或者enable_sparse
:一個布林值,表示是否開啟稀疏優化,預設為True。如果為True則啟用稀疏優化。 -
two_round
或者two_round_loading
或者use_two_round_loading
:一個布林值,指示是否啟動兩次載入。預設值為False,表示只需要進行一次載入。預設情況下,LightGBM會將資料檔案對映到記憶體,然後從記憶體載入特徵,這將提供更快的資料載入速度。但是當資料檔案很大時,記憶體可能會被耗盡。如果資料檔案太大,則將它設定為True -
save_binary
或者is_save_binary
或者is_save_binary_file
:一個布林值,表示是否將資料集(包括驗證集)儲存到二進位制檔案中。預設值為False。如果為True,則可以加快資料的載入速度。 -
verbosity
或者verbose
:一個整數,表示是否輸出中間資訊。預設值為1。如果小於0,則僅僅輸出critical資訊;如果等於0,則還會輸出error,warning資訊;如果大於0,則還會輸出info資訊。 -
header
或者has_header
:一個布林值,表示輸入資料是否有頭部。預設為False。 -
label
或者label_column
:一個字串,表示標籤列。預設為空字串。你也可以指定一個整數,如label=0表示第0列是標籤列。你也可以為列名新增字首,如label=prefix:label_name
。 -
weight
或者weight_column
:一個字串,表示樣本權重列。預設為空字串。你也可以指定一個整數,如weight=0表示第0列是權重列。注意:它是剔除了標籤列之後的索引。假如標籤列為0,權重列為1,則這裡weight=0。你也可以為列名新增字首,如weight=prefix:weight_name
。 -
query
或者query_column
或者gourp
或者group_column
:一個字串,query/groupID列。預設為空字串。你也可以指定一個整數,如query=0表示第0列是query列。注意:它是剔除了標籤列之後的索引。假如標籤列為0,query列為1,則這裡query=0。你也可以為列名新增字首,如query=prefix:query_name
。 -
ignore_column
或者ignore_feature
或者blacklist
:一個字串,表示訓練中忽略的一些列,預設為空字串。可以用數字做索引,如ignore_column=0,1,2
表示第0,1,2列將被忽略。注意:它是剔除了標籤列之後的索引。 - 你也可以為列名新增字首,如
ignore_column=prefix:ign_name1,ign_name2
。 -
categorical_feature
或者categorical_column
或者cat_feature
或者cat_column
:一個字串,指定category特徵的列。預設為空字串。可以用數字做索引,如categorical_feature=0,1,2
表示第0,1,2列將作為category特徵。注意:它是剔除了標籤列之後的索引。你也可以為列名新增字首,如categorical_feature=prefix:cat_name1,cat_name2
在categorycal特徵中,負的取值被視作缺失值。 -
predict_raw_score
或者raw_score
或者is_predict_raw_score
:一個布林值,表示是否預測原始得分。預設為False。如果為True則僅預測原始得分。該引數只用於prediction任務。 -
predict_leaf_index
或者leaf_index
或者is_predict_leaf_index
:一個布林值,表示是否預測每個樣本在每棵樹上的葉節點編號。預設為False。在預測時,每個樣本都會被分配到每棵樹的某個葉子節點上。該引數就是要輸出這些葉子節點的編號。該引數只用於prediction任務。 -
predict_contrib
或者contrib
或者is_predict_contrib
:一個布林值,表示是否輸出每個特徵對於每個樣本的預測的貢獻。預設為False。輸出的結果形狀為[nsamples,nfeatures+1],之所以+1是考慮到bais的貢獻。所有的貢獻加起來就是該樣本的預測結果。該引數只用於prediction任務。 -
bin_construct_sample_cnt
或者subsample_for_bin
:一個整數,表示用來構建直方圖的樣本的數量。預設為200000。如果資料非常稀疏,則可以設定為一個更大的值,如果設定更大的值,則會提供更好的訓練效果,但是會增加資料載入時間。 -
num_iteration_predict
:一個整數,表示在預測中使用多少棵子樹。預設為-1。小於等於0表示使用模型的所有子樹。該引數只用於prediction任務。 -
pred_early_stop
:一個布林值,表示是否使用早停來加速預測。預設為False。如果為True,則可能影響精度。 -
pred_early_stop_freq
:一個整數,表示檢查早停的頻率。預設為10 -
pred_early_stop_margin
:一個浮點數,表示早停的邊際閾值。預設為0 -
use_missing
:一個布林值,表示是否使用缺失值功能。預設為True如果為False則禁用缺失值功能。 -
zero_as_missing
:一個布林值,表示是否將所有的零(包括在libsvm/sparse矩陣中未顯示的值)都視為缺失值。預設為False。如果為False,則將nan視作缺失值。如果為True,則np.nan
和零都將視作缺失值。 -
init_score_file
:一個字串,表示訓練時的初始化分數檔案的路徑。預設為空字串,表示train_data_file+”.init”(如果存在) -
valid_init_score_file
:一個字串,表示驗證時的初始化分數檔案的路徑。預設為空字串,表示valid_data_file+”.init”(如果存在)。如果有多個(對應於多個驗證集),則可以用逗號,
來分隔。
(4) 目標引數
-
sigmoid
:一個浮點數,用sigmoid函式的引數,預設為0。它用於二分類任務和lambdarank任務。 -
alpha
:一個浮點數,用於Huber損失函式和Quantileregression,預設值為0。它用於huber迴歸任務和Quantile迴歸任務。 -
fair_c
:一個浮點數,用於Fair損失函式,預設值為0。它用於fair迴歸任務。 -
gaussian_eta
:一個浮點數,用於控制高斯函式的寬度,預設值為0。它用於regression_l1迴歸任務和huber迴歸任務。 -
posson_max_delta_step
:一個浮點數,用於Poisson regression的引數,預設值為7。它用於poisson迴歸任務。 -
scale_pos_weight
:一個浮點數,用於調整正樣本的權重,預設值為0它用於二分類任務。 -
boost_from_average
:一個布林值,指示是否將初始得分調整為平均值(它可以使得收斂速度更快)。預設為True。它用於迴歸任務。 -
is_unbalance
或者unbalanced_set
:一個布林值,指示訓練資料是否均衡的。預設為True。它用於二分類任務。 -
max_position
:一個整數,指示將在這個NDCG位置優化。預設為20。它用於lambdarank任務。 -
label_gain
:一個浮點數序列,給出了每個標籤的增益。預設值為0,1,3,7,15,….它用於lambdarank任務。 -
num_class
或者num_classes
:一個整數,指示了多分類任務中的類別數量。預設為1它用於多分類任務。 -
reg_sqrt
:一個布林值,預設為False。如果為True,則擬合的結果為:\sqrt{label}。同時預測的結果被自動轉換為:{pred}^2。它用於迴歸任務。
(5) 度量引數
-
metric
:一個字串,指定了度量的指標,預設為:對於迴歸問題,使用l2;對於二分類問題,使用binary_logloss
;對於lambdarank問題,使用ndcg。如果有多個度量指標,則用逗號,
分隔。-
l1
或者mean_absolute_error
或者mae
或者regression_l1
:表示絕對值損失。 -
l2
或者mean_squared_error
或者mse
或者regression_l2
或者regression
:表示平方損失。 -
l2_root
或者root_mean_squared_error
或者rmse
:表示開方損失。 -
quantile
:表示Quantile迴歸中的損失。 -
mape
或者mean_absolute_percentage_error
:表示MAPE損失。 -
huber
:表示huber損失。 -
fair
:表示fair損失。 -
poisson
:表示poisson迴歸的負對數似然。 -
gamma
:表示gamma迴歸的負對數似然。 -
gamma_deviance
:表示gamma迴歸的殘差的方差。 -
tweedie
:表示Tweedie迴歸的負對數似然。 -
ndcg
:表示NDCG。 -
map
或者mean_average_precision
:表示平均的精度。 -
auc
:表示AUC。 -
binary_logloss
或者binary
:表示二類分類中的對數損失函式。 -
binary_error
:表示二類分類中的分類錯誤率。 -
multi_logloss
或者multiclass
或者softmax
或者‘multiclassova或者
multiclass_ova,或者
ova或者
ovr`:表示多類分類中的對數損失函式。 -
multi_error
:表示多分類中的分類錯誤率。 -
xentropy
或者cross_entropy
:表示交叉熵。 -
xentlambda
或者cross_entropy_lambda
:表示intensity加權的交叉熵。 -
kldiv
或者kullback_leibler
:表示KL散度。
-
-
metric_freq
或者output_freq
:一個正式,表示每隔多少次輸出一次度量結果。預設為1。 -
train_metric
或者training_metric
或者is_training_metric
:一個布林值,預設為False。如果為True,則在訓練時就輸出度量結果。 -
ndcg_at
或者ndcg_eval_at
或者eval_at
:一個整數列表,指定了NDCG評估點的位置。預設為1、2、3、4、5。
2.2 引數影響與調參建議
以下為總結的核心引數對模型的影響,及與之對應的調參建議。
(1) 對樹生長控制
-
num_leaves
:葉節點的數目。它是控制樹模型複雜度的主要引數。- 如果是
level-wise
,則該引數為\(2^{depth}\),其中depth為樹的深度。但是當葉子數量相同時,leaf-wise的樹要遠遠深過level-wise樹,非常容易導致過擬合。因此應該讓num_leaves小於\(2^{depth}\)。在leaf-wise樹中,並不存在depth的概念。因為不存在一個從leaves到depth的合理對映。
- 如果是
-
min_data_in_leaf
:每個葉節點的最少樣本數量。- 它是處理
leaf-wise
樹的過擬合的重要引數。將它設為較大的值,可以避免生成一個過深的樹。但是也可能導致欠擬合。
- 它是處理
-
max_depth
:樹的最大深度。該引數可以顯式的限制樹的深度。
(2) 更快的訓練速度
- 通過設定
bagging_fraction
和bagging_freq
引數來使用bagging方法。 - 通過設定
feature_fraction
引數來使用特徵的子抽樣。 - 使用較小的
max_bin
。 - 使用
save_binary
在未來的學習過程對資料載入進行加速。
(3) 更好的模型效果
- 使用較大的
max_bin
(學習速度可能變慢)。 - 使用較小的
learning_rate
和較大的num_iterations
。 - 使用較大的
num_leaves
(可能導致過擬合)。 - 使用更大的訓練資料。
- 嘗試
dart
。
(4) 緩解過擬合問題
- 使用較小的
max_bin
。 - 使用較小的
num_leaves
。 - 使用
min_data_in_leaf
和min_sum_hessian_in_leaf
。 - 通過設定
bagging_fraction
和bagging_freq
來使用bagging
。 - 通過設定
feature_fraction
來使用特徵子抽樣。 - 使用更大的訓練資料。
- 使用
lambda_l1
、lambda_l2
和min_gain_to_split
來使用正則。 - 嘗試
max_depth
來避免生成過深的樹。
3.LightGBM內建建模方式
3.1 內建建模方式
LightGBM內建了建模方式,有如下的資料格式與核心訓練方法:
- 基於
lightgbm.Dataset
格式的資料。 - 基於
lightgbm.train
介面訓練。
下面是官方的一個簡單示例,演示了讀取libsvm格式資料(成Dataset
格式)並指定引數建模的過程。
# coding: utf-8
import json
import lightgbm as lgb
import pandas as pd
from sklearn.metrics import mean_squared_error
# 載入資料集合
print('載入資料...')
df_train = pd.read_csv('./data/regression.train.txt', header=None, sep='\t')
df_test = pd.read_csv('./data/regression.test.txt', header=None, sep='\t')
# 設定訓練集和測試集
y_train = df_train[0].values
y_test = df_test[0].values
X_train = df_train.drop(0, axis=1).values
X_test = df_test.drop(0, axis=1).values
# 構建lgb中的Dataset格式
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train)
# 敲定好一組引數
params = {
'task': 'train',
'boosting_type': 'gbdt',
'objective': 'regression',
'metric': {'l2', 'auc'},
'num_leaves': 31,
'learning_rate': 0.05,
'feature_fraction': 0.9,
'bagging_fraction': 0.8,
'bagging_freq': 5,
'verbose': 0
}
print('開始訓練...')
# 訓練
gbm = lgb.train(params,
lgb_train,
num_boost_round=20,
valid_sets=lgb_eval,
early_stopping_rounds=5)
# 儲存模型
print('儲存模型...')
# 儲存模型到檔案中
gbm.save_model('model.txt')
print('開始預測...')
# 預測
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
# 評估
print('預估結果的rmse為:')
print(mean_squared_error(y_test, y_pred) ** 0.5)
載入資料...
開始訓練...
[1] valid_0's l2: 0.24288 valid_0's auc: 0.764496
Training until validation scores don't improve for 5 rounds.
[2] valid_0's l2: 0.239307 valid_0's auc: 0.766173
[3] valid_0's l2: 0.235559 valid_0's auc: 0.785547
[4] valid_0's l2: 0.230771 valid_0's auc: 0.797786
[5] valid_0's l2: 0.226297 valid_0's auc: 0.805155
[6] valid_0's l2: 0.223692 valid_0's auc: 0.800979
[7] valid_0's l2: 0.220941 valid_0's auc: 0.806566
[8] valid_0's l2: 0.217982 valid_0's auc: 0.808566
[9] valid_0's l2: 0.215351 valid_0's auc: 0.809041
[10] valid_0's l2: 0.213064 valid_0's auc: 0.805953
[11] valid_0's l2: 0.211053 valid_0's auc: 0.804631
[12] valid_0's l2: 0.209336 valid_0's auc: 0.802922
[13] valid_0's l2: 0.207492 valid_0's auc: 0.802011
[14] valid_0's l2: 0.206016 valid_0's auc: 0.80193
Early stopping, best iteration is:
[9] valid_0's l2: 0.215351 valid_0's auc: 0.809041
儲存模型...
開始預測...
預估結果的rmse為:
0.4640593794679212
3.2 設定樣本權重
LightGBM的建模非常靈活,它可以支援我們對於每個樣本設定不同的權重學習,設定的方式也非常簡單,我們需要提供給模型一組權重陣列資料,長度和樣本數一致。
如下是一個典型的例子,其中binary.train
和binary.test
讀取後加載為lightgbm.Dataset
格式的輸入,而在lightgbm.Dataset
的構建引數中可以設定樣本權重(這個例子中是numpy array的形態)。再基於lightgbm.train
介面使用內建建模方式訓練。
# coding: utf-8
import json
import lightgbm as lgb
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error
import warnings
warnings.filterwarnings("ignore")
# 載入資料集
print('載入資料...')
df_train = pd.read_csv('./data/binary.train', header=None, sep='\t')
df_test = pd.read_csv('./data/binary.test', header=None, sep='\t')
W_train = pd.read_csv('./data/binary.train.weight', header=None)[0]
W_test = pd.read_csv('./data/binary.test.weight', header=None)[0]
y_train = df_train[0].values
y_test = df_test[0].values
X_train = df_train.drop(0, axis=1).values
X_test = df_test.drop(0, axis=1).values
num_train, num_feature = X_train.shape
# 載入資料的同時載入權重
lgb_train = lgb.Dataset(X_train, y_train,
weight=W_train, free_raw_data=False)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train,
weight=W_test, free_raw_data=False)
# 設定引數
params = {
'boosting_type': 'gbdt',
'objective': 'binary',
'metric': 'binary_logloss',
'num_leaves': 31,
'learning_rate': 0.05,
'feature_fraction': 0.9,
'bagging_fraction': 0.8,
'bagging_freq': 5,
'verbose': 0
}
# 產出特徵名稱
feature_name = ['feature_' + str(col) for col in range(num_feature)]
print('開始訓練...')
gbm = lgb.train(params,
lgb_train,
num_boost_round=10,
valid_sets=lgb_train, # 評估訓練集
feature_name=feature_name,
categorical_feature=[21])
載入資料...
開始訓練...
[1] training's binary_logloss: 0.68205
[2] training's binary_logloss: 0.673618
[3] training's binary_logloss: 0.665891
[4] training's binary_logloss: 0.656874
[5] training's binary_logloss: 0.648523
[6] training's binary_logloss: 0.641874
[7] training's binary_logloss: 0.636029
[8] training's binary_logloss: 0.629427
[9] training's binary_logloss: 0.623354
[10] training's binary_logloss: 0.617593
3.3 模型儲存與載入
上述建模過程得到的模型物件,可以通過save_model成員函式進行儲存。儲存好的模型可以通過lgb.Booster
載入回記憶體,並對測試集進行預測。
具體示例程式碼如下:
# 檢視特徵名稱
print('完成10輪訓練...')
print('第7個特徵為:')
print(repr(lgb_train.feature_name[6]))
# 儲存模型
gbm.save_model('./model/lgb_model.txt')
# 特徵名稱
print('特徵名稱:')
print(gbm.feature_name())
# 特徵重要度
print('特徵重要度:')
print(list(gbm.feature_importance()))
# 載入模型
print('載入模型用於預測')
bst = lgb.Booster(model_file='./model/lgb_model.txt')
# 預測
y_pred = bst.predict(X_test)
# 在測試集評估效果
print('在測試集上的rmse為:')
print(mean_squared_error(y_test, y_pred) ** 0.5)
完成10輪訓練...
第7個特徵為:
'feature_6'
特徵名稱:
['feature_0', 'feature_1', 'feature_2', 'feature_3', 'feature_4', 'feature_5', 'feature_6', 'feature_7', 'feature_8', 'feature_9', 'feature_10', 'feature_11', 'feature_12', 'feature_13', 'feature_14', 'feature_15', 'feature_16', 'feature_17', 'feature_18', 'feature_19', 'feature_20', 'feature_21', 'feature_22', 'feature_23', 'feature_24', 'feature_25', 'feature_26', 'feature_27']
特徵重要度:
[8, 5, 1, 19, 7, 33, 2, 0, 2, 10, 5, 2, 0, 9, 3, 3, 0, 2, 2, 5, 1, 0, 36, 3, 33, 45, 29, 35]
載入模型用於預測
在測試集上的rmse為:
0.4629245607636925
3.4 繼續訓練
LightGBM為boosting模型,每一輪訓練會增加新的基學習器,LightGBM還支援基於現有模型和引數繼續訓練,無需每次從頭訓練。
如下是典型的示例,我們載入已經訓練10輪(即10顆樹整合)的lgb模型,在此基礎上繼續訓練(在引數層面做了一些改變,調整了學習率,增加了一些bagging等緩解過擬合的處理方法)
# 繼續訓練
# 從./model/model.txt中載入模型初始化
gbm = lgb.train(params,
lgb_train,
num_boost_round=10,
init_model='./model/lgb_model.txt',
valid_sets=lgb_eval)
print('以舊模型為初始化,完成第 10-20 輪訓練...')
# 在訓練的過程中調整超引數
# 比如這裡調整的是學習率
gbm = lgb.train(params,
lgb_train,
num_boost_round=10,
init_model=gbm,
learning_rates=lambda iter: 0.05 * (0.99 ** iter),
valid_sets=lgb_eval)
print('逐步調整學習率完成第 20-30 輪訓練...')
# 調整其他超引數
gbm = lgb.train(params,
lgb_train,
num_boost_round=10,
init_model=gbm,
valid_sets=lgb_eval,
callbacks=[lgb.reset_parameter(bagging_fraction=[0.7] * 5 + [0.6] * 5)])
print('逐步調整bagging比率完成第 30-40 輪訓練...')
[11] valid_0's binary_logloss: 0.616177
[12] valid_0's binary_logloss: 0.611792
[13] valid_0's binary_logloss: 0.607043
[14] valid_0's binary_logloss: 0.602314
[15] valid_0's binary_logloss: 0.598433
[16] valid_0's binary_logloss: 0.595238
[17] valid_0's binary_logloss: 0.592047
[18] valid_0's binary_logloss: 0.588673
[19] valid_0's binary_logloss: 0.586084
[20] valid_0's binary_logloss: 0.584033
以舊模型為初始化,完成第 10-20 輪訓練...
[21] valid_0's binary_logloss: 0.616177
[22] valid_0's binary_logloss: 0.611834
[23] valid_0's binary_logloss: 0.607177
[24] valid_0's binary_logloss: 0.602577
[25] valid_0's binary_logloss: 0.59831
[26] valid_0's binary_logloss: 0.595259
[27] valid_0's binary_logloss: 0.592201
[28] valid_0's binary_logloss: 0.589017
[29] valid_0's binary_logloss: 0.586597
[30] valid_0's binary_logloss: 0.584454
逐步調整學習率完成第 20-30 輪訓練...
[31] valid_0's binary_logloss: 0.616053
[32] valid_0's binary_logloss: 0.612291
[33] valid_0's binary_logloss: 0.60856
[34] valid_0's binary_logloss: 0.605387
[35] valid_0's binary_logloss: 0.601744
[36] valid_0's binary_logloss: 0.598556
[37] valid_0's binary_logloss: 0.595585
[38] valid_0's binary_logloss: 0.593228
[39] valid_0's binary_logloss: 0.59018
[40] valid_0's binary_logloss: 0.588391
逐步調整bagging比率完成第 30-40 輪訓練...
3.5 自定義損失函式
LightGBM支援在訓練過程中,自定義損失函式和評估準則,其中損失函式的定義需要返回損失函式一階和二階導數的計算方法,評估準則部分需要對資料的label和預估值進行計算。其中損失函式用於訓練過程中的樹結構學習,而評估準則很多時候是用在驗證集上進行效果評估。
# 自定義損失函式需要提供損失函式的一階和二階導數形式
def loglikelood(preds, train_data):
labels = train_data.get_label()
preds = 1. / (1. + np.exp(-preds))
grad = preds - labels
hess = preds * (1. - preds)
return grad, hess
# 自定義評估函式
def binary_error(preds, train_data):
labels = train_data.get_label()
return 'error', np.mean(labels != (preds > 0.5)), False
gbm = lgb.train(params,
lgb_train,
num_boost_round=10,
init_model=gbm,
fobj=loglikelood,
feval=binary_error,
valid_sets=lgb_eval)
print('用自定義的損失函式與評估標準完成第40-50輪...')
[41] valid_0's binary_logloss: 0.614429 valid_0's error: 0.268
[42] valid_0's binary_logloss: 0.610689 valid_0's error: 0.26
[43] valid_0's binary_logloss: 0.606267 valid_0's error: 0.264
[44] valid_0's binary_logloss: 0.601949 valid_0's error: 0.258
[45] valid_0's binary_logloss: 0.597271 valid_0's error: 0.266
[46] valid_0's binary_logloss: 0.593971 valid_0's error: 0.276
[47] valid_0's binary_logloss: 0.591427 valid_0's error: 0.278
[48] valid_0's binary_logloss: 0.588301 valid_0's error: 0.284
[49] valid_0's binary_logloss: 0.586562 valid_0's error: 0.288
[50] valid_0's binary_logloss: 0.584056 valid_0's error: 0.288
用自定義的損失函式與評估標準完成第40-50輪...
4.LightGBM預估器形態介面
4.1 SKLearn形態預估器介面
和XGBoost一樣,LightGBM也支援用SKLearn中統一的預估器形態介面進行建模,如下為典型的參考案例,對於讀取為Dataframe格式的訓練集和測試集,可以直接使用LightGBM初始化LGBMRegressor
進行fit擬合訓練。使用方法與介面,和SKLearn中其他預估器一致。
# coding: utf-8
import lightgbm as lgb
import pandas as pd
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import GridSearchCV
# 載入資料
print('載入資料...')
df_train = pd.read_csv('./data/regression.train.txt', header=None, sep='\t')
df_test = pd.read_csv('./data/regression.test.txt', header=None, sep='\t')
# 取出特徵和標籤
y_train = df_train[0].values
y_test = df_test[0].values
X_train = df_train.drop(0, axis=1).values
X_test = df_test.drop(0, axis=1).values
print('開始訓練...')
# 初始化LGBMRegressor
gbm = lgb.LGBMRegressor(objective='regression',
num_leaves=31,
learning_rate=0.05,
n_estimators=20)
# 使用fit函式擬合
gbm.fit(X_train, y_train,
eval_set=[(X_test, y_test)],
eval_metric='l1',
early_stopping_rounds=5)
# 預測
print('開始預測...')
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration_)
# 評估預測結果
print('預測結果的rmse是:')
print(mean_squared_error(y_test, y_pred) ** 0.5)
載入資料...
開始訓練...
[1] valid_0's l1: 0.491735
Training until validation scores don't improve for 5 rounds.
[2] valid_0's l1: 0.486563
[3] valid_0's l1: 0.481489
[4] valid_0's l1: 0.476848
[5] valid_0's l1: 0.47305
[6] valid_0's l1: 0.469049
[7] valid_0's l1: 0.465556
[8] valid_0's l1: 0.462208
[9] valid_0's l1: 0.458676
[10] valid_0's l1: 0.454998
[11] valid_0's l1: 0.452047
[12] valid_0's l1: 0.449158
[13] valid_0's l1: 0.44608
[14] valid_0's l1: 0.443554
[15] valid_0's l1: 0.440643
[16] valid_0's l1: 0.437687
[17] valid_0's l1: 0.435454
[18] valid_0's l1: 0.433288
[19] valid_0's l1: 0.431297
[20] valid_0's l1: 0.428946
Did not meet early stopping. Best iteration is:
[20] valid_0's l1: 0.428946
開始預測...
預測結果的rmse是:
0.4441153344254208
4.2 網格搜尋調參
上面提到LightGBM的預估器介面,整體使用方法和SKLearn中其他預估器一致,所以我們也可以使用SKLearn中的超引數調優方法來進行模型調優。
如下是一個典型的網格搜尋交法調優超引數的程式碼示例,我們會給出候選引數列表字典,通過GridSearchCV
進行交叉驗證實驗評估,選出LightGBM在候選引數中最優的超引數。
# 配合scikit-learn的網格搜尋交叉驗證選擇最優超引數
estimator = lgb.LGBMRegressor(num_leaves=31)
param_grid = {
'learning_rate': [0.01, 0.1, 1],
'n_estimators': [20, 40]
}
gbm = GridSearchCV(estimator, param_grid)
gbm.fit(X_train, y_train)
print('用網格搜尋找到的最優超引數為:')
print(gbm.best_params_)
用網格搜尋找到的最優超引數為:
{'learning_rate': 0.1, 'n_estimators': 40}
4.3 繪圖解釋
LightGBM支援對模型訓練進行視覺化呈現與解釋,包括對於訓練過程中的損失函式取值與評估準則結果的視覺化、訓練完成後特徵重要度的排序與視覺化、基學習器(比如決策樹)的視覺化。
以下為參考程式碼:
# coding: utf-8
import lightgbm as lgb
import pandas as pd
try:
import matplotlib.pyplot as plt
except ImportError:
raise ImportError('You need to install matplotlib for plotting.')
# 載入資料集
print('載入資料...')
df_train = pd.read_csv('./data/regression.train.txt', header=None, sep='\t')
df_test = pd.read_csv('./data/regression.test.txt', header=None, sep='\t')
# 取出特徵和標籤
y_train = df_train[0].values
y_test = df_test[0].values
X_train = df_train.drop(0, axis=1).values
X_test = df_test.drop(0, axis=1).values
# 構建lgb中的Dataset資料格式
lgb_train = lgb.Dataset(X_train, y_train)
lgb_test = lgb.Dataset(X_test, y_test, reference=lgb_train)
# 設定引數
params = {
'num_leaves': 5,
'metric': ('l1', 'l2'),
'verbose': 0
}
evals_result = {} # to record eval results for plotting
print('開始訓練...')
# 訓練
gbm = lgb.train(params,
lgb_train,
num_boost_round=100,
valid_sets=[lgb_train, lgb_test],
feature_name=['f' + str(i + 1) for i in range(28)],
categorical_feature=[21],
evals_result=evals_result,
verbose_eval=10)
print('在訓練過程中繪圖...')
ax = lgb.plot_metric(evals_result, metric='l1')
plt.show()
print('畫出特徵重要度...')
ax = lgb.plot_importance(gbm, max_num_features=10)
plt.show()
print('畫出第84顆樹...')
ax = lgb.plot_tree(gbm, tree_index=83, figsize=(20, 8), show_info=['split_gain'])
plt.show()
#print('用graphviz畫出第84顆樹...')
#graph = lgb.create_tree_digraph(gbm, tree_index=83, name='Tree84')
#graph.render(view=True)
載入資料...
開始訓練...
[10] training's l2: 0.217995 training's l1: 0.457448 valid_1's l2: 0.21641 valid_1's l1: 0.456464
[20] training's l2: 0.205099 training's l1: 0.436869 valid_1's l2: 0.201616 valid_1's l1: 0.434057
[30] training's l2: 0.197421 training's l1: 0.421302 valid_1's l2: 0.192514 valid_1's l1: 0.417019
[40] training's l2: 0.192856 training's l1: 0.411107 valid_1's l2: 0.187258 valid_1's l1: 0.406303
[50] training's l2: 0.189593 training's l1: 0.403695 valid_1's l2: 0.183688 valid_1's l1: 0.398997
[60] training's l2: 0.187043 training's l1: 0.398704 valid_1's l2: 0.181009 valid_1's l1: 0.393977
[70] training's l2: 0.184982 training's l1: 0.394876 valid_1's l2: 0.178803 valid_1's l1: 0.389805
[80] training's l2: 0.1828 training's l1: 0.391147 valid_1's l2: 0.176799 valid_1's l1: 0.386476
[90] training's l2: 0.180817 training's l1: 0.388101 valid_1's l2: 0.175775 valid_1's l1: 0.384404
[100] training's l2: 0.179171 training's l1: 0.385174 valid_1's l2: 0.175321 valid_1's l1: 0.382929
參考資料
ShowMeAI系列教程推薦
- 圖解Python程式設計:從入門到精通系列教程
- 圖解資料分析:從入門到精通系列教程
- 圖解AI數學基礎:從入門到精通系列教程
- 圖解大資料技術:從入門到精通系列教程
- 圖解機器學習演算法:從入門到精通系列教程
- 機器學習實戰:手把手教你玩轉機器學習系列