彩筆運(yùn)維勇闖機(jī)器學(xué)習(xí)--GBDT
前言
本文討論的GBDT算法,也是基于決策樹(shù)
開(kāi)始探索
scikit-learn
老規(guī)矩,先上代碼,看看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))
腳本!啟動(dòng):

深入理解GBDT
GBDT全稱,梯度提升決策樹(shù)(Gradient Boosting Decision Tree),通過(guò)“不斷擬合上一步誤差”的方式來(lái)迭代構(gòu)建模型,每一步都用一棵新的決策樹(shù)來(lái)逼近當(dāng)前的殘差,從而不斷提升整體模型性能
不斷的迭代決策樹(shù),通過(guò)損失函數(shù)的負(fù)梯度作為每一輪迭代的優(yōu)化目標(biāo),每一棵決策樹(shù)糾正前一棵樹(shù)的誤差,最終將所有樹(shù)的預(yù)測(cè)結(jié)果加權(quán)求和得到最終輸出
基本思路
1)首先計(jì)算出初始概率:
預(yù)測(cè)值計(jì)算公式(logit公式): $$F=log(\frac{p}{1-p})$$
概率計(jì)算公式(sigmoid公式): $$P=\frac{1}{1+e^{-F}}$$
2)計(jì)算殘差,通過(guò)一棵回歸樹(shù)擬合該殘差
3)再次計(jì)算概率
該輪預(yù)測(cè)值: $$F_t(x)=F_{t-1}(x)+η·T_t(x)$$
- \(F_t(x)\):當(dāng)前輪次對(duì)x的預(yù)測(cè)值
- \(F_{t-1}\):上一輪次對(duì)x的預(yù)測(cè)值
- \(η\):學(xué)習(xí)率,每輪更新的步長(zhǎng)
- \(T_t(x)\):每輪訓(xùn)練的回歸樹(shù),用來(lái)擬合上一輪訓(xùn)練的殘差
計(jì)算出概率: $$P=\frac{1}{1+e^{-F}}$$
4)計(jì)算殘差、擬合殘差、求樹(shù)的梯度。循環(huán)往復(fù),直至收斂
舉例說(shuō)明
下面以二分類任務(wù)為例,有10個(gè)樣本,6個(gè)正類(1),4個(gè)負(fù)類(0)
1)計(jì)算初始概率
初始預(yù)測(cè)值:所有樣本的初始預(yù)測(cè)值為正類的對(duì)數(shù)幾率,通過(guò)logit函數(shù)計(jì)算:$$F = log( \frac{p}{1-p}) = log(\frac{0.6}{0.4}) \approx 0.4055 $$
帶入到sigmoid計(jì)算預(yù)測(cè)概率:
2)計(jì)算殘差,所謂殘差,是單個(gè)樣本點(diǎn)的預(yù)測(cè)值與真實(shí)值之間的差
正類樣本(1)的殘差:\(r_i=1-0.6=0.4\)
負(fù)類樣本(0)的殘差:\(r_i=0-0.6=-0.6\)
3)訓(xùn)練第一棵決策回歸樹(shù)
4)再次計(jì)算概率
假設(shè)學(xué)習(xí)率\(\eta=0.1\),更新模型預(yù)測(cè):
- 正類預(yù)測(cè):\(F_{正類}=0.4055+0.1×0.4 = 0.4455\)
- 負(fù)類預(yù)測(cè):\(F_{負(fù)類}=0.4055+0.1×(?0.6) = 0.3455\)
計(jì)算預(yù)測(cè)概率
更新預(yù)測(cè)概率\(P\)
- 正類概率:\(P_{正類}=\frac{1}{1+e^{-0.4455}} \approx 0.6095\)
- 負(fù)類概率:\(P_{負(fù)類}=\frac{1}{1+e^{-0.3455}} \approx 0.5854\)
由于設(shè)置了迭代次數(shù):n_estimators=5,繼續(xù)迭代
4)計(jì)算二輪殘差
- 正類殘差:\(r_{正類}=1-0.6095=0.3905\)
- 負(fù)類殘差:\(r_{負(fù)類}=0-0.5854=?0.5854\)
5)繼續(xù)訓(xùn)練第二棵決策回歸樹(shù)
- 模型預(yù)測(cè)\(F\)
- 正類預(yù)測(cè):\(F_{正類}=0.4455+0.1×0.3905 \approx 0.4846\)
- 負(fù)類預(yù)測(cè):\(F_{負(fù)類}=0.3455+0.1×(-0.5854) \approx 0.287\)
- 預(yù)測(cè)概率\(P\)
- 正類概率:\(P_{正類} \approx 0.6188\)
- 負(fù)類概率:\(P_{負(fù)類} \approx 0.5713\)
6)不斷迭代,直至n_estimators=5
默認(rèn)使用最后一次的參數(shù),有位彥祖就說(shuō),這不合理啊,有可能中途第三次訓(xùn)練的參數(shù)擬合度更高,為什么不用第三次的參數(shù)呢,這個(gè)問(wèn)題可以使用早停法解決,后面會(huì)說(shuō)
回歸樹(shù)
有位彥祖問(wèn)了,我明明是做分類問(wèn)題,為什么要用回歸樹(shù)來(lái)擬合殘差?“回歸”這個(gè)詞到底指的是什么?
我們用的決策樹(shù),是回歸決策樹(shù),是為了擬合殘差。之前討論過(guò)決策樹(shù),但是是分類決策樹(shù),這里簡(jiǎn)單描述一下回歸決策樹(shù)
直接上一個(gè)例子,更加明白。比如現(xiàn)在有一組樣本
| x | y |
|---|---|
| 1 | 5 |
| 2 | 6 |
| 3 | 7 |
| 4 | 15 |
| 5 | 16 |
| 6 | 17 |
為了簡(jiǎn)單說(shuō)明,假設(shè)我們的樹(shù)深度只有1
1)選擇切分點(diǎn),兩個(gè)樣本中間
x = [1 2 3 4 5 6] => [1.5 2.5 3.5 4.5 5.5]
假設(shè)選擇3.5的切分點(diǎn)
2)計(jì)算損失函數(shù)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\)
-
加權(quán)總MSE:\(\frac{3}{6}·0.6667 + \frac{3}{6}·0.6667 = 0.6667\)
也可以選擇其他的分割點(diǎn),然后計(jì)算MSE,選擇最優(yōu)分割點(diǎn)
3)擬合樹(shù)
殘差與梯度
根據(jù)二分類的交叉熵公式以及求概率公式
對(duì)特征\(x\)求導(dǎo),通過(guò)剝洋蔥方法:
由于\(\hat{y}=\frac{1}{1+e^{-F}}\),那么\(1-\hat{y}=\frac{e^{-F}}{1+e^{-F}}\),帶入上面:
梯度有了,那負(fù)梯度自然也計(jì)算出來(lái)了
通過(guò)計(jì)算,負(fù)梯度=殘差,所以,在上面演示的GBDT二分類任務(wù)中,就是沿著負(fù)梯度(殘差)方向不斷的尋找
早停法
顧名思義,就是發(fā)現(xiàn)模型性能下降的時(shí)候,立刻停止訓(xùn)練,并且保留性能最高的那組參數(shù)
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}")
腳本,啟動(dòng)!

