Gaussian Mixture Model pada chapter sebelumnya mengajari kita membaca parameter sebagai distribusi; chapter penutup section ini menghadapkan kita ke janji yang paling sering kita klaim tanpa mengujinya: ketika classifier mengeluarkan 0,8, apakah 80% kasus semacam itu benar-benar berlabel positif? Untuk keputusan berbasis peluang — menetapkan premi, memilih ambang peninjauan manual, menghitung nilai harapan — angka yang tidak terkalibrasi menghasilkan keputusan yang salah bahkan ketika akurasinya tinggi. Di chapter ini kita mengukur kesesuaian tersebut lewat kurva kalibrasi dan Brier score, lalu memperbaikinya dengan CalibratedClassifierCV — penutup yang tepat karena alat ini bekerja persis seperti teorema Bayes: memetakan skor mentah model ke peluang yang sudah diperiksa terhadap frekuensi nyata.
Apa itu Kalibrasi #
Model terkalibrasi jika keluaran probabilitasnya cocok dengan frekuensi kejadian di lapangan: dari seluruh kasus yang diprediksi 0,8, sekitar 80% memang positif; dari yang diprediksi 0,1, sekitar 10% positif. Uji mentalnya sederhana — bayangkan mengelompokkan 100 prediksi 0,8 ke satu kantong, lalu menghitung isinya. Kalibrasi berbeda dari diskriminasi (kemampuan memisahkan kelas): model yang selalu memprediksi probabilitas dasar 0,5 pada data berimbang adalah buruk memisahkan namun sempurna terkalibrasi; model yang memisahkan tajam namun selalu terlalu yakin adalah kebalikannya. Idealnya model bagilah keduanya — dan kalibrasi bisa diperbaiki setelah modelnya jadi.
RandomForest adalah kasus klasik yang perlu diperiksa. Probabilitasnya dihitung sebagai fraksi suara pohon, dan fraksi semacam itu condong menjauh dari 0 dan 1 — pohon yang beragam jarang bulat sepakat. Akibatnya 0,3 dari model bisa berarti 0,1 yang sesungguhnya, dan 0,6 bisa berarti 0,75.
Kurva Kalibrasi dan Brier Score #
calibration_curve dari sklearn.calibration membagi prediksi ke dalam beberapa bin, lalu mengembalikan dua deret: rata-rata probabilitas prediksi per bin dan frekuensi empiris label positif per bin. Model terkalibrasi sempurna membuat kedua deret berimpit di garis diagonal. Argumen strategy="quantile" mengisi tiap bin dengan jumlah sampel yang sama (stabil secara statistik); strategy="uniform" membagi rentang [0, 1] sama lebar (bin tepi bisa nyaris kosong). Satu kebiasaan yang harus diingat: fungsi ini mengembalikan (prob_true, prob_pred) — frekuensi empiris lebih dulu — sehingga urutan penamaan variabel mudah terbalik.
Sebagai angka tunggal, Brier score adalah rata-rata kuadrat selisih probabilitas prediksi terhadap label nyata:
Brier = (1/n) Σ (p_i - y_i)²Skor ini menghukum sekaligus kalibrasi dan ketajaman pemisahan, bernilai 0 untuk prediksi sempurna dan 0,25 untuk tebakan konstan 0,5 pada data berimbang. Karena label 0/1 dan prediksi 0/1 juga dihukum kuadrat, prediksi percaya diri yang keliru dikenai denda terbesar — perilaku yang persis kita inginkan saat menilai probabilitas.
Praktik: RandomForest Sebelum dan Sesudah Kalibrasi #
Kita bekerja pada 1.200 sampel make_classification dengan label yang cukup berisik (flip_y=0.08) supaya probabilitas menengah benar-benar muncul. RandomForest dasar dilatih pada 720 sampel latih; dua versi terkalibrasi — sigmoid (Platt scaling) dan isotonic — dilatih lewat CalibratedClassifierCV dengan cv=3; seluruh penilaian dilakukan pada 480 sampel uji yang tidak pernah disentuh proses kalibrasi.
# Kalibrasi probabilitas: kurva kalibrasi, Brier score, CalibratedClassifierCV.
# Model dasar: RandomForestClassifier -- fraksi suara pohon cenderung bias.
import numpy as np
from sklearn.calibration import CalibratedClassifierCV, calibration_curve
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, brier_score_loss
from sklearn.model_selection import train_test_split
# 1) Data klasifikasi sintetis dengan label berisik (flip_y).
X, y = make_classification(
n_samples=1200, n_features=10, n_informative=4, n_redundant=2,
n_clusters_per_class=2, flip_y=0.08, random_state=42,
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.4, random_state=42, stratify=y
)
print(f"latih {len(y_train)} sampel, uji {len(y_test)} sampel")
# 2) Model dasar + dua versi terkalibrasi (dilatih ulang lewat cv=3).
dasar = RandomForestClassifier(n_estimators=300, random_state=42)
dasar.fit(X_train, y_train)
sigmoid = CalibratedClassifierCV(
estimator=dasar, method="sigmoid", cv=3
).fit(X_train, y_train)
isotonic = CalibratedClassifierCV(
estimator=dasar, method="isotonic", cv=3
).fit(X_train, y_train)
proba_dasar = dasar.predict_proba(X_test)[:, 1]
proba_sig = sigmoid.predict_proba(X_test)[:, 1]
proba_iso = isotonic.predict_proba(X_test)[:, 1]
# 3) Fraksi suara pohon: sempit di tengah, jarang benar-benar 0 atau 1.
ekstrem_dasar = float(np.mean((proba_dasar < 0.10) | (proba_dasar > 0.90)))
ekstrem_sig = float(np.mean((proba_sig < 0.10) | (proba_sig > 0.90)))
print(f"\nProporsi prediksi ekstrem (<0.10 atau >0.90):")
print(f" tanpa kalibrasi : {ekstrem_dasar:.3f}")
print(f" sigmoid : {ekstrem_sig:.3f}")
# 4) Brier score: galat kuadrat rata-rata probabilitas positif.
print("\nBrier score (makin kecil makin baik):")
print(f" tanpa kalibrasi : {brier_score_loss(y_test, proba_dasar):.4f}")
print(f" sigmoid : {brier_score_loss(y_test, proba_sig):.4f}")
print(f" isotonic : {brier_score_loss(y_test, proba_iso):.4f}")
print("\nAkurasi label (ambang 0.5):")
print(f" tanpa kalibrasi : {accuracy_score(y_test, proba_dasar >= 0.5):.4f}")
print(f" sigmoid : {accuracy_score(y_test, proba_sig >= 0.5):.4f}")
# 5) Kurva kalibrasi 8 bin kuantil: prob_prediksi vs frekuensi empiris.
def tabel_kalibrasi(nama, proba):
# calibration_curve mengembalikan (prob_true, prob_pred):
# frekuensi empiris lebih dulu, rata-rata prediksi belakangan.
frekuensi, prediksi = calibration_curve(
y_test, proba, n_bins=8, strategy="quantile"
)
gap = float(np.max(np.abs(prediksi - frekuensi)))
print(f"\nKurva kalibrasi ({nama}), 8 bin kuantil:")
print(" prob_prediksi frekuensi_empiris")
for p, e in zip(prediksi, frekuensi):
print(f" {p:>12.3f} {e:>19.3f}")
print(f" gap maksimum |prediksi - frekuensi| = {gap:.3f}")
tabel_kalibrasi("tanpa kalibrasi", proba_dasar)
tabel_kalibrasi("sigmoid", proba_sig)Output yang Dihasilkan:
latih 720 sampel, uji 480 sampel
Proporsi prediksi ekstrem (<0.10 atau >0.90):
tanpa kalibrasi : 0.315
sigmoid : 0.577
Brier score (makin kecil makin baik):
tanpa kalibrasi : 0.0968
sigmoid : 0.0913
isotonic : 0.0919
Akurasi label (ambang 0.5):
tanpa kalibrasi : 0.8792
sigmoid : 0.8833
Kurva kalibrasi (tanpa kalibrasi), 8 bin kuantil:
prob_prediksi frekuensi_empiris
0.044 0.033
0.124 0.065
0.214 0.102
0.336 0.300
0.585 0.750
0.801 0.857
0.891 0.965
0.960 0.983
gap maksimum |prediksi - frekuensi| = 0.165
Kurva kalibrasi (sigmoid), 8 bin kuantil:
prob_prediksi frekuensi_empiris
0.033 0.050
0.063 0.033
0.124 0.133
0.267 0.283
0.637 0.733
0.881 0.850
0.944 0.967
0.969 0.983
gap maksimum |prediksi - frekuensi| = 0.097Mari kita bedah hasil eksekusinya:
- Baris 22–29 (tiga model):
CalibratedClassifierCV(estimator=dasar, method=..., cv=3)menerima estimator melalui argumenestimator(sejak scikit-learn 1.2 menggantikanbase_estimator) dan melatih ulang model dasar pada tiap fold sebelum memasang lapisan kalibrasi — peta kalibrasi tidak pernah melihat data yang dipakai menilainya. - Baris 35–39 (prediksi ekstrem): tanpa kalibrasi hanya 31,5% prediksi berada di bawah 0,10 atau di atas 0,90; setelah kalibrasi sigmoid proporsinya 57,7%. Ini bukan model jadi lebih berani tanpa alasan — peta sigmoid meregangkan kembali probabilitas yang sebelumnya terjepit ke tengah oleh fraksi suara pohon.
- Baris 43–45 (Brier score): 0,0968 turun ke 0,0913 (sigmoid) dan 0,0919 (isotonic). Perbaikan terlihat sederhana sebagai angka, tetapi pada aplikasi yang memakai peluang secara langsung — misalnya penetapan premi asuransi — pemangkasan galat kuadrat sebesar ini berarti seluruh tabel keputusan bergeser ke arah yang benar.
- Baris 47–49 (akurasi label): 0,8792 menjadi 0,8833. Kalibrasi tidak menuntut model mengklasifikasi lebih baik — peta kalibrasi bersifat monoton sehingga urutan skor nyaris tak berubah; yang berubah adalah makna angkanya.
- Baris 53–64 (kurva kalibrasi): pada model dasar, bin 5 memperlihatkan prediksi rata-rata 0,585 sementara frekuensi nyatanya 0,750 — gap terbesar 0,165. Pola fraksi suara terlihat konsisten: bin 1 memprediksi 0,044 saat kenyataannya 0,033, bin 8 memprediksi 0,960 saat kenyataannya 0,983 — angka menjauh dari 0 dan 1. Setelah kalibrasi sigmoid, gap maksimum menyusut ke 0,097 dan deret prediksi–frekuensi berjalan berdampingan jauh lebih rapat.
Sigmoid vs Isotonic #
Dua metode di CalibratedClassifierCV berbeda pada bentuk peta kalibrasinya:
| Aspek | method="sigmoid" | method="isotonic" |
|---|---|---|
| Bentuk peta | Regresi logistik (Platt scaling) | Fungsi bertahap monoton naik (isotonic regression) |
| Parameter bebas | 2 (kemiringan, intersep) | Banyak — satu segmen per kelompok data |
| Fleksibilitas | Rendah, halus | Tinggi, mengikuti data |
| Kebutuhan data | Aman pada ratusan sampel | Ideal di atas ~1.000 sampel per kelas |
| Risiko | Terlalu sederhana saat kurva melengkung tajam | Terlalu rapat ke data (overfitting) saat kecil |
Pada contoh kita keduanya berakhir nyaris seri (0,0913 vs 0,0919) — dengan 720 sampel latih, fleksibilitas isotonic belum dibayar lunas. Semakin kecil data, semakin kuat alasan memilih sigmoid.
Kapan Kalibrasi Diperlukan #
Kalibrasi wajib dipertimbangkan ketika probabilitasnya dikonsumsi langsung: penetapan premi atau limit kredit, ambang keputusan berbasis nilai harapan, peringkat berpeluang pada sistem rekomendasi, sampai meta-features untuk model stacking. Sebaliknya, kalau downstream hanya membaca urutan — AUC, pemeringkatan pencarian, pemilihan top-k — peta monoton tidak mengubah urutan dan kalibrasi jadi tidak mendesak. Aturan praktisnya satu kalimat: jika angkanya dijumlah, kalibrasi penting; jika hanya urutannya yang dipakai, kalibrasi opsional.
Section Probabilistic Machine Learning sampai di sini lengkap: kita memandang model sebagai distribusi, memperbarui keyakinan lewat Bayes, menaksir parameter lewat likelihood, memodelkan data sebagai campuran, dan memastikan probabilitas keluaran bisa dipercaya. Benang merah berikutnya tetap soal kejadian langka: bagaimana menandai titik yang menurut model hampir mustahil terjadi? Itu pembukaan Section Anomaly Detection, dimulai dari Chapter Konsep Anomaly Detection.
Referensi Resmi #
- Probability calibration — scikit-learn User Guide — penjelasan resmi sigmoid, isotonic, dan diagram kalibrasi RandomForest.
- sklearn.calibration.CalibratedClassifierCV — API Reference
— argumen
estimator,method, dancvyang dipakai pada contoh. - sklearn.calibration.calibration_curve — API Reference
— urutan keluaran
prob_truedanprob_predbeserta strategi bin. - sklearn.metrics.brier_score_loss — API Reference — definisi resmi Brier score.