前言
本文討論的GBDT算法,也是基於決策樹
開始探索
scikit-learn
老規矩,先上代碼,看看GBDT的用法
from sklearn.datasets import load_iris
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
gbdt_model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=0)
gbdt_model.fit(X_train, y_train)
gbdt_pred = gbdt_model.predict(X_test)
print("\nClassification Report (GBDT):")
print(classification_report(y_test, gbdt_pred))
腳本!啓動:

深入理解GBDT
GBDT全稱,梯度提升決策樹(Gradient Boosting Decision Tree),通過“不斷擬合上一步誤差”的方式來迭代構建模型,每一步都用一棵新的決策樹來逼近當前的殘差,從而不斷提升整體模型性能
不斷的迭代決策樹,通過損失函數的負梯度作為每一輪迭代的優化目標,每一棵決策樹糾正前一棵樹的誤差,最終將所有樹的預測結果加權求和得到最終輸出
基本思路
1)首先計算出初始概率:
預測值計算公式(logit公式): $$F=log(\frac{p}{1-p})$$
概率計算公式(sigmoid公式): $$P=\frac{1}{1+e^{-F}}$$
2)計算殘差,通過一棵迴歸樹擬合該殘差
3)再次計算概率
該輪預測值: $$F_t(x)=F_{t-1}(x)+η·T_t(x)$$
- \(F_t(x)\):當前輪次對x的預測值
- \(F_{t-1}\):上一輪次對x的預測值
- \(η\):學習率,每輪更新的步長
- \(T_t(x)\):每輪訓練的迴歸樹,用來擬合上一輪訓練的殘差
計算出概率: $$P=\frac{1}{1+e^{-F}}$$
4)計算殘差、擬合殘差、求樹的梯度。循環往復,直至收斂
舉例説明
下面以二分類任務為例,有10個樣本,6個正類(1),4個負類(0)
1)計算初始概率
初始預測值:所有樣本的初始預測值為正類的對數機率,通過logit函數計算:$$F = log( \frac{p}{1-p}) = log(\frac{0.6}{0.4}) \approx 0.4055 $$
帶入到sigmoid計算預測概率:
2)計算殘差,所謂殘差,是單個樣本點的預測值與真實值之間的差
正類樣本(1)的殘差:\(r_i=1-0.6=0.4\)
負類樣本(0)的殘差:\(r_i=0-0.6=-0.6\)
3)訓練第一棵決策迴歸樹
4)再次計算概率
假設學習率\(\eta=0.1\),更新模型預測:
- 正類預測:\(F_{正類}=0.4055+0.1×0.4 = 0.4455\)
- 負類預測:\(F_{負類}=0.4055+0.1×(−0.6) = 0.3455\)
計算預測概率
更新預測概率\(P\)
- 正類概率:\(P_{正類}=\frac{1}{1+e^{-0.4455}} \approx 0.6095\)
- 負類概率:\(P_{負類}=\frac{1}{1+e^{-0.3455}} \approx 0.5854\)
由於設置了迭代次數:n_estimators=5,繼續迭代
4)計算二輪殘差
- 正類殘差:\(r_{正類}=1-0.6095=0.3905\)
- 負類殘差:\(r_{負類}=0-0.5854=−0.5854\)
5)繼續訓練第二棵決策迴歸樹
- 模型預測\(F\)
- 正類預測:\(F_{正類}=0.4455+0.1×0.3905 \approx 0.4846\)
- 負類預測:\(F_{負類}=0.3455+0.1×(-0.5854) \approx 0.287\)
- 預測概率\(P\)
- 正類概率:\(P_{正類} \approx 0.6188\)
- 負類概率:\(P_{負類} \approx 0.5713\)
6)不斷迭代,直至n_estimators=5
默認使用最後一次的參數,有位彥祖就説,這不合理啊,有可能中途第三次訓練的參數擬合度更高,為什麼不用第三次的參數呢,這個問題可以使用早停法解決,後面會説
迴歸樹
有位彥祖問了,我明明是做分類問題,為什麼要用迴歸樹來擬合殘差?“迴歸”這個詞到底指的是什麼?
我們用的決策樹,是迴歸決策樹,是為了擬合殘差。之前討論過決策樹,但是是分類決策樹,這裏簡單描述一下回歸決策樹
直接上一個例子,更加明白。比如現在有一組樣本
| x | y |
|---|---|
| 1 | 5 |
| 2 | 6 |
| 3 | 7 |
| 4 | 15 |
| 5 | 16 |
| 6 | 17 |
為了簡單説明,假設我們的樹深度只有1
1)選擇切分點,兩個樣本中間
x = [1 2 3 4 5 6] => [1.5 2.5 3.5 4.5 5.5]
假設選擇3.5的切分點
2)計算損失函數MSE
-
左子集:x = [1 2 3],y = [5 6 7]
- 均值:\(\frac{5+6+7}{3} = 6\)
- MSE = \(\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 = \frac{(5-6)^2+(6-6)^2+(7-6)^2}{3} \approx 0.6667\)
-
右子集:x = [4 5 6],y = [15 16 17]
- 均值:\(\frac{15+16+17}{3} = 16\)
- MSE = \(\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 = \frac{(15-16)^2+(16-16)^2+(17-16)^2}{3} \approx 0.6667\)
-
加權總MSE:\(\frac{3}{6}·0.6667 + \frac{3}{6}·0.6667 = 0.6667\)
也可以選擇其他的分割點,然後計算MSE,選擇最優分割點
3)擬合樹
殘差與梯度
根據二分類的交叉熵公式以及求概率公式
對特徵\(x\)求導,通過剝洋葱方法:
由於\(\hat{y}=\frac{1}{1+e^{-F}}\),那麼\(1-\hat{y}=\frac{e^{-F}}{1+e^{-F}}\),帶入上面:
梯度有了,那負梯度自然也計算出來了
通過計算,負梯度=殘差,所以,在上面演示的GBDT二分類任務中,就是沿着負梯度(殘差)方向不斷的尋找
早停法
顧名思義,就是發現模型性能下降的時候,立刻停止訓練,並且保留性能最高的那組參數
import lightgbm as lgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
X, y = make_classification(n_samples=1000, n_features=20, random_state=0)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=0)
train_data = lgb.Dataset(X_train, label=y_train)
val_data = lgb.Dataset(X_val, label=y_val, reference=train_data)
params = {
'objective': 'binary',
'metric': 'binary_logloss',
'learning_rate': 0.1,
'max_depth': 3,
'num_leaves': 7,
'verbose': -1
}
model = lgb.train(
params,
train_data,
num_boost_round=1000,
valid_sets=[val_data],
callbacks=[
lgb.early_stopping(stopping_rounds=5),
lgb.log_evaluation(period=10)
]
)
y_pred = model.predict(X_val, num_iteration=model.best_iteration)
y_pred_binary = [1 if p > 0.5 else 0 for p in y_pred]
print(f"Validation Accuracy: {accuracy_score(y_val, y_pred_binary):.4f}")
print(f"Best iteration: {model.best_iteration}")
腳本,啓動!

objective:binary表示分類任務的損失函數metric:binary_logloss表示監控指標為對數損失函數,也可以換成binary_error表示誤差率num_boost_round=1000:最大迭代次數stopping_rounds=5:連續5輪不提升則停止period=10:每10輪打印日誌
小結
給一組系統性能數據,能不能發現潛在的風險,風險判定為,日誌錯誤率為>100條
如果錯誤日誌為80條,雖然沒有告警,但是系統已經在風險邊緣了
先給一組數據,通過系統性能指標進行分類,然後再對於各時段的性能數據進行分類,看系統是否處於崩潰邊緣
聯繫我
- 聯繫我,做深入的交流
![]()
至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...
