Akurasi menyembunyikan informasi justru pada saat informasi tersebut paling dibutuhkan. Dua model dengan akurasi 90% bisa sangat berbeda nasibnya: yang satu melakukan 90% kesalahan pada transaksi sah, yang lain pada transaksi penipuan — dan biaya keduanya tidak sama. Confusion matrix membongkar satu angka akurasi menjadi tabel silang antara kondisi sebenarnya dan prediksi model, sehingga setiap jenis galat bisa dilihat, dihitung, dan dihargai sendiri-sendiri. Chapter ini membedah anatomi matriks 2×2, memastikan kita membaca baris dan kolom dengan benar, lalu melihat bagaimana matriks yang sama bekerja untuk tiga kelas.

Anatomi Empat Sel untuk Kasus Biner #

Misalkan kita membangun deteksi penipuan transaksi dengan kelas positif “penipuan” (label 1) dan kelas negatif “sah” (label 0). Setiap prediksi jatuh ke salah satu dari empat sel:

  • True Positive (TP): transaksi penipuan, dan model menandainya penipuan. Keputusan yang tepat.
  • False Positive (FP): transaksi sah, tetapi model menandainya penipuan. Transaksi nasabah yang jujur terhambat — kartu dibekukan sementara, pembayaran tertunda, layanan pelanggan menerima keluhan. Biayanya berupa ketidaknyamanan dan kepercayaan nasabah yang tergerus.
  • False Negative (FN): transaksi penipuan, tetapi model meloloskannya sebagai sah. Kerugian langsung di pihak bank atau pemilik kartu.
  • True Negative (TN): transaksi sah dan model meloloskannya. Tidak ada berita — dan itulah hasil yang diharapkan.

Dua jenis galat tersebut hampir tidak pernah setara. Membekukan transaksi sah yang nilainya Rp200.000 berbeda konsekuensinya dengan meloloskan penipuan sebesar Rp20.000.000. Sebelum memilih model, manajemen perlu tahu ke arah mana galat model cenderung jatuh — dan itulah pertanyaan yang dijawab confusion matrix.

Konvensi scikit-learn: Baris Aktual, Kolom Prediksi #

Fungsi confusion_matrix dari scikit-learn menyusun tabel dengan konvensi yang harus dihafal benar: baris adalah label aktual, kolom adalah label prediksi, dan urutan kelas mengikuti label terurut (untuk label 0/1, baris-kolom pertama adalah kelas 0). Matriks 2×2-nya berbentuk:

Prediksi: 0 (sah)Prediksi: 1 (penipuan)
Aktual: 0 (sah)TNFP
Aktual: 1 (penipuan)FNTP

Dalam notasi indeks NumPy, sel-sel tersebut adalah cm[0, 0], cm[0, 1], cm[1, 0], dan cm[1, 1]. Kesalahan membaca konvensi (misalnya mengira kolom adalah aktual) akan menukar FP dengan FN — dan menyesatkan seluruh analisis biaya di atasnya.

Membuktikan Empat Sel dalam Angka #

Kita ambil 20 transaksi dengan hasil prediksi tetap, bangun matriksnya, lalu verifikasi tiap sel dengan penghitungan manual memakai topeng boolean. Akurasi juga kita hitung sendiri dari sel-sel matriks sebagai pemeriksaan silang.

python
# Confusion matrix: bedah 20 prediksi menjadi 4 sel (TP, FP, FN, TN),
# lalu baca matriks 3 kelas pada dataset iris.

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.model_selection import train_test_split

# --- Kasus biner: deteksi penipuan transaksi ---
# 1 = penipuan (kelas positif), 0 = transaksi sah.
y_true = np.array([0, 0, 0, 1, 0, 0, 1, 0, 1, 0,
                   0, 1, 0, 0, 1, 0, 0, 0, 1, 0])
y_pred = np.array([0, 1, 0, 1, 0, 0, 1, 0, 0, 0,
                   1, 1, 0, 0, 0, 0, 0, 1, 1, 0])

cm = confusion_matrix(y_true, y_pred)  # baris = aktual, kolom = prediksi
print("Confusion matrix (baris = aktual, kolom = prediksi):")
print(cm)

# Ambil keempat sel lewat indeks [baris, kolom].
TN, FP, FN, TP = cm[0, 0], cm[0, 1], cm[1, 0], cm[1, 1]

# Hitung manual dengan topeng boolean -- harus identik dengan sel matriks.
tp_manual = int(np.sum((y_true == 1) & (y_pred == 1)))
fp_manual = int(np.sum((y_true == 0) & (y_pred == 1)))
fn_manual = int(np.sum((y_true == 1) & (y_pred == 0)))
tn_manual = int(np.sum((y_true == 0) & (y_pred == 0)))

print(f"TP = {TP} (manual {tp_manual}) , FP = {FP} (manual {fp_manual})")
print(f"FN = {FN} (manual {fn_manual}) , TN = {TN} (manual {tn_manual})")

# Akurasi dihitung sendiri dari sel matriks, lalu dibandingkan.
akurasi_manual = (TP + TN) / (TP + TN + FP + FN)
print(f"Akurasi dari matriks = {akurasi_manual:.3f} , "
      f"accuracy_score = {accuracy_score(y_true, y_pred):.3f}")

