Buka papan peringkat kompetisi data tabular di Kaggle dan lihat solusi para juara. Hampir semuanya berdiri di atas satu library: XGBoost. Sejak dirilis 2014, library ini terus jadi senjata default untuk data berbentuk tabel karena cepat, akurat, dan jarang butuh setting macam-macam. Kita akan bangun model klasifikasi tumor payudara dari nol — bandingkan dengan baseline logistic regression, baca feature importance, lalu tuning. Bukan biar menang di dataset yang mudah ini, tapi biar kamu pegang workflow lengkapnya.

Kenapa XGBoost, Bukan Sekadar Decision Tree

XGBoost adalah singkatan dari eXtreme Gradient Boosting. Cara kerjanya: dia melatih banyak decision tree kecil secara berurutan, dan setiap tree baru fokus memperbaiki kesalahan tree sebelumnya. Tree pertama menebak kasar, tree kedua belajar dari data yang masih salah ditebak, tree ketiga dari sisa kesalahan berikutnya, dan seterusnya. Prediksi akhirnya adalah penjumlahan tebakan semua tree itu.

Kapan XGBoost lebih unggul daripada neural network? Saat datamu tabular dengan ukuran menengah (ribuan sampai jutaan baris) dan kamu butuh hasil bagus dalam hitungan menit, bukan berjam-jam. XGBoost juga tahan terhadap missing value dan menangani fitur campuran numerik-kategorikal tanpa banyak preprocessing.

Siapkan Environment

Instal dulu dependensinya. Saya pakai Python 3.11, xgboost 2.1, dan scikit-learn 1.5 di tutorial ini.

bash
pip install xgboost scikit-learn pandas matplotlib

Dataset dan Baseline

Kita pakai dataset breast cancer bawaan scikit-learn: 569 sampel, 30 fitur numerik, dan label biner malignant/benign. Sebelum lompat ke XGBoost, latih baseline dulu supaya ada angka pembanding. Kalau kamu belum kenal logistic regression atau cross-validation, saya sudah bahas dasarnya di tutorial klasifikasi dengan scikit-learn.

python
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline

X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

baseline = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
scores = cross_val_score(baseline, X_train, y_train, cv=5, scoring="accuracy")
print(f"Baseline CV accuracy: {scores.mean():.4f} (+/- {scores.std():.4f})")

Di mesin saya, baseline logistic regression menghasilkan akurasi cross-validation sekitar 0.980. Angka itu hampir mentok karena dataset breast cancer memang kecil dan linear. Default XGBoost malah bisa berada di bawah baseline — kita pakai dataset ini justru supaya kamu melihat prosesnya, bukan karena XGBoost dijamin menang. Nilai asli XGBoost baru kelihatan di data tabular yang besar dan berantakan, tempat logistic regression mentok di angka 0.70-an.

Latih Model XGBoost Pertama

Sekarang latih model XGBoost dengan parameter yang masuk akal sebagai titik awal. max_depth=3 artinya tiap tree maksimal sedalam 3 level — cukup dangkal untuk mencegah overfitting, cukup dalam untuk menangkap pola.

python
import xgboost as xgb
from sklearn.metrics import accuracy_score, classification_report

model = xgb.XGBClassifier(
    n_estimators=100,
    max_depth=3,
    learning_rate=0.1,
    random_state=42,
    eval_metric="logloss",
)
model.fit(X_train, y_train)