objective:binary表示分類任務(wù)的損失函數(shù)metric:binary_logloss表示監(jiān)控指標(biāo)為對(duì)數(shù)損失函數(shù),也可以換成binary_error表示誤差率num_boost_round=1000:最大迭代次數(shù)stopping_rounds=5:連續(xù)5輪不提升則停止period=10:每10輪打印日志
小結(jié)
給一組系統(tǒng)性能數(shù)據(jù),能不能發(fā)現(xiàn)潛在的風(fēng)險(xiǎn),風(fēng)險(xiǎn)判定為,日志錯(cuò)誤率為>100條
如果錯(cuò)誤日志為80條,雖然沒(méi)有告警,但是系統(tǒng)已經(jīng)在風(fēng)險(xiǎn)邊緣了
先給一組數(shù)據(jù),通過(guò)系統(tǒng)性能指標(biāo)進(jìn)行分類,然后再對(duì)于各時(shí)段的性能數(shù)據(jù)進(jìn)行分類,看系統(tǒng)是否處于崩潰邊緣
聯(lián)系我
- 聯(lián)系我,做深入的交流
![]()
至此,本文結(jié)束
在下才疏學(xué)淺,有撒湯漏水的,請(qǐng)各位不吝賜教...
本文來(lái)自博客園,作者:it排球君,轉(zhuǎn)載請(qǐng)注明原文鏈接:http://www.rzrgm.cn/MrVolleyball/p/19112957


浙公網(wǎng)安備 33010602011771號(hào)