# --- Kasus multiclass: iris, 3 kelas ---
print()
iris = load_iris()
X_latih, X_uji, y_latih, y_uji = train_test_split(
    iris.data, iris.target, test_size=0.3, stratify=iris.target, random_state=42
)
model = LogisticRegression(max_iter=1000, random_state=42)
model.fit(X_latih, y_latih)
prediksi = model.predict(X_uji)

cm3 = confusion_matrix(y_uji, prediksi)
nama_kelas = ["setosa", "versicolor", "virginica"]
print("Confusion matrix iris (baris = aktual, kolom = prediksi):")
print(f"{'':>18} pred setosa  pred versicolor  pred virginica")
for nama, baris in zip(nama_kelas, cm3):
    print(f"aktual {nama:>10}: {baris[0]:>10d} {baris[1]:>16d} {baris[2]:>14d}")

benar = int(np.trace(cm3))  # jumlah diagonal = prediksi benar
print(f"Diagonal (benar) = {benar} dari {int(cm3.sum())} sampel , "
      f"akurasi = {accuracy_score(y_uji, prediksi):.3f}")

Output yang Dihasilkan:

text
Confusion matrix (baris = aktual, kolom = prediksi):
[[11  3]
 [ 2  4]]
TP = 4 (manual 4) , FP = 3 (manual 3)
FN = 2 (manual 2) , TN = 11 (manual 11)
Akurasi dari matriks = 0.750 , accuracy_score = 0.750

Confusion matrix iris (baris = aktual, kolom = prediksi):
                   pred setosa  pred versicolor  pred virginica
aktual     setosa:         15                0              0
aktual versicolor:          0               14              1
aktual  virginica:          0                2             13
Diagonal (benar) = 42 dari 45 sampel , akurasi = 0.933

Mari kita telaah bagian-bagian pentingnya:

  1. Baris 12–15 (y_true dan y_pred): dua puluh pasangan label aktual dan prediksi ditulis sebagai array tetap. Dari 20 transaksi, 6 adalah penipuan dan model menandai 7 transaksi sebagai penipuan.
  2. Baris 17–19 (confusion_matrix(...)): fungsi mengembalikan array 2×2 sesuai konvensi baris-aktual-kolom-prediksi, dengan kelas terurut [0, 1].
  3. Baris 22 (TN, FP, FN, TP = cm[0, 0], ...): keempat sel diambil lewat indeks [baris, kolom] — ingat bahwa cm[1, 0] adalah FN (aktual penipuan, diprediksi sah), bukan sebaliknya.
  4. Baris 25–28 (topeng boolean): tiap sel dihitung ulang langsung dari pasangan label, misalnya TP adalah jumlah sampel dengan (y_true == 1) & (y_pred == 1). Kesamaan hasil dengan indeks matriks di baris 30–31 memastikan konvensi dibaca dengan benar.
  5. Baris 34–36 (akurasi_manual): akurasi dihitung dari sel matriks sebagai jumlah diagonal dibagi total, lalu dibandingkan dengan accuracy_score — keduanya harus identik.
  6. Baris 41–46 (bagian iris): skema yang sama diterapkan pada data uji iris yang dibelah dengan stratify dan random_state=42, lalu diprediksi LogisticRegression.

Pada output bagian pertama, matriks [[11, 3], [2, 4]] terbaca sebagai berikut: 11 transaksi sah benar diloloskan, 3 transaksi sah keliru ditahan (FP), 2 penipuan lolos (FN), dan 4 penipuan tertangkap (TP). Akurasi 0,750 — (4+11)/20 — sama persis baik dihitung dari matriks maupun oleh accuracy_score. Angka 0,750 itu sendiri kini punya anatomi: kita tahu bahwa 3 kesalahan mengganggu nasabah jujur dan 2 kesalahan membiarkan kerugian terjadi.

Membaca Matriks Multiclass #

Untuk tiga kelas, konvensinya sama persis: baris aktual, kolom prediksi, urutan kelas terurut. Output iris menunjukkan 15 bunga setosa diprediksi setosa seluruhnya, 14 dari 15 versicolor benar dengan 1 jatuh ke virginica, dan 13 dari 15 virginica benar dengan 2 jatuh ke versicolor. Diagonal matriks (np.trace) berjumlah 42 — itulah 42 prediksi benar dari 45 sampel, akurasi 0,933. Pola galat juga terbaca: kebingungan hanya terjadi antara versicolor dan virginica, dua spesies yang memang bertetangga pada ruang fitur, dan tidak ada satu pun setosa yang tertukar. Informasi semacam ini tidak akan pernah muncul dari satu angka akurasi.

Empat sel TP, FP, FN, dan TN adalah bahan baku bagi seluruh metrik klasifikasi berikutnya. Dua turunan paling penting — precision dan recall — memakai FP dan FN sebagai penyeimbang yang mencerminkan biaya nyata, dan itulah pokok bahasan Chapter Precision, Recall, dan F1-Score.

Referensi Resmi #