y_pred = model.predict(X_test)
print(f"XGBoost accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred, target_names=["malignant", "benign"]))

learning_rate 0.1 dengan 100 tree adalah kombinasi yang aman untuk mulai. Kalau kamu kecilkan learning_rate ke 0.01, model butuh lebih banyak tree (misal 1000) untuk mencapai akurasi serupa, tapi hasil akhirnya biasanya sedikit lebih halus.

Feature Importance: Fitur Mana yang Paling Berpengaruh

Salah satu keunggulan XGBoost dibanding model black-box: dia menghitung seberapa besar tiap fitur mengurangi error, lalu hasilnya bisa kita plot. Parameter importance_type="gain" mengukur kontribusi fitur berdasarkan penurunan loss, bukan sekadar berapa kali fitur dipakai.

python
import matplotlib.pyplot as plt

xgb.plot_importance(model, importance_type="gain", max_num_features=10)
plt.tight_layout()
plt.show()

Dari plot ini biasanya muncul fitur seperti worst perimeter, worst radius, atau mean concave points di posisi teratas — masuk akal, karena tumor ganas punya ukuran dan bentuk yang tidak beraturan. Fitur yang nyaris tidak berkontribusi bisa kamu buang untuk membuat model lebih ringan dan lebih cepat.

Parameter default jarang yang terbaik. Grid search mencoba semua kombinasi dari kisi yang kamu tentukan. Kombinasi di bawah ini ada 72 buah, tiap kombinasi divalidasi 5-fold, jadi total 360 kali fitting — pakai n_jobs=-1 supaya semua core CPU ikut kerja. Kalau kombinasi makin banyak, Optuna jauh lebih efisien daripada brute-force seperti ini.

python
from sklearn.model_selection import GridSearchCV

param_grid = {
    "max_depth": [3, 5, 7],
    "learning_rate": [0.01, 0.1, 0.3],
    "n_estimators": [100, 300],
    "subsample": [0.8, 1.0],
    "colsample_bytree": [0.8, 1.0],
}

gs = GridSearchCV(
    xgb.XGBClassifier(random_state=42, eval_metric="logloss"),
    param_grid,
    cv=5,
    scoring="accuracy",
    n_jobs=-1,
    verbose=1,
)
gs.fit(X_train, y_train)

print(f"Best params: {gs.best_params_}")
print(f"Best CV accuracy: {gs.best_score_:.4f}")

subsample dan colsample_bytree adalah dua parameter yang sering dilupakan. Keduanya mengambil sampel acak dari baris dan kolom untuk tiap tree, yang menambah variasi antar tree dan mencegah overfitting. Nilai 0.8 artinya tiap tree hanya melihat 80% data.

Early Stopping: Berhenti Sebelum Overfitting

Semakin banyak tree, model makin bisa hafal data training — sampai titik tertentu malah merusak performa di data baru. Early stopping menghentikan training saat metrik di validation set berhenti membaik selama N iterasi berturut-turut. Perhatikan: saya memisahkan validation set dari training, bukan memakai test set. Memakai test set untuk early stopping adalah bentuk kebocoran data.

python
X_train2, X_val, y_train2, y_val = train_test_split(
    X_train, y_train, test_size=0.2, random_state=42, stratify=y_train
)

model = xgb.XGBClassifier(
    n_estimators=1000,
    learning_rate=0.1,
    max_depth=5,
    early_stopping_rounds=20,
    eval_metric="logloss",
    random_state=42,
)
model.fit(
    X_train2, y_train2,
    eval_set=[(X_val, y_val)],
    verbose=False,
)

print(f"Best iteration: {model.best_iteration}")
print(f"Final accuracy: {accuracy_score(y_test, model.predict(X_test)):.4f}")

model.best_iteration menunjukkan jumlah tree terbaik yang ditemukan, bisa jauh di bawah n_estimators=1000. Di dataset ini, early stopping biasanya berhenti sebelum 100 tree karena model sudah konvergen.

eval_metric wajib disetel, kalau tidak XGBoost versi terbaru akan memunculkan peringatan. Untuk klasifikasi biner pakai logloss atau auc; untuk regresi pakai rmse. Metrik ini juga dipakai untuk menentukan kapan early stopping berhenti.

Simpan dan Muat Model

Setelah puas dengan hasilnya, simpan model supaya bisa dipakai di aplikasi tanpa harus latih ulang. Kalau kamu melacak banyak eksperimen, simpan juga parameter dan metrik tiap run ke MLflow supaya tidak bingung mana model yang terbaik.

python
import joblib

joblib.dump(gs.best_estimator_, "xgboost_model.joblib")

loaded = joblib.load("xgboost_model.joblib")
print(f"Loaded model accuracy: {accuracy_score(y_test, loaded.predict(X_test)):.4f}")

Coba sekarang: unduh dataset Titanic dari Kaggle, ganti eval_metric jadi auc, dan lihat apakah XGBoost mengalahkan baseline logistic regression kamu. Kalau mau naik kelas, coba multi-class atau regresi — tinggal ganti objective dan metriknya, sisanya sama persis.