Akurasi memberi tahu berapa banyak prediksi yang meleset, tetapi tidak memberi tahu meleset ke arah mana. Padahal arah itulah yang menentukan keputusan nyata: email penting yang tercecer ke folder spam adalah masalah lain daripada email promosi yang lolos ke kotak masuk. Confusion matrix adalah tabel 2x2 yang mencatat keempat kemungkinan hasil prediksi secara terpisah — dan dari tabel kecil inilah seluruh metrik klasifikasi pada babak-babak berikutnya diturunkan. Pada chapter ini kita hitung keempat selnya secara manual, membacanya lewat confusion_matrix dari scikit-learn, lalu memakainya untuk membaca hasil skrining kesehatan.
Empat Sel: TP, FP, FN, dan TN #
Confusion matrix memilah prediksi berdasarkan dua pertanyaan: apa kondisi sebenarnya (positif atau negatif) dan apa prediksi model (positif atau negatif). Irisan keduanya menghasilkan empat sel dengan nama baku yang wajib dihafal:
| Sel | Kondisi aktual | Prediksi model | Makna pada filter spam |
|---|---|---|---|
| TP (true positive) | Positif | Positif | Spam yang berhasil ditandai spam |
| FP (false positive) | Negatif | Positif | Email penting yang salah ditandai spam |
| FN (false negative) | Positif | Negatif | Spam yang lolos ke kotak masuk |
| TN (true negative) | Negatif | Negatif | Email penting yang tetap sampai ke kotak masuk |
Dua sel menyimpan kabar baik (TP dan TN — prediksi sejalan dengan kenyataan), dua sel menyimpan kesalahan yang arahnya berbeda (FP dan FN). Pembedaan FP versus FN adalah inti kegunaan confusion matrix: biaya keduanya hampir tidak pernah sama. Salah menandai email penting sebagai spam bisa membuat kita kehilangan kabar undangan wawancara kerja; membiarkan satu email promosi lolos hanyalah gangguan kecil. Metrik berbeda menimbang dua jenis kesalahan ini secara berbeda, dan semuanya berawal dari empat angka di tabel ini.
Menghitung Empat Sel Secara Manual #
Klasifikasi pos = spam (label 1), negatif = bukan spam (label 0). Sebuah filter sederhana mengolah 16 email — delapan spam dan delapan email biasa — dengan hasil sebagai berikut:
# 1 = spam, 0 = bukan spam
aktual = [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
prediksi = [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0]
tp = fp = fn = tn = 0
for a, p in zip(aktual, prediksi):
if a == 1 and p == 1:
tp += 1
elif a == 0 and p == 1:
fp += 1
elif a == 1 and p == 0:
fn += 1
else:
tn += 1
print("TP (spam, diprediksi spam) :", tp)
print("FP (bukan, diprediksi spam) :", fp)
print("FN (spam, diprediksi bukan) :", fn)
print("TN (bukan, diprediksi bukan) :", tn)Output yang Dihasilkan:
TP (spam, diprediksi spam) : 6
FP (bukan, diprediksi spam) : 2
FN (spam, diprediksi bukan) : 2
TN (bukan, diprediksi bukan) : 6Mari kita telaah baris-baris kode di atas:
- Deret
aktualdanprediksi: kedua list sejajar posisi — indeks ke-i merujuk email yang sama. Delapan nilai 1 terlebih dahulu memudahkan kita memeriksa hitungan. - Empat cabang
if/elif: setiap pasangan label jatuh ke tepat satu cabang. Urutan pemeriksaan tidak penting; yang penting setiap kombinasi aktual-prediksi terhitung satu kali. - Pembacaan hasil: 6 spam tertangkap, 2 spam lolos (FN), 2 email penting salah ditandai (FP), dan 6 email penting selamat. Akurasi bisa dihitung langsung dari sini: (6+6)/16 = 0.75 — tetapi kini kita juga tahu komposisi kesalahannya, sesuatu yang angka akurasi sembunyikan.
Perhatikan bahwa kedua jenis kesalahan berjumlah sama (2 dan 2). Ini kebetulan data contoh, bukan hukum alam — pada kasus nyata FP dan FN hampir selalu timpang, dan ketimpangan itulah yang menentukan prioritas perbaikan model.
confusion_matrix dari scikit-learn #
Fungsi confusion_matrix menghitung tabel yang sama dalam satu panggilan. Kita juga memakai .ravel() untuk mengurai keempat selnya dan pandas DataFrame agar tabelnya enak dibaca:
import pandas as pd
from sklearn.metrics import confusion_matrix
aktual = [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
prediksi = [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0]
cm = confusion_matrix(aktual, prediksi)
print("Matriks mentah:")
print(cm)
tn, fp, fn, tp = cm.ravel()
print("Hasil ravel -> TN=%d, FP=%d, FN=%d, TP=%d" % (tn, fp, fn, tp))
tabel = pd.DataFrame(
cm,
index=["Aktual bukan spam", "Aktual spam"],
columns=["Prediksi bukan spam", "Prediksi spam"],
)
print(tabel)Output yang Dihasilkan:
Matriks mentah:
[[6 2]
[2 6]]
Hasil ravel -> TN=6, FP=2, FN=2, TP=6
Prediksi bukan spam Prediksi spam
Aktual bukan spam 6 2
Aktual spam 2 6Mari kita telaah hasilnya:
- Matriks mentah
[[6 2], [2 6]]: scikit-learn menempatkan baris sebagai kelas aktual dan kolom sebagai kelas prediksi, dengan urutan kelas mengikuti label terkecil lebih dulu (0 lalu 1). Sel[0][0]=6berarti aktual-negatif yang diprediksi negatif (TN); sel[1][0]=2berarti aktual-spam yang diprediksi bukan spam (FN). - Urutan
.ravel(): fungsi ini mengembalikan empat sel dalam urutan(TN, FP, FN, TP)— bukan urutan baku TP-FP-FN-TN seperti penulisan manual. Kesalahan urutan saat membongkarravel()adalah sumber bug yang sangat umum. - DataFrame
tabel: memberi nama baris dan kolom pada matriks sehingga pembaca laporan tidak perlu menghafal konvensi. Membaca satu baris penuh menjawab pertanyaan yang sangat spesifik: dari 8 email spam yang masuk, 2 lolos — data ini yang akan dipakai menghitung recall pada chapter berikutnya.
Membaca Proporsi per Baris: Contoh Skrining Kesehatan #
Empat sel mentah menjadi lebih bermakna ketika dibaca sebagai proporsi per baris. Kita ganti konteks ke skrining kesehatan: sebuah puskesmas menguji alat bantu deteksi dini pada 40 pasien — 12 terbukti positif, 28 sehat:
import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix
# 40 pasien skrining: 12 positif, 28 sehat
aktual = [1] * 12 + [0] * 28
prediksi = [1] * 9 + [0] * 3 + [1] * 3 + [0] * 25
cm = confusion_matrix(aktual, prediksi)
tabel = pd.DataFrame(
cm,
index=["Aktual sehat", "Aktual positif"],
columns=["Prediksi sehat", "Prediksi positif"],
)
print(tabel)
proporsi = confusion_matrix(aktual, prediksi, normalize="true")
print("Proporsi per baris (aktual sehat, aktual positif):")
print(np.round(proporsi, 2))Output yang Dihasilkan:
Prediksi sehat Prediksi positif
Aktual sehat 25 3
Aktual positif 3 9
Proporsi per baris (aktual sehat, aktual positif):
[[0.89 0.11]
[0.25 0.75]]Mari kita baca hasilnya seperti tenaga medis membacanya:
- Baris “Aktual positif” (12 pasien): 9 terdeteksi positif, 3 terlewat. Parameter
normalize="true"membagi tiap sel dengan jumlah barisnya, sehingga baris ini terbaca langsung sebagai proporsi: 9/12 = 0.75 terdeteksi, 3/12 = 0.25 terlewat. Angka 0.75 inilah yang kelak kita kenal sebagai recall. - Baris “Aktual sehat” (28 pasien): 25 dinyatakan sehat, 3 menerima peringatan palsu (0.11). Dalam skrining kesehatan, 3 peringatan palsu umumnya lebih ditoleransi daripada 3 kasus terlewat — alat skrining dirancang peka, tindak lanjut pemeriksaan lanjutan yang menyaring kembali.
- Kolom “Prediksi positif” (12 peringatan): 9 benar dan 3 palsu — pembacaan per kolom seperti ini menjadi bahan menghitung precision pada chapter berikutnya.
Satu tabel 2x2 yang sama, tiga cara membaca: keseluruhan (akurasi), per baris (recall), per kolom (precision). Tidak ada informasi baru yang ditambahkan — yang berubah hanyalah pertanyaan kita terhadap keempat angka yang sama.
Rangkuman #
- Confusion matrix memilah prediksi menjadi empat sel: TP dan TN (prediksi tepat) serta FP dan FN (dua jenis kesalahan yang arah dan dampaknya berbeda).
- Hitungan manual 16 email menghasilkan TP=6, FP=2, FN=2, TN=6 — akurasi (6+6)/16 tetap bisa dihitung, tetapi kini komposisi kesalahannya ikut terlihat.
confusion_matrixscikit-learn menempatkan baris sebagai aktual dan kolom sebagai prediksi;.ravel()mengembalikan sel dalam urutan(TN, FP, FN, TP).normalize="true"mengubah tiap baris menjadi proporsi, sehingga baris kelas positif terbaca langsung sebagai tingkat deteksi (calon recall).- Membaca confusion matrix itu memilih pertanyaan: keseluruhan untuk akurasi, per baris untuk recall, per kolom untuk precision.
Keempat sel ini adalah bahan baku mentah. Langkah berikutnya adalah menggilingnya menjadi metrik yang menimbang kesalahan sesuai kebutuhan kita: precision untuk menekan alarm palsu, recall untuk menekan kasus terlewat, dan F1 untuk menggabungkan keduanya — pokok bahasan chapter Precision, Recall, dan F1-Score .