Evaluasi Model dan Pemilihan Metrik: Panduan Machine Learning untuk Pemula #3
Setelah model selesai dilatih, muncul pertanyaan yang kelihatannya sederhana: modelnya bagus atau tidak? Jawabannya ternyata tidak sesederhana melihat satu angka.
Model dengan akurasi 99 persen bisa jadi sama sekali tidak berguna. Model dengan akurasi 70 persen bisa jadi sangat berharga. Semuanya tergantung masalah apa yang sedang diselesaikan dan kesalahan jenis apa yang paling merugikan.
Artikel ini membahas cara mengukur performa model dengan benar. Fokusnya bukan menghafal rumus, tapi memahami kapan memakai ukuran yang mana dan kenapa.
Daftar Isi
- Kenapa Memilih Metrik Itu Penting
- Istilah Dasar yang Perlu Dipahami
- Menyiapkan Data dan Model Contoh
- Confusion Matrix: Fondasi Semua Metrik Klasifikasi
- Metrik Klasifikasi Satu per Satu
- Probabilitas dan Ambang Keputusan
- ROC-AUC dan PR-AUC
- Metrik untuk Regresi
- Cara Mengukur yang Benar
- Panduan Memilih Metrik
- Kesalahan Pemula yang Sering Terjadi
Kenapa Memilih Metrik Itu Penting
Analogi Sederhana
Bayangkan Anda menilai keberhasilan sebuah restoran. Kalau ukurannya jumlah pengunjung, restoran yang menjual makanan murah tapi tidak enak bisa menang. Kalau ukurannya keuntungan, restoran mahal dengan sedikit pelanggan bisa menang. Kalau ukurannya kepuasan pelanggan, hasilnya bisa berbeda lagi.
Tidak ada ukuran yang salah. Yang salah adalah memakai ukuran yang tidak sesuai dengan tujuan sebenarnya.
Begitu juga dengan model machine learning. Memilih metrik yang keliru berarti Anda mengoptimalkan hal yang salah selama berminggu-minggu tanpa sadar.
Cerita Kasus: Akurasi 99 Persen yang Tidak Berguna
Sebuah bank ingin mendeteksi transaksi penipuan. Dari 10.000 transaksi, hanya 100 yang merupakan penipuan, yaitu 1 persen.
Seorang pemula membuat model dan hasilnya akurasi 99 persen. Terdengar luar biasa.
Padahal model itu ternyata menjawab "bukan penipuan" untuk semua transaksi tanpa kecuali. Karena 99 persen transaksi memang bukan penipuan, tebakan malas itu otomatis benar 99 persen.
Model tersebut tidak pernah berhasil menemukan satu pun penipuan. Nilainya nol bagi bank, tapi angkanya terlihat hebat.
Inilah kenapa memahami metrik jauh lebih penting daripada mengejar angka yang tinggi.
Pertanyaan yang Harus Dijawab Sebelum Memilih Metrik
Sebelum menulis kode evaluasi, jawab dulu tiga pertanyaan ini.
Apa yang sedang diprediksi? Kategori atau angka. Ini menentukan kelompok metrik mana yang dipakai.
Apakah jumlah tiap kelas seimbang? Kalau satu kelas jauh lebih sedikit, akurasi langsung tidak layak dipakai.
Kesalahan mana yang lebih merugikan? Salah menuduh orang yang tidak bersalah, atau melewatkan orang yang benar-benar bersalah? Jawaban ini yang paling menentukan.
Istilah Dasar yang Perlu Dipahami
Kelas Positif dan Negatif
Dalam klasifikasi dua kelas, salah satu kelas disebut positif dan lainnya negatif.
Istilah ini sering membingungkan pemula karena terdengar seperti "baik" dan "buruk". Padahal maksudnya bukan itu. Kelas positif adalah kelas yang ingin kita deteksi atau temukan, meskipun isinya hal buruk.
Contohnya, dalam deteksi penipuan, "penipuan" adalah kelas positif. Dalam deteksi penyakit, "sakit" adalah kelas positif.
Dalam kode, kelas positif biasanya diberi angka 1 dan kelas negatif angka 0.
Data Seimbang dan Tidak Seimbang
Data seimbang artinya jumlah tiap kelas kira-kira sama, misalnya 50 banding 50.
Data tidak seimbang artinya satu kelas jauh lebih sedikit, misalnya 1 banding 99. Ini kondisi yang sangat umum di dunia nyata: penipuan jarang, penyakit langka jarang, mesin rusak jarang.
Sebagian besar jebakan dalam evaluasi model muncul dari data tidak seimbang.
Probabilitas dan Ambang
Model klasifikasi sebenarnya tidak langsung menjawab "ya" atau "tidak". Yang dihasilkan adalah angka kepercayaan antara 0 dan 1, misalnya 0,73.
Ambang atau threshold adalah batas yang menentukan angka berapa yang dianggap "ya". Secara bawaan ambangnya 0,5, tapi angka ini bisa dan sering perlu diubah. Bagian tersendiri di artikel ini membahasnya.
Menyiapkan Data dan Model Contoh
Kita akan memakai dua dataset: satu yang cukup seimbang, dan satu yang sengaja dibuat sangat timpang supaya jebakan akurasi terlihat jelas.
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer, make_classification
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
RANDOM_STATE = 42
# Dataset 1: deteksi tumor, cukup seimbang
data = load_breast_cancer(as_frame=True)
X, y = data.data, data.target # 1 = jinak, 0 = ganas
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, stratify=y, random_state=RANDOM_STATE
)
model = Pipeline([
("skala", StandardScaler()),
("model", LogisticRegression(max_iter=5000, random_state=RANDOM_STATE)),
])
model.fit(X_train, y_train)
# Dataset 2: sengaja timpang, 2 persen kelas positif
Xt, yt = make_classification(
n_samples=10_000, n_features=20, n_informative=5,
weights=[0.98, 0.02], # hanya 2 persen kelas positif
random_state=RANDOM_STATE,
)
Xt_train, Xt_test, yt_train, yt_test = train_test_split(
Xt, yt, test_size=0.3, stratify=yt, random_state=RANDOM_STATE
)
print("Sebaran kelas dataset timpang:", np.bincount(yt))
Confusion Matrix: Fondasi Semua Metrik Klasifikasi
Apa Itu Confusion Matrix
Ini tabel kecil yang memecah hasil prediksi menjadi empat kategori. Hampir semua metrik klasifikasi dihitung dari keempat angka ini, jadi memahaminya sekali akan membuat sisanya jauh lebih mudah.
| Model bilang: Negatif | Model bilang: Positif | |
|---|---|---|
| Kenyataannya Negatif | Benar Negatif (TN) | Salah Positif (FP) |
| Kenyataannya Positif | Salah Negatif (FN) | Benar Positif (TP) |
Memahami Keempatnya dengan Analogi Alarm Kebakaran
Benar Positif (True Positive). Ada api, alarm berbunyi. Model benar.
Benar Negatif (True Negative). Tidak ada api, alarm diam. Model benar.
Salah Positif (False Positive). Tidak ada api, tapi alarm berbunyi. Ini alarm palsu. Merepotkan, semua orang keluar gedung tanpa perlu, tapi tidak ada yang celaka.
Salah Negatif (False Negative). Ada api, tapi alarm diam. Ini yang berbahaya. Bisa berakibat fatal.
Perhatikan bahwa dua jenis kesalahan itu tidak setara. Alarm palsu itu mengganggu, alarm yang gagal berbunyi itu mematikan. Ketidaksetaraan inilah yang membuat kita tidak bisa asal memakai akurasi.
Cara Mengingatnya
Kata pertama menjawab: apakah model benar? Kata kedua menjawab: apa yang dikatakan model?
Jadi "Salah Positif" artinya model mengatakan positif, dan model salah.
Contoh Kode
from sklearn.metrics import confusion_matrix
prediksi = model.predict(X_test)
cm = confusion_matrix(y_test, prediksi)
print(cm)
# Susunan: [[TN, FP],
# [FN, TP]]
tn, fp, fn, tp = cm.ravel()
print(f"Benar Negatif (TN): {tn}")
print(f"Salah Positif (FP): {fp} <- alarm palsu")
print(f"Salah Negatif (FN): {fn} <- gagal terdeteksi")
print(f"Benar Positif (TP): {tp}")
Menampilkan dalam Bentuk Gambar
import matplotlib.pyplot as plt
from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_estimator(
model, X_test, y_test,
display_labels=["Ganas", "Jinak"],
cmap="Blues",
)
plt.title("Confusion Matrix")
plt.show()
Biasakan selalu melihat confusion matrix sebelum melihat metrik apa pun. Satu tabel ini menceritakan lebih banyak daripada deretan angka persentase.
Metrik Klasifikasi Satu per Satu
Akurasi
Apa yang Diukur
Persentase tebakan yang benar dari seluruh data.
Akurasi = (TP + TN) / semua data
Analogi
Seperti nilai ujian pilihan ganda: berapa soal yang benar dari total soal.
Kapan Layak Dipakai
Hanya ketika dua syarat terpenuhi sekaligus: jumlah kelasnya kira-kira seimbang, dan kedua jenis kesalahan sama merugikannya.
Kapan Menipu
Saat data timpang. Mari buktikan langsung dengan dataset kedua tadi.
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, recall_score
# Model malas: selalu menebak kelas terbanyak
malas = DummyClassifier(strategy="most_frequent")
malas.fit(Xt_train, yt_train)
tebakan_malas = malas.predict(Xt_test)
print("Akurasi model malas:", round(accuracy_score(yt_test, tebakan_malas), 4))
print("Recall model malas :", round(recall_score(yt_test, tebakan_malas), 4))
Hasilnya akurasi sekitar 0,98 tapi recall 0,00. Model yang tidak pernah menemukan satu pun kasus positif mencatat akurasi 98 persen.
Ini bukti kenapa akurasi tidak boleh dipakai sendirian.
Precision
Apa yang Diukur
Dari semua yang ditebak positif oleh model, berapa persen yang benar-benar positif?
Precision = TP / (TP + FP)
Analogi
Bayangkan polisi menangkap 100 orang sebagai tersangka. Ternyata hanya 70 yang benar-benar bersalah. Precision-nya 70 persen. Artinya 30 orang tidak bersalah ikut ditangkap.
Precision menjawab pertanyaan: seberapa bisa saya percaya kalau model bilang "ya"?
Kapan Ini yang Paling Penting
Saat salah positif itu mahal atau merugikan.
Penyaring email spam. Kalau email penting masuk folder spam, pengguna bisa kehilangan tawaran kerja. Lebih baik beberapa spam lolos daripada satu email penting hilang.
Rekomendasi produk. Merekomendasikan barang yang tidak relevan membuat pengguna kehilangan kepercayaan.
Penindakan otomatis. Memblokir akun pengguna yang sebenarnya tidak bersalah menimbulkan komplain dan kerugian reputasi.
Recall
Apa yang Diukur
Dari semua yang sebenarnya positif, berapa persen yang berhasil ditemukan model?
Recall = TP / (TP + FN)
Analogi
Di sebuah kota ada 100 penjahat. Polisi berhasil menangkap 60 di antaranya. Recall-nya 60 persen. Artinya 40 penjahat masih berkeliaran.
Recall menjawab pertanyaan: berapa banyak kasus yang lolos dari perhatian model?
Nama lain recall adalah sensitivity atau true positive rate.
Kapan Ini yang Paling Penting
Saat salah negatif itu berbahaya atau mahal.
Skrining penyakit. Melewatkan pasien yang benar-benar sakit jauh lebih berbahaya daripada memeriksa ulang orang sehat.
Deteksi penipuan. Satu transaksi penipuan yang lolos bisa merugikan jauh lebih besar daripada beberapa transaksi wajar yang diperiksa manual.
Deteksi kerusakan mesin. Melewatkan tanda kerusakan bisa berujung kecelakaan.
Kenapa Precision dan Recall Saling Bertolak Belakang
Analogi Jaring Ikan
Bayangkan menangkap ikan dengan jaring.
Kalau lubang jaringnya besar, hanya ikan besar yang tertangkap. Hampir semua yang Anda dapat memang ikan yang diincar, jadi precision tinggi. Tapi banyak ikan kecil lolos, jadi recall rendah.
Kalau lubang jaringnya sangat kecil, hampir semua ikan tertangkap sehingga recall tinggi. Tapi sampah, plastik, dan rumput laut ikut terbawa, jadi precision rendah.
Tidak ada jaring yang sempurna di kedua sisi. Anda harus memilih mana yang lebih penting untuk kebutuhan Anda.
Cara Menggeser Keseimbangannya
Menaikkan salah satu hampir selalu menurunkan yang lain. Pergeseran itu diatur lewat ambang keputusan, yang dibahas di bagian berikutnya.
F1-Score
Apa yang Diukur
Gabungan antara precision dan recall dalam satu angka.
F1 = 2 × (Precision × Recall) / (Precision + Recall)
Kenapa Bukan Rata-rata Biasa
Ini pertanyaan bagus. Rumus di atas adalah rata-rata harmonik, bukan rata-rata biasa.
Bedanya, rata-rata harmonik menghukum ketimpangan. Kalau precision 1,0 dan recall 0,0, rata-rata biasa menghasilkan 0,5 yang terkesan lumayan. Padahal model itu sebenarnya rusak. Rata-rata harmonik menghasilkan 0,0, yang jauh lebih jujur.
Jadi F1 hanya tinggi kalau precision dan recall sama-sama tinggi.
Kapan Dipakai
Saat precision dan recall sama pentingnya, dan Anda butuh satu angka untuk membandingkan beberapa model.
Ini metrik default yang baik untuk data tidak seimbang, menggantikan akurasi.
F-beta: Kalau Salah Satu Lebih Penting
Cara Kerjanya
F1 memberi bobot sama pada precision dan recall. Kalau Anda ingin salah satunya lebih diprioritaskan, pakai F-beta.
Nilai beta lebih dari 1 memberi bobot lebih pada recall. Nilai kurang dari 1 memberi bobot lebih pada precision.
from sklearn.metrics import fbeta_score
prediksi = model.predict(X_test)
print("F1 :", round(fbeta_score(y_test, prediksi, beta=1), 4))
print("F2 :", round(fbeta_score(y_test, prediksi, beta=2), 4)) # recall 2x lebih penting
print("F0.5 :", round(fbeta_score(y_test, prediksi, beta=0.5), 4)) # precision lebih penting
Untuk skrining penyakit, F2 lebih masuk akal. Untuk penyaring spam, F0.5 lebih masuk akal.
Melihat Semuanya Sekaligus
from sklearn.metrics import classification_report
print(classification_report(
y_test, prediksi,
target_names=["Ganas", "Jinak"],
digits=3,
))
Cara membaca keluarannya:
Tiap baris menunjukkan metrik untuk satu kelas. Kolom support menunjukkan berapa banyak data asli yang ada di kelas itu. Kalau support sangat kecil, angka metriknya jadi tidak stabil dan tidak bisa terlalu dipercaya.
Kalau Kelasnya Lebih dari Dua
Untuk klasifikasi multikelas, ada tiga cara merangkum metrik dari semua kelas.
Macro average. Hitung metrik tiap kelas lalu ambil rata-rata biasa. Semua kelas dianggap sama penting, tidak peduli jumlah datanya. Pakai ini kalau kelas kecil sama pentingnya dengan kelas besar.
Weighted average. Sama seperti macro, tapi tiap kelas ditimbang sesuai jumlah datanya. Kelas besar lebih berpengaruh pada hasil akhir.
Micro average. Semua prediksi digabung dulu baru dihitung. Untuk klasifikasi satu label, hasilnya sama dengan akurasi.
from sklearn.metrics import f1_score
print("Macro :", round(f1_score(y_test, prediksi, average="macro"), 4))
print("Weighted:", round(f1_score(y_test, prediksi, average="weighted"), 4))
Untuk data tidak seimbang, macro average biasanya lebih jujur karena tidak menyembunyikan performa buruk di kelas minoritas.
Probabilitas dan Ambang Keputusan
Model Sebenarnya Menghasilkan Angka, Bukan Keputusan
Ini konsep yang sering terlewat oleh pemula, padahal sangat berguna.
Ketika Anda memanggil predict(), model sebenarnya menghitung probabilitas lebih dulu, lalu membandingkannya dengan ambang 0,5.
probabilitas = model.predict_proba(X_test)[:, 1] # probabilitas kelas positif
keputusan = model.predict(X_test)
for i in range(5):
print(f"Probabilitas: {probabilitas[i]:.4f} -> Keputusan: {keputusan[i]}")
Angka 0,5 itu hanya bawaan, bukan angka keramat. Anda boleh mengubahnya.
Kenapa Mengubah Ambang Itu Berguna
Bayangkan model memberi probabilitas 0,45 untuk sebuah transaksi mencurigakan. Dengan ambang 0,5, transaksi itu dinyatakan aman dan lolos.
Padahal 0,45 cukup mencurigakan. Kalau ambangnya diturunkan ke 0,3, transaksi itu akan ditandai untuk diperiksa.
Menurunkan ambang membuat model lebih mudah menyatakan positif, sehingga recall naik dan precision turun. Menaikkan ambang efeknya kebalikan.
Yang menarik, ini tidak memerlukan pelatihan ulang sama sekali. Modelnya sama persis, cuma cara membaca hasilnya yang berubah.
Melihat Efek Perubahan Ambang
from sklearn.metrics import precision_score, recall_score, f1_score
prob_timpang = LogisticRegression(max_iter=5000).fit(Xt_train, yt_train)
p = prob_timpang.predict_proba(Xt_test)[:, 1]
print(f"{'Ambang':>8} {'Precision':>10} {'Recall':>8} {'F1':>8}")
for ambang in [0.1, 0.2, 0.3, 0.5, 0.7, 0.9]:
tebak = (p >= ambang).astype(int)
print(f"{ambang:>8.2f} {precision_score(yt_test, tebak, zero_division=0):>10.3f} "
f"{recall_score(yt_test, tebak):>8.3f} {f1_score(yt_test, tebak):>8.3f}")
Jalankan kode ini dan perhatikan polanya. Saat ambang turun, recall naik dan precision turun. Itulah trade-off jaring ikan tadi, terlihat dalam angka.
Memilih Ambang Berdasarkan Kebutuhan
Misalnya kebijakan rumah sakit menuntut recall minimal 90 persen, artinya tidak boleh melewatkan lebih dari 10 persen pasien yang sakit. Kita bisa mencari ambang terbaik yang memenuhi syarat itu.
from sklearn.metrics import precision_recall_curve
precision, recall, ambang = precision_recall_curve(yt_test, p)
target_recall = 0.90
memenuhi = np.where(recall[:-1] >= target_recall)[0]
terpilih = memenuhi[-1] # ambang tertinggi yang masih memenuhi syarat
print(f"Ambang terpilih : {ambang[terpilih]:.4f}")
print(f"Recall : {recall[terpilih]:.4f}")
print(f"Precision: {precision[terpilih]:.4f}")
Catatan Penting
Ambang harus dipilih memakai data validasi yang terpisah, bukan data uji akhir. Kalau Anda mencoba-coba ambang di data uji lalu memilih yang hasilnya paling bagus, data uji itu sudah tidak jujur lagi.
