Random forest menekan varians dengan merata-ratakan banyak pohon yang saling menutupi. Gradient boosting menempuh arah yang hampir kebalikannya: satu model sederhana dilatih lebih dulu, galatnya diukur, lalu model kecil berikutnya dilatih khusus untuk memperbaiki galat tersebut — dan proses koreksi ini berantai puluhan hingga ratusan kali. Hasil akhirnya bukan rata-rata sekelompok model sejajar, melainkan jumlahan bertahap yang makin lama makin dekat ke pola sebenarnya. Pada Chapter ini kita akan membongkar mekanisme residual tersebut dengan tangan — lima iterasi boosting murni NumPy yang bisa Anda ikuti baris demi baris — sebelum membandingkannya dengan GradientBoostingRegressor dari scikit-learn dan melihat trade-off learning_rate yang menjadi jantung tuning model boosting.
Koreksi Berantai atas Residual #
Mulailah dari model paling sederhana: konstanta F0 sebesar rata-rata target. Prediksi awal ini jelas keliru di hampir semua titik, dan selisihnya — residual y - F(x) — adalah peta kekurangan model saat ini. Gradient boosting kemudian melatih pohon kecil h1 untuk memprediksi residual itu, bukan target aslinya. Prediksi gabungan diperbarui, residual baru dihitung ulang, pohon berikutnya belajar dari sisa galat yang masih ada, demikian seterusnya. Untuk loss kuadrat, residual memang arah penurunan loss yang paling curam; pada loss lain (misalnya log-loss klasifikasi) yang dipakai adalah pseudo-residual — gradien loss terhadap prediksi — namun idenya sama persis.
Setelah M koreksi, model final berbentuk model aditif:
F(x) = F0 + eta * h1(x) + eta * h2(x) + ... + eta * hM(x)Koefisien eta adalah learning rate (scikit-learn menyebutnya shrinkage): skala kontribusi tiap pohon terhadap jumlahan. Nilai kecil membuat tiap koreksi hanya menggeser prediksi sedikit — langkah kecil yang hati-hati, dengan ruang bagi koreksi berikutnya mengoreksinya kembali.
Trade-off Learning Rate dan Jumlah Pohon #
learning_rate dan n_estimators tidak bisa dituning terpisah karena keduanya mengendalikan besaran yang sama: seberapa cepat jumlahan mengejar target. Learning rate kecil dengan pohon sedikit menghasilkan underfit — model belum sempat menyusun koreksi yang cukup. Learning rate besar mempercepat konvergensi di data latih, tetapi tiap pohon membawa pengaruh kasar yang mudah mengikuti derau; digabung dengan pohon banyak, kombinasi ini berisiko overfit. Kombinasi yang lazim dan aman: learning_rate kecil (0,05–0,1) dikawal n_estimators besar (ratusan hingga ribuan), dengan pemantauan validasi.
Mekanisme pemantauannya ada bawaan scikit-learn: early stopping. Dengan n_iter_no_change=10 dan validation_fraction=0.2, pelatihan menyisihkan 20% data latih sebagai validation set internal, dan berhenti lebih awal ketika skor validation tidak membaik selama 10 iterasi berturut-turut. Anggaran n_estimators bisa dipasang besar — pelatihan berhenti sendiri saat tambahan pohon tidak lagi membawa perbaikan.
Pohon Dangkal untuk Bias #
Kedalaman pohon di gradient boosting lazimnya 3–5 tingkat — jauh lebih dangkal daripada pohon random forest yang tumbuh bebas. Alasannya kembali ke dekomposisi galat: boosting membangun bias rendah secara bertahap, bukan sekaligus. Satu pohon dangkal sendirian underfit parah (bias tinggi); seratus koreksi berantai di atasnya yang menurunkan bias sambil menjaga tiap langkah kecil. Sebaliknya, memberi pohon yang dalam per koreksi justru berbahaya — tiap koreksi menjadi terlalu ekspresif sehingga mampu menghafal derau pada residual, dan kesalahan satu iterasi menular ke iterasi berikutnya.
| Aspek | Random Forest | Gradient Boosting |
|---|---|---|
| Pola latih | Paralel; pohon saling independen | Sekuensial; pohon ke-i memperbaiki gabungan sebelumnya |
| Galat yang ditekan | Varians lewat rata-rata pohon dalam | Bias lewat koreksi berantai pohon dangkal |
| Kedalaman pohon | Dalam (max_depth=None lazim) | Dangkal (3–5) |
| Sensitivitas hyperparameter | Rendah; tambah pohon hampir selalu aman | Tinggi; learning_rate dan n_estimators saling mengunci |
| Risiko khas | Overfit ringan bila derau dominan | Overfit cepat bila learning rate besar + pohon banyak |
Eksperimen: Boosting Manual Lima Iterasi #
Tidak ada cara lebih jernih memahami boosting selain menulis mesinnya sendiri. Skrip berikut membangun 40 titik data nonlinier, lalu menjalankan boosting tangan: lima stump (max_depth=1) yang masing-masing belajar dari residual terkini.
# Gradient Boosting: koreksi berantai atas sisa galat (residual).
# Bagian 1: boosting manual 5 iterasi pada regresi kecil (NumPy + stump).
# Bagian 2: GradientBoostingRegressor pada data yang sama.
# Bagian 3: random forest vs gradient boosting pada klasifikasi.
# Bagian 4: trade-off learning_rate melawan jumlah pohon.
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import (GradientBoostingRegressor,
GradientBoostingClassifier,
RandomForestClassifier)
# --- Bagian 1: boosting manual dengan lima stump ----------------------
# Model F(x) dibangun bertahap: tiap stump belajar dari residual
# (selisih target dengan prediksi gabungan saat ini).
rng = np.random.default_rng(42)
X_reg = np.sort(rng.uniform(0, 6, 40)).reshape(-1, 1)
derau = rng.normal(0, 0.15, 40)
y_reg = 1.5 * np.sin(X_reg.ravel()) + 0.5 + derau
tingkat_belajar = 0.5
prediksi_gabungan = np.full_like(y_reg, y_reg.mean())
print("Bagian 1 - boosting manual (regresi, 5 iterasi):")
print(f" {'norma derau murni (batas bawah)':<38} : "
f"{np.linalg.norm(derau):.3f}")
print(f" {'norma residual awal (model konstanta)':<38} : "
f"{np.linalg.norm(y_reg - prediksi_gabungan):.3f}")
for iterasi in range(1, 6):
residual = y_reg - prediksi_gabungan
stump = DecisionTreeRegressor(max_depth=1, random_state=42)
stump.fit(X_reg, residual)
prediksi_gabungan = (prediksi_gabungan
+ tingkat_belajar * stump.predict(X_reg))
print(f" {'norma residual setelah iterasi ' + str(iterasi):<38} : "
f"{np.linalg.norm(y_reg - prediksi_gabungan):.3f}")
# --- Bagian 2: GradientBoostingRegressor pada data sama ---------------
gbm = GradientBoostingRegressor(n_estimators=5, learning_rate=0.5,
max_depth=1, random_state=42)
gbm.fit(X_reg, y_reg)
pred_sklearn = gbm.predict(X_reg)
print("\nBagian 2 - GradientBoostingRegressor (parameter serupa):")
print(f" {'MSE boosting manual':<38} : "
f"{np.mean((y_reg - prediksi_gabungan) ** 2):.4f}")
print(f" {'MSE GradientBoostingRegressor':<38} : "
f"{np.mean((y_reg - pred_sklearn) ** 2):.4f}")
print(f" {'selisih maksimum kedua prediksi':<38} : "
f"{np.max(np.abs(prediksi_gabungan - pred_sklearn)):.6f}")
# --- Bagian 3: random forest vs gradient boosting ----------------------
X_kls, y_kls = make_classification(n_samples=200, n_features=16,
n_informative=6, n_redundant=3,
flip_y=0.08, class_sep=0.8,
random_state=42)
X_latih, X_uji, y_latih, y_uji = train_test_split(
X_kls, y_kls, test_size=60, random_state=42)
hutan_acak = RandomForestClassifier(n_estimators=300, random_state=42)
boosting = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1,
max_depth=3, random_state=42)
print("\nBagian 3 - klasifikasi: random forest vs gradient boosting:")
print(f" {'model':<38} {'latih':>6} {'uji':>6}")
for nama, model in [("random forest (300 pohon)", hutan_acak),
("gradient boosting (100, lr=0.1)", boosting)]:
model.fit(X_latih, y_latih)
print(f" {nama:<38} {model.score(X_latih, y_latih):>6.3f} "
f"{model.score(X_uji, y_uji):>6.3f}")
# --- Bagian 4: trade-off learning_rate vs n_estimators -----------------
print("\nBagian 4 - efek learning_rate dengan jumlah pohon yang sama:")
print(f" {'model':<38} {'latih':>6} {'uji':>6}")
for lr, n_pohon in [(0.05, 30), (0.5, 30), (0.05, 200)]:
model = GradientBoostingClassifier(n_estimators=n_pohon,
learning_rate=lr, max_depth=3,
random_state=42)
model.fit(X_latih, y_latih)
nama = f"gradient boosting (lr={lr}, {n_pohon} pohon)"
print(f" {nama:<38} {model.score(X_latih, y_latih):>6.3f} "
f"{model.score(X_uji, y_uji):>6.3f}")Output yang Dihasilkan:
Bagian 1 - boosting manual (regresi, 5 iterasi):
norma derau murni (batas bawah) : 0.684
norma residual awal (model konstanta) : 7.207
norma residual setelah iterasi 1 : 4.140
norma residual setelah iterasi 2 : 2.872
norma residual setelah iterasi 3 : 2.232
norma residual setelah iterasi 4 : 2.025
norma residual setelah iterasi 5 : 1.879
Bagian 2 - GradientBoostingRegressor (parameter serupa):
MSE boosting manual : 0.0883
MSE GradientBoostingRegressor : 0.0883
selisih maksimum kedua prediksi : 0.000000
Bagian 3 - klasifikasi: random forest vs gradient boosting:
model latih uji
random forest (300 pohon) 1.000 0.717
gradient boosting (100, lr=0.1) 1.000 0.683
Bagian 4 - efek learning_rate dengan jumlah pohon yang sama:
model latih uji
gradient boosting (lr=0.05, 30 pohon) 0.936 0.600
gradient boosting (lr=0.5, 30 pohon) 1.000 0.717
gradient boosting (lr=0.05, 200 pohon) 1.000 0.717Mari kita telaah bagian-bagian kunci skrip tersebut:
- Baris 18–21 (data regresi sintetis):
rngberseed 42 membangkitkan 40 titik pada rentang 0–6 dengan target1.5·sin(x) + 0.5plus derau Gaussian 0,15. Arrayderaudisimpan terpisah agar normanya bisa dicetak sebagai batas bawah teoretis. - Baris 23–24 (inisialisasi
F0):np.full_likemengisi prediksi awal dengan rata-rata target — konstanta terbaik untuk loss kuadrat, persis inisialisasi bawaanGradientBoostingRegressor. - Baris 30–37 (satu iterasi boosting): baris 31 menghitung residual; baris 32–33 melatih stump satu pemecahan pada residual tersebut; baris 34–35 menambahkan kontribusi stump (dikali
tingkat_belajar) ke prediksi gabungan; baris 36–37 mencetak norma residual setelah pembaruan. - Baris 40–50 (validasi terhadap pustaka):
GradientBoostingRegressordipanggil dengan parameter serupa (n_estimators=5,learning_rate=0.5,max_depth=1); MSE dan selisih maksimum prediksi kedua versi dicetak untuk membuktikan keduanya menghitung hal yang sama. - Baris 53–58 (dataset klasifikasi tetap):
make_classification(random_state=42)denganflip_y=0.08danclass_sep=0.8menghasilkan masalah dengan derau label yang cukup nyata — kondisi di mana trade-off hyperparameter boosting terlihat. - Baris 60–69 (dua keluarga berhadapan): random forest dan gradient boosting dilatih pada split yang sama, akurasi latih dan uji dicetak berdampingan.
- Baris 74–81 (sweep learning rate): tiga kombinasi diuji —
lr=0.05dengan 30 pohon,lr=0.5dengan 30 pohon, danlr=0.05dengan 200 pohon — untuk memperlihatkan trade-off secara langsung.
Membaca Hasil Eksperimen #
Bagian 1 adalah intuisi utamanya: norma residual turun monoton dari 7,207 (model konstanta) ke 4,140 setelah koreksi pertama, lalu 2,872, 2,232, 2,025, dan 1,879 setelah koreksi kelima. Perhatikan batas bawah pada baris pertama: norma derau murni 0,684. Residual tidak mungkin sehat turun di bawah angka itu tanpa mulai menghafal derau; lima koreksi hati-hati membawa kita mendekatinya tanpa melampauinya. Bagian 2 mengonfirmasi implementasi manual tersebut: MSE kedua versi sama (0,0883) dan selisih maksimum prediksi 0,000000 — mesin lima baris kita identik dengan GradientBoostingRegressor pada parameter yang sama.
Bagian 3 memperlihatkan realitas yang jujur: pada 200 sampel ber-label bising, random forest (0,717) unggul tipis atas gradient boosting dengan pengaturan standar (0,683). Gradient boosting memang bukan pemenang otomatis — kekuatannya baru muncul penuh setelah learning_rate dan n_estimators dikawal bersama. Bagian 4 menutup buktinya: dengan hanya 30 pohon, lr=0.05 nyaris tak bergerak (akurasi uji 0,600; akurasi latih 0,936 — koreksinya belum selesai), sementara lr=0.5 pada 30 pohon yang sama langsung mencapai 0,717. Namun beri 200 pohon pada lr=0.05, akurasi uji kembali ke 0,717 — langkah kecil mengejar ketinggalan lewat jumlah langkah. Itulah trade-off-nya: langkah besar cepat tetapi kasar, langkah kecil lambat tetapi lebih terkontrol.
Algoritme boosting yang kita rakit secara manual ini ternyata sangat cocok untuk dioptimalkan secara teknik — dan di titik itulah XGBoost memasuki panggung. Chapter berikutnya menyusun ulangan konsep yang sama dengan regularisasi eksplisit, gradien orde kedua, dan sejumlah optimasi sistem yang menjadikannya rujukan kompetisi data selama bertahun-tahun.
Referensi Resmi #
- Gradient Boosted Trees — scikit-learn User Guide — penjelasan resmi mekanisme gradient boosting, shrinkage, dan early stopping.
- GradientBoostingClassifier — scikit-learn API — dokumentasi hyperparameter yang dipakai pada contoh.
- GradientBoostingRegressor — scikit-learn API — estimator regresi yang kita bahas tuntas pada Bagian 1 dan 2.