K-Nearest Neighbors pada chapter sebelumnya mengambil keputusan dari kepadatan tetangga, dan seperti semua model berbasis jarak, ia menuntut fitur yang diskalakan. Support Vector Machine (SVM) berbagi tuntutan yang sama tetapi membawa filosofi geometris yang berbeda: alih-alih menghitung tetangga, SVM mencari garis — atau bidang pada dimensi lebih tinggi — pemisah dua kelas yang memberi ruang aman selebar mungkin di antara keduanya. Model ini dikenal tangguh pada data berdimensi banyak, akurat pada dataset kecil-menengah, dan memiliki mekanisme bernama kernel untuk menggarap batas pemisah yang melengkung. Pada chapter ini kita memakai data panjang dan berat biji kopi untuk membedah hyperplane, margin, dan peran penskalaan, lalu data percobaan harga di “Toko Kopi Kita” untuk melihat kapan kernel rbf benar-benar dibutuhkan.
Hyperplane dan Margin Maksimum #
Pada klasifikasi dua kelas, tugas SVM adalah menemukan hyperplane — garis pemisah pada dua dimensi, bidang pada tiga dimensi, dan seterusnya — yang memisahkan kedua kelas. Dari tak terhingga banyaknya garis pemisah yang mungkin, SVM memilih satu dengan kriteria khusus:
Hyperplane : w . x + b = 0
Margin : jarak terpendek hyperplane ke titik terdekat tiap kelas
Tujuan SVM : maksimalkan lebar margin (2 x jarak tersebut)
w : arah tegak lurus hyperplane (bobot tiap fitur)
b : pergeseran posisi hyperplane
titik-titik yang tepat berada di tepi margin = vektor pendukungIntuisinya: garis pemisah yang menempel rapat ke salah satu kelas terlalu percaya diri — sedikit derau pada data baru sudah cukup untuk membuat prediksi berpindah kelas. Garis yang berdiri persis di tengah, dengan ruang kosong selebar mungkin di kedua sisinya, memberi toleransi terbesar terhadap variasi data baru. Hanya titik-titik yang berada tepat di tepi margin — dinamai vektor pendukung (support vector) — yang menentukan posisi hyperplane; titik lain yang berada jauh di zona aman boleh dipindahkan tanpa mengubah apa pun. Inilah sebabnya SVM hemat perhatian: model yang tersimpan hanyalah segelintir titik perbatasan itu, bukan seluruh data seperti KNN.
Penskalaan Fitur Sebelum SVM #
Margin dihitung sebagai jarak di ruang fitur, jadi satuan fitur ikut menentukan bentuk geometrinya. Kasus kita: “Toko Kopi Kita” menerima kiriman biji kopi dari beberapa pemasok dan perlu memilah lot arabika dari robusta hanya dari dua ukuran fisik — panjang_mm (milimeter, bernilai 8-12) dan berat_gram (gram, bernilai 0,10-0,24). Polanya: arabika cenderung lebih panjang dan lebih berat. Masalahnya, skala panjang_mm ratusan kali lebih besar daripada berat_gram, sehingga geometri margin nyaris sepenuhnya dibentuk oleh panjang biji:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
biji = pd.DataFrame({
"panjang_mm": [9.4, 10.1, 10.8, 11.2, 9.8, 10.5, 11.6, 9.9, 10.3, 11.0,
9.6, 10.7, 11.4, 10.2, 10.9,
8.4, 9.1, 8.8, 9.6, 8.2, 9.3, 8.6, 9.8, 8.9, 9.5,
8.3, 9.0, 9.7, 8.5, 9.05],
"berat_gram": [0.21, 0.19, 0.22, 0.20, 0.23, 0.18, 0.24, 0.20, 0.22, 0.19,
0.22, 0.21, 0.18, 0.24, 0.155,
0.12, 0.14, 0.11, 0.13, 0.15, 0.10, 0.13, 0.12, 0.16, 0.11,
0.14, 0.15, 0.14, 0.12, 0.175],
"arabika": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
})
fitur = ["panjang_mm", "berat_gram"]
X = biji[fitur]
y = biji["arabika"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3,
stratify=y, random_state=42)
mentah = SVC(kernel="linear", C=1.0)
mentah.fit(X_latih, y_latih)
skala = StandardScaler()
X_latih_skala = skala.fit_transform(X_latih)
X_uji_skala = skala.transform(X_uji)
diskala = SVC(kernel="linear", C=1.0)
diskala.fit(X_latih_skala, y_latih)
print("Data mentah : akurasi uji %.2f" % mentah.score(X_uji, y_uji))
print("Data diskala: akurasi uji %.2f" % diskala.score(X_uji_skala, y_uji))
print("Vektor pendukung model diskala: %d dari %d titik latih"
% (diskala.n_support_.sum(), len(X_latih)))Output yang Dihasilkan:
Data mentah : akurasi uji 0.78
Data diskala: akurasi uji 1.00
Vektor pendukung model diskala: 5 dari 21 titik latihMari kita telaah baris-baris kode di atas:
SVC(kernel="linear", C=1.0):SVCadalah kelas SVM scikit-learn;kernel="linear"meminta hyperplane berupa garis lurus, danCmengatur ketatnya margin (kita bahas khusus di bagian berikutnya).- Data mentah hanya mencapai 0,78: rentang
panjang_mmsekitar 8-12 sedangkanberat_gramhanya 0,10-0,24. Dalam geometri mentah, selisih 1 mm panjang biji setara selisih satu penuh satuan berat — padahal 1 mm itu jauh lebih bermakna secara fisik. Kelompok arabika pendek dan robusta panjang di zona tumpang tindih pun salah pilah karenaberat_gramnyaris tak terdengar oleh margin. StandardScalermenyeterakan keduanya (z-score, sama seperti chapter KNN): akurasi melonjak ke 1,00 pada 9 lot uji, dan hanya 5 dari 21 titik latih yang berperan sebagai vektor pendukung — sisanya dudung aman di belakang margin.
Kernel: Ketika Garis Lurus Tidak Cukup #
Hyperplane lurus tidak selalu ada. Kasus klasik dari dunia ritel: “Toko Kopi Kita” menguji harga menu andalan dan menemukan bahwa penjualan di atas target (laku=1) justru muncul di dua ujung spektrum — harga promo di bawah Rp12 ribu yang memancing pemburu diskon, dan harga premium di atas Rp26 ribu yang menarik pembeli kualitas — sementara harga menengah Rp14-23 ribu justru kalah bersaing (laku=0). Kelas laku=1 membentuk dua gugus di kiri-kanan dengan pita laku=0 di tengah; tidak ada satu garis lurus pun yang mampu membelah pola seperti ini.
Di sinilah kernel masuk. Kernel adalah trik matematis yang menghitung jarak kompleks di ruang berdimensi lebih tinggi tanpa benar-benar memindahkan data ke sana — dan di ruang itu, batas yang melengkung di dunia asal bisa menjadi lurus. Kernel linear tetap pada garis lurus; kernel rbf (radial basis function) membentuk batas melengkung mengikuti gugus data:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
percobaan = pd.DataFrame({
"harga_gelas": [8500, 9000, 9500, 10000, 10500, 11000, 9000, 10000, 11500,
10500, 26500, 27000, 28000, 29000, 30000, 31000, 32000,
27500, 14000, 15000, 16000, 17000, 18000, 19000, 20000,
21000, 22000, 23000, 14500, 19500],
"rating_minggu": [4.2, 3.9, 4.5, 4.0, 4.3, 4.6, 4.4, 4.1, 3.8, 4.7,
4.5, 4.8, 4.3, 4.6, 4.9, 4.4, 4.7, 4.2,
4.0, 4.4, 4.6, 4.2, 4.8, 4.1, 4.5, 4.3, 4.7, 4.0, 4.6, 4.9],
"laku": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
})
fitur = ["harga_gelas", "rating_minggu"]
X = percobaan[fitur]
y = percobaan["laku"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3,
stratify=y, random_state=42)
skala = StandardScaler()
X_latih_skala = skala.fit_transform(X_latih)
X_uji_skala = skala.transform(X_uji)
print("kernel | akurasi latih | akurasi uji | vektor pendukung")
for nama in ["linear", "rbf"]:
model = SVC(kernel=nama, C=1.0)
model.fit(X_latih_skala, y_latih)
print("%-7s | %.2f | %.2f | %d"
% (nama, model.score(X_latih_skala, y_latih),
model.score(X_uji_skala, y_uji), model.n_support_.sum()))Output yang Dihasilkan:
kernel | akurasi latih | akurasi uji | vektor pendukung
linear | 0.62 | 0.56 | 18
rbf | 0.95 | 0.89 | 18Mari kita telaah hasilnya:
linearmentok di 0,56 pada data uji — bukan karena SVM lemah, melainkan karena bentuk datanya memang tidak bisa dipisah satu garis: ujung kiri dan ujung kanan sama-samalaku=1, pita tengahlaku=0. Garis mana pun yang memisahkan dua ujung pasti memotong pita tengah.rbfmencapai 0,89 dengan membengkokkan batas mengikuti pita tengah — inilah pekerjaan kernel: memindahkan masalah ke ruang dimana pola “dua gugus dengan pita di tengah” menjadi terpisah garis.- Jumlah vektor pendukung yang besar (18 dari 21 titik latih) pada kedua kernel menandakan kelas-kelas ini saling berkelindan di sekitar batas — margin yang bersih sulit ditemukan pada data harga seperti ini.
Parameter C: Menimbang Lebar Margin #
Data nyata jarang rapi sempurna; hampir selalu ada titik yang melanggar zona aman. Parameter C mengatur sikap SVM terhadap pelanggaran itu: C kecil berarti pelanggaran dibiarkan demi margin yang tetap lebar dan tenang, sedangkan C besar berarti setiap pelanggaran ditindak tegas sampai margin menyempit mengikuti titik-titiknya. Kita amati dampaknya pada data biji kopi yang telah diskalakan:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
biji = pd.DataFrame({
"panjang_mm": [9.4, 10.1, 10.8, 11.2, 9.8, 10.5, 11.6, 9.9, 10.3, 11.0,
9.6, 10.7, 11.4, 10.2, 10.9,
8.4, 9.1, 8.8, 9.6, 8.2, 9.3, 8.6, 9.8, 8.9, 9.5,
8.3, 9.0, 9.7, 8.5, 9.05],
"berat_gram": [0.21, 0.19, 0.22, 0.20, 0.23, 0.18, 0.24, 0.20, 0.22, 0.19,
0.22, 0.21, 0.18, 0.24, 0.155,
0.12, 0.14, 0.11, 0.13, 0.15, 0.10, 0.13, 0.12, 0.16, 0.11,
0.14, 0.15, 0.14, 0.12, 0.175],
"arabika": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
})
X = biji[["panjang_mm", "berat_gram"]]
y = biji["arabika"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3,
stratify=y, random_state=42)
skala = StandardScaler()
X_latih_skala = skala.fit_transform(X_latih)
X_uji_skala = skala.transform(X_uji)
print(" C | akurasi latih | akurasi uji | vektor pendukung")
for c in [0.01, 1.0, 100.0]:
model = SVC(kernel="linear", C=c)
model.fit(X_latih_skala, y_latih)
print("%5.2f | %.2f | %.2f | %d"
% (c, model.score(X_latih_skala, y_latih),
model.score(X_uji_skala, y_uji), model.n_support_.sum()))Output yang Dihasilkan:
C | akurasi latih | akurasi uji | vektor pendukung
0.01 | 0.52 | 0.44 | 20
1.00 | 1.00 | 1.00 | 5
100.00 | 1.00 | 1.00 | 3Tabel ini memperlihatkan dua arah kegagalan yang sama tuanya dengan bias-variance:
C=0.01terlalu pemalu: penalti pelanggaran nyaris nol sehingga SVM memilih margin super lebar yang mengabaikan hampir seluruh struktur data — akurasi latih 0,52 berarti model nyaris tidak belajar (underfitting), dan 20 dari 21 titik menjadi vektor pendukung karena hyperplane tidak berpihak dengan yakin.C=1.0sudah optimal di sini: margin cukup tegas untuk mengikuti pola panjang-berat, akurasi uji 1,00, cukup 5 vektor pendukung.C=100tidak lagi memperbaiki hasil tetapi menipiskan margin: hanya 3 vektor pendukung yang menopang keputusan — pada data uji yang sedikit berbeda, hyperplane yang terlalu menempel pada segelintir titik ini lebih rapuh.Cbesar adalah pintu menuju overfitting ketika datanya berkelindan.
Kekuatan dan Kelemahan SVM #
| Aspek | Keterangan |
|---|---|
| Tangguh di dimensi banyak | Margin ditentukan segelintir vektor pendukung; cocok saat fitur jauh lebih banyak dari sampel |
| Efektif pada data kecil-menengah | Punya kecenderungan menggeneralisasi baik walau datanya tidak besar |
| Wajib penskalaan fitur | Margin adalah ukuran jarak; 0,78 lawan 1,00 pada data biji kopi kita |
| Kernel untuk batas melengkung | rbf membenahi pola yang mustahil dipisah garis (0,56 menjadi 0,89) |
| Penyetelan cukup rumit | Kombinasi C, kernel, dan parameter kernel (mis. gamma) perlu dicoba bersama |
| Prediksi melambat pada data besar | Melatih SVM pada puluhan ribu baris bisa sangat lambat dibanding model pohon |
| Sulit dijelaskan langsung | Tidak ada koefisien sesederhana regresi untuk ditunjukkan ke pemangku kepentingan |
Kapan Kita Memakainya #
SVM adalah pilihan kuat ketika jumlah fitur besar relatif terhadap jumlah baris — misalnya hasil pengukuran sensor, data biomedis, atau representasi teks — dan ketika kita menginginkan batas keputusan yang presisi dari data yang tidak terlalu besar. Untuk data tabular besar dengan jutaan baris, keluarga pohon dari chapter-chapter sebelumnya biasanya lebih praktis. Seluruh model kita sejauh ini bekerja dengan angka: fitur numerik yang diskalakan, jarak, margin. Chapter penutup Section ini berpindah ke jenis data yang berbeda wujud — teks bebas berbahasa manusia — dan memperkenalkan model yang justru bekerja lewat probabilitas: Naive Bayes.
Rangkuman #
- SVM mencari hyperplane pemisah dengan margin maksimum; hanya titik di tepi margin (vektor pendukung) yang menentukan hasil — 5 dari 21 titik latih pada data biji kopi kita.
- Penskalaan fitur adalah prasyarat: geometri margin digiring oleh fitur berskala besar; akurasi biji kopi melompat dari 0,78 ke 1,00 setelah
StandardScaler. - Kernel
linearmenghasilkan batas lurus; kernelrbfmembengkokkan batas lewat ruang dimensi lebih tinggi — pada percobaan harga (pola dua gugus dengan pita tengah),rbf0,89 lawanlinear0,56. Cmenimbang lebar margin lawan ketegasan pelanggaran: terlalu kecil membuat model nyaris tidak belajar (0,44), terlalu besar menipiskan margin hingga rawan overfitting.- SVM kuat pada data dimensi banyak berukuran kecil-menengah, tetapi lambat pada data besar dan tidak butuh penskalaan pada model pohon.
Prediksi SVM berbunyi “kelas mana” tanpa menayangkan rasa yakinnya. Model terakhir Section ini bekerja persis sebaliknya: seluruh keputusannya adalah perkalian probabilitas atas kata-kata — mari kita tutup dengan Naive Bayes pada chapter Naive Bayes .