動態

詳情 返回 返回

彩筆運維勇闖機器學習--GBDT - 動態 詳情

前言

本文討論的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))


腳本!啓動:

watermarked-gbdt_1_1

深入理解GBDT

GBDT全稱,梯度提升決策樹(Gradient Boosting Decision Tree),通過“不斷擬合上一步誤差”的方式來迭代構建模型,每一步都用一棵新的決策樹來逼近當前的殘差,從而不斷提升整體模型性能

不斷的迭代決策樹,通過損失函數的負梯度作為每一輪迭代的優化目標,每一棵決策樹糾正前一棵樹的誤差,最終將所有樹的預測結果加權求和得到最終輸出

基本思路

1)首先計算出初始概率:

預測值計算公式(logit公式): $$F=log(\frac{p}{1-p})$$
概率計算公式(sigmoid公式): $$P=\frac{1}{1+e^{-F}}$$

2)計算殘差,通過一棵迴歸樹擬合該殘差

\[\begin{aligned} T_t(x)= \left\{ \begin{array}{ll} a \qquad ,x ∈ 正類 \\ b \qquad ,x ∈ 負類 \end{array} \right. \end{aligned} \]

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計算預測概率:

\[P=\frac{1}{1+e^{-F}}=\frac{1}{1+e^{-0.4055}} \approx 0.6 \]

2)計算殘差,所謂殘差,是單個樣本點的預測值與真實值之間的差

正類樣本(1)的殘差:\(r_i=1-0.6=0.4\)
負類樣本(0)的殘差:\(r_i=0-0.6=-0.6\)

3)訓練第一棵決策迴歸樹

\[\begin{aligned} T_t(x)= \left\{ \begin{array}{ll} \frac{6·0.4}{6} = 0.4 \qquad ,x ∈ 正類 \\ \frac{4·(-0.6)}{4} = -0.6 \qquad ,x ∈ 負類 \end{array} \right. \end{aligned} \]

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)繼續訓練第二棵決策迴歸樹

\[\begin{aligned} T_t(x)= \left\{ \begin{array}{ll} \frac{6·0.3905}{6} = 0.3905 \qquad ,x ∈ 正類 \\ \frac{4·(-0.5854)}{4} = -0.5854 \qquad ,x ∈ 負類 \end{array} \right. \end{aligned} \]

  • 模型預測\(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)擬合樹

\[\begin{aligned} T_t(x)= \left\{ \begin{array}{ll} \frac{5+6+7}{3} = 6\qquad ,x > 3.5 \\ \frac{15+16+17}{3} = 16 \qquad ,x <= 3.5 \end{array} \right. \end{aligned} \]

殘差與梯度

根據二分類的交叉熵公式以及求概率公式

\[\begin{cases} L(y, \hat{y})=-(y \log(\hat{y}) + (1 - y) \log(1 - \hat{y})) \\ \hat{y}=\frac{1}{1+e^{-F}} \\ \end{cases} \]

對特徵\(x\)求導,通過剝洋葱方法:

\[\frac{\partial L}{\partial F}=\frac{\partial L}{\partial \hat{y}}·\frac{\partial \hat{y}}{\partial F}=-(\frac{y}{\hat{y}}-\frac{1-y}{1-\hat{y}})·\frac{e^{-F}}{(1+e^{-F})^2} \]

由於\(\hat{y}=\frac{1}{1+e^{-F}}\),那麼\(1-\hat{y}=\frac{e^{-F}}{1+e^{-F}}\),帶入上面:

\[\frac{\partial L}{\partial F}=-(\frac{y}{\hat{y}}-\frac{1-y}{1-\hat{y}})· \hat{y}(1-\hat{y})=\hat{y}-y \]

梯度有了,那負梯度自然也計算出來了

\[y-\hat{y} \]

通過計算,負梯度=殘差,所以,在上面演示的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}")

腳本,啓動!

watermarked-gbdt_1_2

  • objective:binary表示分類任務的損失函數
  • metric:binary_logloss表示監控指標為對數損失函數,也可以換成binary_error表示誤差率
  • num_boost_round=1000:最大迭代次數
  • stopping_rounds=5:連續5輪不提升則停止
  • period=10:每10輪打印日誌

小結

給一組系統性能數據,能不能發現潛在的風險,風險判定為,日誌錯誤率為>100條

如果錯誤日誌為80條,雖然沒有告警,但是系統已經在風險邊緣了

先給一組數據,通過系統性能指標進行分類,然後再對於各時段的性能數據進行分類,看系統是否處於崩潰邊緣

聯繫我

  • 聯繫我,做深入的交流

至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...

Add a new 評論

Some HTML is okay.