Support Vector Machine (SVM) adalah algoritma supervised learning yang digunakan untuk klasifikasi dan regresi. Prinsip utama SVM adalah mencari hyperplane optimal yang memisahkan dua kelas dengan margin maksimum (Cortes & Vapnik, 1995). Dalam kasus data non-linear, SVM menggunakan teknik kernel trick untuk memetakan data ke ruang berdimensi lebih tinggi. SVM dibagi menjadi dua model, yaitu model linear dan model non-linear.
Dataset yang digunakan dalam penelitian ini adalah Breast Cancer Dataset. Dataset ini mengandung informasi tentang berbagai fitur medis yang digunakan untuk mengklasifikasikan apakah tumor yang ditemukan pada pasien adalah jinak (benign) atau ganas (malignant). ## Load Library Memuat berbagai library penting seperti e1071 untuk SVM, caret untuk ML workflow, ggplot2 untuk visualisasi, corrplot untuk korelasi antar fitur, dan mlbench untuk dataset.
# Load libraries
# Load libraries
library(e1071) # SVM
library(caret) # Machine learning toolkit
library(ggplot2) # Visualisasi
library(dplyr) # Data manipulation
library(gridExtra) # Multiple plots
library(RColorBrewer) # Color palettes
library(pROC) # ROC curves
library(tidyr) # Data tidying (untuk pivot functions)
library(knitr) # Kable tables
library(mlbench) # For Dataset
library(corrplot)
Eksplorasi data dan visualisasi awal ini dilakukan untuk memahami struktur dan distribusi data sebelum membangun model.
# Load dataset
data(BreastCancer)
df <- BreastCancer
# Informasi dasar dataset
cat("Dimensi dataset:", dim(df), "\n")
## Dimensi dataset: 699 11
cat("Jumlah missing values:", sum(is.na(df)), "\n")
## Jumlah missing values: 16
# Struktur data
str(df)
## 'data.frame': 699 obs. of 11 variables:
## $ Id : chr "1000025" "1002945" "1015425" "1016277" ...
## $ Cl.thickness : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 5 5 3 6 4 8 1 2 2 4 ...
## $ Cell.size : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 1 4 1 8 1 10 1 1 1 2 ...
## $ Cell.shape : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 1 4 1 8 1 10 1 2 1 1 ...
## $ Marg.adhesion : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 1 5 1 1 3 8 1 1 1 1 ...
## $ Epith.c.size : Ord.factor w/ 10 levels "1"<"2"<"3"<"4"<..: 2 7 2 3 2 7 2 2 2 2 ...
## $ Bare.nuclei : Factor w/ 10 levels "1","2","3","4",..: 1 10 2 4 1 10 10 1 1 1 ...
## $ Bl.cromatin : Factor w/ 10 levels "1","2","3","4",..: 3 3 3 3 3 9 3 3 1 2 ...
## $ Normal.nucleoli: Factor w/ 10 levels "1","2","3","4",..: 1 2 1 7 1 7 1 1 1 1 ...
## $ Mitoses : Factor w/ 9 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 5 1 ...
## $ Class : Factor w/ 2 levels "benign","malignant": 1 1 1 1 1 2 1 1 1 1 ...
# Summary statistik
summary(df)
## Id Cl.thickness Cell.size Cell.shape Marg.adhesion
## Length:699 1 :145 1 :384 1 :353 1 :407
## Class :character 5 :130 10 : 67 2 : 59 2 : 58
## Mode :character 3 :108 3 : 52 10 : 58 3 : 58
## 4 : 80 2 : 45 3 : 56 10 : 55
## 10 : 69 4 : 40 4 : 44 4 : 33
## 2 : 50 5 : 30 5 : 34 8 : 25
## (Other):117 (Other): 81 (Other): 95 (Other): 63
## Epith.c.size Bare.nuclei Bl.cromatin Normal.nucleoli Mitoses
## 2 :386 1 :402 2 :166 1 :443 1 :579
## 3 : 72 10 :132 3 :165 10 : 61 2 : 35
## 4 : 48 2 : 30 1 :152 3 : 44 3 : 33
## 1 : 47 5 : 30 7 : 73 2 : 36 10 : 14
## 6 : 41 3 : 28 4 : 40 8 : 24 4 : 12
## 5 : 39 (Other): 61 5 : 34 6 : 22 7 : 9
## (Other): 66 NA's : 16 (Other): 69 (Other): 69 (Other): 17
## Class
## benign :458
## malignant:241
##
##
##
##
##
# Distribusi kelas
table(df$Class)
##
## benign malignant
## 458 241
# Plot distribusi kelas
ggplot(df, aes(x = Class, fill = Class)) +
geom_bar(width = 0.5) +
scale_fill_manual(values = c("skyblue", "salmon")) +
labs(title = "Distribusi Kelas: Benign vs Malignant",
x = "Kelas",
y = "Jumlah") +
theme_minimal()
Hasil Eksplorasi: 1) Dataset terdiri dari 699 observasi, 11 variabel, 16
nilai NA (missing) 2) Dataset mengandung banyak fitur bertipe ordinal
factor, yang perlu dikonversi ke numerik. 3) Distribusi kelas terdapat
458 observasi benign 241 obervasi malignant. Menunjukkan dataset tidak
terlalu imbalanced, meski kelas benign sedikit lebih dominan (~65%).
# Mengonversi kolom ordinal menjadi numerik
cols_to_convert <- c("Cl.thickness", "Cell.size", "Cell.shape", "Marg.adhesion",
"Epith.c.size", "Bare.nuclei", "Bl.cromatin",
"Normal.nucleoli", "Mitoses")
df[cols_to_convert] <- lapply(df[cols_to_convert], as.numeric)
# Memilih variabel numerik selain 'Class' dan 'Id'
numeric_vars <- df %>%
select(-Class, -Id) %>%
select(where(is.numeric))
# Mengecek struktur data numerik
str(numeric_vars)
## 'data.frame': 699 obs. of 9 variables:
## $ Cl.thickness : num 5 5 3 6 4 8 1 2 2 4 ...
## $ Cell.size : num 1 4 1 8 1 10 1 1 1 2 ...
## $ Cell.shape : num 1 4 1 8 1 10 1 2 1 1 ...
## $ Marg.adhesion : num 1 5 1 1 3 8 1 1 1 1 ...
## $ Epith.c.size : num 2 7 2 3 2 7 2 2 2 2 ...
## $ Bare.nuclei : num 1 10 2 4 1 10 10 1 1 1 ...
## $ Bl.cromatin : num 3 3 3 3 3 9 3 3 1 2 ...
## $ Normal.nucleoli: num 1 2 1 7 1 7 1 1 1 1 ...
## $ Mitoses : num 1 1 1 1 1 1 1 1 5 1 ...
# Menghitung matriks korelasi (dengan observasi lengkap saja)
correlation_matrix <- cor(numeric_vars, use = "complete.obs")
# Visualisasi korelasi antar variabel
corrplot(correlation_matrix,
method = "color", # bentuk visual: warna gradasi
type = "upper", # hanya segitiga atas
col = colorRampPalette(c("red", "white", "blue"))(200), # warna: merah ke biru
tl.col = "black", # warna teks label
tl.srt = 45, # rotasi label variabel
tl.cex = 0.8, # ukuran teks label
number.cex = 0.7, # ukuran angka korelasi (jika ditampilkan)
addCoef.col = "black", # warna angka korelasi
title = "Matriks Korelasi Variabel Numerik",
mar = c(0,0,2,0), # margin atas untuk judul
diag = FALSE) # tidak menampilkan diagonal
Heatmap matriks korelasi menunjukkan korelasi kuat antara Cell.size dan
Cell.shape (r = 0.91). Di sisi lain, variabel Mitoses tampak memiliki
korelasi yang relatif lemah dengan sebagian besar variabel lain (umumnya
di bawah 0.50), sehingga dapat dianggap sebagai variabel yang lebih
independen. Korelasi yang tinggi antar variabel perlu diwaspadai karena
dapat menyebabkan multikolinearitas, terutama jika digunakan dalam
model-model linier. Namun, pada metode yang lebih robust seperti Support
Vector Machine (SVM), hal ini cenderung tidak menjadi masalah besar
meskipun tetap relevan dalam interpretasi model.
Langkah: 1. Hapus data NA → tersisa 683 observasi 2. Konversi faktor ordinal ke numerik 3. Standarisasi fitur (menggunakan scale) 4. Split data: 80% training (548), 20% testing (135)
# Menghilangkan baris dengan nilai yang hilang
df_clean <- na.omit(df)
cat("Jumlah data setelah menghapus missing values:", nrow(df_clean), "baris\n")
## Jumlah data setelah menghapus missing values: 683 baris
# Memilih fitur numerik dan target kelas untuk analisis
df_selected <- df_clean %>%
select(Class, Cl.thickness, Cell.size, Cell.shape, Marg.adhesion,
Epith.c.size, Bare.nuclei, Bl.cromatin, Normal.nucleoli, Mitoses)
# Melakukan standardisasi pada variabel numerik
df_selected[, -1] <- scale(df_selected[, -1])
# Membagi data menjadi training (80%) dan testing (20%) secara acak dengan seed tertentu
set.seed(123)
idx_train <- createDataPartition(df_selected$Class, p = 0.8, list = FALSE)
train_data <- df_selected[idx_train, ]
test_data <- df_selected[-idx_train, ]
cat("Jumlah baris data training:", nrow(train_data), "\n")
## Jumlah baris data training: 548
cat("Jumlah baris data testing:", nrow(test_data), "\n")
## Jumlah baris data testing: 135
# Menghitung dan menampilkan frekuensi kelas pada data training dan testing
train_class_freq <- table(train_data$Class)
test_class_freq <- table(test_data$Class)
kable(rbind(train_class_freq, test_class_freq),
caption = "Frekuensi Kelas pada Data Training dan Testing")
benign | malignant | |
---|---|---|
train_class_freq | 356 | 192 |
test_class_freq | 88 | 47 |
Data telah dibersihkan dari missing values dan dibagi menjadi set training (80%) dan testing (20%). Dari hasil pembagian data, terlihat bahwa kelas benign lebih dominan dibandingkan kelas malignant di kedua set. Pada data training terdapat 356 sampel benign dan 192 sampel malignant, sedangkan pada data testing terdapat 88 sampel benign dan 47 sampel malignant.
Distribusi kelas ini relatif seimbang antar set training dan testing, sehingga model yang dibangun diharapkan dapat belajar dari representasi kedua kelas yang proporsional dan menguji performa secara adil pada data baru.
SVM Linear merupakan pendekatan yang digunakan ketika data bersifat linearly separable, yaitu data dapat dipisahkan oleh sebuah garis lurus (atau hyperplane dalam dimensi tinggi). Tujuan utama model ini adalah untuk mencari hyperplane optimal yang memaksimalkan margin (jarak terdekat antara kelas positif dan negatif terhadap hyperplane). Model ini bekerja dengan mengoptimasi: \[ \min \frac{1}{2} \|w\|^2 + C \sum_{i=1}^n \xi_i \] dengan kendala: \[ y_i (w^T x_i + b) \geq 1 - \xi_i, \quad \xi_i \geq 0 \]
Parameter C (cost) mengatur trade-off antara margin maksimum dan kesalahan klasifikasi: - C kecil → toleran terhadap kesalahan → margin lebih besar - C besar → memaksa klasifikasi benar → margin kecil namun berisiko overfitting
Langkah ini melakukan pelatihan model SVM dengan kernel linear menggunakan data training yang telah disiapkan sebelumnya. Model dilatih untuk memisahkan kelas benign dan malignant berdasarkan fitur-fitur yang tersedia. Setelah model dilatih, dilakukan prediksi terhadap data testing untuk menguji generalisasi model. Hasil prediksi dievaluasi menggunakan confusion matrix untuk mengetahui akurasi dan distribusi kesalahan klasifikasi antar kelas.
# Training SVM Linear
svm_linear <- svm(Class ~ ., data = train_data,
kernel = "linear", cost = 1, scale = FALSE)
# Summary model
summary(svm_linear)
##
## Call:
## svm(formula = Class ~ ., data = train_data, kernel = "linear", cost = 1,
## scale = FALSE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 1
##
## Number of Support Vectors: 43
##
## ( 21 22 )
##
##
## Number of Classes: 2
##
## Levels:
## benign malignant
# Prediksi pada data testing
pred_linear <- predict(svm_linear, test_data)
# Confusion Matrix
cm_linear <- confusionMatrix(pred_linear, test_data$Class)
print(cm_linear)
## Confusion Matrix and Statistics
##
## Reference
## Prediction benign malignant
## benign 87 2
## malignant 1 45
##
## Accuracy : 0.9778
## 95% CI : (0.9364, 0.9954)
## No Information Rate : 0.6519
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.9508
##
## Mcnemar's Test P-Value : 1
##
## Sensitivity : 0.9886
## Specificity : 0.9574
## Pos Pred Value : 0.9775
## Neg Pred Value : 0.9783
## Prevalence : 0.6519
## Detection Rate : 0.6444
## Detection Prevalence : 0.6593
## Balanced Accuracy : 0.9730
##
## 'Positive' Class : benign
##
Model SVM dengan kernel linear dan parameter cost = 1 dilatih pada data training. Model menggunakan 43 support vector (21 dari kelas benign, 22 dari kelas malignant). Evaluasi performa model yang diperoleh dari Confusion Matrix adalah sebagai berikut. - Akurasi tinggi, yaitu 97.78%, dengan confidence interval 93.64%–99.54%. - Sensitivitas (recall) kelas benign sebesar 98.86%, menunjukkan model sangat baik dalam mendeteksi kelas benign. - Spesifisitas kelas malignant sebesar 95.74%, menandakan kemampuan model mengenali kelas malignant dengan baik.
Evaluasi model dilakukan dengan menghitung metrik performa utama seperti akurasi, precision, recall, dan F1-score. Karena struktur output confusion matrix bisa berbeda antara binary dan multiclass, kode ini juga menangani fleksibilitas tersebut. Nilai-nilai yang hilang (NA) diatasi agar evaluasi tetap akurat. Semua hasil dirangkum dalam bentuk tabel agar mudah dibaca dan dibandingkan.
# Ambil nilai akurasi dari confusion matrix
acc_linear <- cm_linear$overall['Accuracy']
# Cek struktur byClass (berlaku untuk binary dan multiclass)
if (!is.null(cm_linear$byClass) && is.matrix(cm_linear$byClass)) {
prec_linear <- cm_linear$byClass[, 'Pos Pred Value']
rec_linear <- cm_linear$byClass[, 'Sensitivity']
f1_linear <- cm_linear$byClass[, 'F1']
} else {
# Penanganan jika hanya ada dua kelas
prec_linear <- c(cm_linear$byClass['Pos Pred Value'])
rec_linear <- c(cm_linear$byClass['Sensitivity'])
f1_linear <- c(cm_linear$byClass['F1'])
}
# Ganti NA dengan nol agar tidak mengganggu perhitungan
prec_linear[is.na(prec_linear)] <- 0
rec_linear[is.na(rec_linear)] <- 0
f1_linear[is.na(f1_linear)] <- 0
# Susun metrik evaluasi ke dalam data frame
svm_linear_metrics <- data.frame(
Metrics = c("Accuracy",
paste0("Precision_", names(prec_linear)),
paste0("Recall_", names(rec_linear)),
paste0("F1_", names(f1_linear))),
Values = c(acc_linear, prec_linear, rec_linear, f1_linear)
)
# Tampilkan sebagai tabel
kable(svm_linear_metrics, digits = 4, caption = "Ringkasan Evaluasi SVM Linear")
Metrics | Values | |
---|---|---|
Accuracy | Accuracy | 0.9778 |
Pos Pred Value | Precision_Pos Pred Value | 0.9775 |
Sensitivity | Recall_Sensitivity | 0.9886 |
F1 | F1_F1 | 0.9831 |
Radial Basis Function (RBF) adalah kernel populer untuk menangani data tidak linear. Formula RBF kernel: \[ K(x_i, x_j) = \exp(-\gamma \|x_i - x_j\|^2) \] Gamma mengontrol jangkauan pengaruh titik data: - Gamma kecil → boundary halus - Gamma besar → boundary tajam (overfitting)
Pada bagian ini, model SVM dilatih kembali tetapi dengan kernel Radial Basis Function (RBF) yang lebih cocok untuk data non-linear. Parameter cost dan gamma digunakan untuk mengontrol margin dan kompleksitas model. Setelah pelatihan, prediksi dilakukan terhadap data testing dan hasilnya dievaluasi menggunakan confusion matrix.
# Training SVM dengan RBF kernel
svm_rbf <- svm(Class ~ ., data = train_data,
kernel = "radial", cost = 1, gamma = 0.25, scale = FALSE)
# Summary model
summary(svm_rbf)
##
## Call:
## svm(formula = Class ~ ., data = train_data, kernel = "radial", cost = 1,
## gamma = 0.25, scale = FALSE)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 1
##
## Number of Support Vectors: 149
##
## ( 33 116 )
##
##
## Number of Classes: 2
##
## Levels:
## benign malignant
# Prediksi pada data testing
pred_rbf <- predict(svm_rbf, test_data)
# Confusion Matrix
cm_rbf <- confusionMatrix(pred_rbf, test_data$Class)
print(cm_rbf)
## Confusion Matrix and Statistics
##
## Reference
## Prediction benign malignant
## benign 85 1
## malignant 3 46
##
## Accuracy : 0.9704
## 95% CI : (0.9259, 0.9919)
## No Information Rate : 0.6519
## P-Value [Acc > NIR] : <2e-16
##
## Kappa : 0.9354
##
## Mcnemar's Test P-Value : 0.6171
##
## Sensitivity : 0.9659
## Specificity : 0.9787
## Pos Pred Value : 0.9884
## Neg Pred Value : 0.9388
## Prevalence : 0.6519
## Detection Rate : 0.6296
## Detection Prevalence : 0.6370
## Balanced Accuracy : 0.9723
##
## 'Positive' Class : benign
##
Tahapan evaluasi untuk model SVM RBF dilakukan dengan cara yang sama seperti sebelumnya. Metrik seperti akurasi, precision, recall, dan F1-score dihitung dari confusion matrix, dan dirangkum dalam sebuah tabel. Ini memungkinkan perbandingan langsung dengan model linear.
# Menghitung akurasi model SVM Non-Linear (RBF)
accuracy_rbf <- cm_rbf$overall['Accuracy']
# Mengekstrak nilai Precision, Recall, dan F1-score dari confusion matrix
# Menangani kemungkinan struktur byClass berbeda (multi-class vs binary)
if (!is.null(cm_rbf$byClass) && is.matrix(cm_rbf$byClass)) {
precision_rbf <- cm_rbf$byClass[, 'Pos Pred Value']
recall_rbf <- cm_rbf$byClass[, 'Sensitivity']
f1_rbf <- cm_rbf$byClass[, 'F1']
} else {
# Jika struktur byClass bukan matriks (misal untuk binary classification)
precision_rbf <- c(cm_rbf$byClass['Pos Pred Value'])
recall_rbf <- c(cm_rbf$byClass['Sensitivity'])
f1_rbf <- c(cm_rbf$byClass['F1'])
}
# Mengganti nilai NA dengan 0 pada hasil evaluasi
precision_rbf[is.na(precision_rbf)] <- 0
recall_rbf[is.na(recall_rbf)] <- 0
f1_rbf[is.na(f1_rbf)] <- 0
# Membuat data frame berisi metrik evaluasi model
eval_rbf <- data.frame(
Metrics = c("Accuracy",
paste0("Precision_", names(precision_rbf)),
paste0("Recall_", names(recall_rbf)),
paste0("F1_", names(f1_rbf))),
Values = c(accuracy_rbf, precision_rbf, recall_rbf, f1_rbf)
)
# Menampilkan hasil evaluasi dalam bentuk tabel
kable(eval_rbf, digits = 4, caption = "Ringkasan Evaluasi SVM Non-Linear dengan RBF")
Metrics | Values | |
---|---|---|
Accuracy | Accuracy | 0.9704 |
Pos Pred Value | Precision_Pos Pred Value | 0.9884 |
Sensitivity | Recall_Sensitivity | 0.9659 |
F1 | F1_F1 | 0.9770 |
Langkah ini menggabungkan hasil evaluasi dari kedua model (SVM linear dan RBF) ke dalam satu tabel untuk memudahkan perbandingan. Selain itu, dibuat visualisasi berupa grafik batang untuk membandingkan akurasi kedua model secara visual.
# Pastikan kedua data frame evaluasi punya jumlah baris yang sama
min_rows <- min(nrow(svm_linear_metrics), nrow(eval_rbf))
linear_eval_trim <- svm_linear_metrics[1:min_rows, ]
rbf_eval_trim <- eval_rbf[1:min_rows, ]
# Satukan metrik dan nilai dari kedua model dalam satu tabel
perf_comparison <- data.frame(
Metric = linear_eval_trim$Metrics,
Linear_SVM = linear_eval_trim$Values,
RBF_SVM = rbf_eval_trim$Values
)
kable(perf_comparison, digits = 4,
caption = "Tabel Perbandingan Kinerja SVM Linear dan RBF")
Metric | Linear_SVM | RBF_SVM |
---|---|---|
Accuracy | 0.9778 | 0.9704 |
Precision_Pos Pred Value | 0.9775 | 0.9884 |
Recall_Sensitivity | 0.9886 | 0.9659 |
F1_F1 | 0.9831 | 0.9770 |
# Data frame untuk membandingkan akurasi kedua model
acc_df <- data.frame(
Model = c("Linear SVM", "RBF SVM"),
Accuracy = c(acc_linear, accuracy_rbf)
)
# Grafik batang perbandingan akurasi dengan palet warna berbeda dan style yang lebih clean
ggplot(acc_df, aes(x = Model, y = Accuracy, fill = Model)) +
geom_bar(stat = "identity", color = "black", width = 0.6) +
geom_text(aes(label = sprintf("%.4f", Accuracy)), vjust = -0.3, size = 4, fontface = "bold") +
labs(title = "Visualisasi Akurasi SVM: Linear vs RBF",
y = "Nilai Akurasi",
x = "Jenis Model") +
theme_light() +
scale_fill_manual(values = c("#1b9e77", "#d95f02")) +
coord_cartesian(ylim = c(0, 1))
Tuning bertujuan mencari kombinasi optimal C dan gamma melalui grid search, dilakukan dengan cross-validation untuk menghindari overfitting.
Bagian ini bertujuan menemukan kombinasi parameter cost dan gamma terbaik untuk SVM RBF menggunakan teknik grid search dengan validasi silang. Proses ini membantu menghindari overfitting dan memastikan model memiliki performa optimal pada data testing. Model terbaik disimpan dan digunakan untuk prediksi serta evaluasi lanjutan.
# Melakukan pencarian parameter terbaik untuk SVM dengan kernel RBF menggunakan grid search
grid_search <- tune(svm, Class ~ ., data = train_data,
kernel = "radial",
ranges = list(cost = c(0.1, 1, 10, 100),
gamma = c(0.01, 0.1, 1, 10)))
# Menampilkan ringkasan hasil tuning parameter
summary(grid_search)
##
## Parameter tuning of 'svm':
##
## - sampling method: 10-fold cross validation
##
## - best parameters:
## cost gamma
## 1 0.01
##
## - best performance: 0.02912458
##
## - Detailed performance results:
## cost gamma error dispersion
## 1 0.1 0.01 0.03646465 0.02421542
## 2 1.0 0.01 0.02912458 0.03228551
## 3 10.0 0.01 0.03276094 0.03405321
## 4 100.0 0.01 0.03094276 0.03094732
## 5 0.1 0.10 0.03461279 0.02900786
## 6 1.0 0.10 0.03276094 0.03405321
## 7 10.0 0.10 0.04373737 0.02731977
## 8 100.0 0.10 0.06387205 0.03356664
## 9 0.1 1.00 0.06377104 0.03334984
## 10 1.0 1.00 0.05282828 0.03015989
## 11 10.0 1.00 0.04737374 0.02730483
## 12 100.0 1.00 0.04737374 0.02730483
## 13 0.1 10.00 0.35050505 0.06434433
## 14 1.0 10.00 0.14589226 0.03988949
## 15 10.0 10.00 0.13127946 0.03582566
## 16 100.0 10.00 0.13127946 0.03582566
#Mengambil parameter terbaik hasil tuning
optimal_params <- grid_search$best.parameters
message(sprintf("Parameter terbaik ditemukan: Cost = %.2f, Gamma = %.2f",
optimal_params$cost, optimal_params$gamma))
# Membuat model SVM dengan parameter optimal tersebut
svm_optimized <- grid_search$best.model
# Melakukan prediksi menggunakan model hasil tuning
predictions_optimized <- predict(svm_optimized, test_data)
# Membuat confusion matrix dari prediksi tersebut
cm_optimized <- confusionMatrix(predictions_optimized, test_data$Class)
# Menampilkan akurasi model yang sudah dituning
message(sprintf("Akurasi model hasil tuning: %.4f", cm_optimized$overall['Accuracy']))
Untuk memberikan gambaran visual dari hasil tuning, heatmap error rate ditampilkan berdasarkan kombinasi nilai cost dan gamma. Area dengan warna lebih terang menunjukkan performa yang lebih baik (error lebih rendah). # Visualisasi heatmap dari hasil tuning parameter untuk melihat tingkat error
svm_tuned <- grid_search$performances
ggplot(svm_tuned, aes(x = factor(cost), y = factor(gamma), fill = error)) +
geom_tile(color = "gray70") + # memberi border tipis biar kotak lebih jelas
scale_fill_gradient(low = "#f0f0f0", high = "#b2182b") + # warna dari abu muda ke merah tua
labs(title = "Heat Map Tingkat Kesalahan pada Parameter Tuning",
x = "Nilai Cost", y = "Nilai Gamma", fill = "Tingkat Error") +
theme_light() +
theme(plot.title = element_text(face = "bold", hjust = 0.5))
Visualisasi decision boundary membantu memahami cara model memisahkan kelas. Biasanya menggunakan 2 fitur penting untuk memproyeksikan ke 2D.
Visualisasi ini digunakan untuk melihat secara intuitif bagaimana model memisahkan kelas benign dan malignant di ruang dua dimensi. Dua fitur dipilih untuk mempermudah pemetaan ke bidang 2D. Visualisasi mencakup decision boundary dari model linear dan RBF agar dapat dibandingkan secara langsung.
# Memilih dua fitur utama untuk visualisasi 2D: Cl.thickness dan Cell.size
train_vis <- train_data %>% select(Class, Cl.thickness, Cell.size)
test_vis <- test_data %>% select(Class, Cl.thickness, Cell.size)
# Membangun model SVM dengan kernel linear untuk data 2D
svm_linear_2d <- svm(Class ~ ., data = train_vis, kernel = "linear", cost = 1)
# Membangun model SVM dengan kernel RBF menggunakan parameter terbaik hasil tuning
svm_rbf_2d <- svm(Class ~ ., data = train_vis, kernel = "radial",
cost = optimal_params$cost, gamma = optimal_params$gamma)
# Fungsi untuk menggambar batas keputusan model pada ruang 2 dimensi
plot_svm_boundary <- function(model, dataset, plot_title) {
# Membuat grid titik prediksi untuk menggambarkan decision boundary
x_vals <- seq(min(dataset$Cl.thickness) - 0.5, max(dataset$Cl.thickness) + 0.5, length.out = 100)
y_vals <- seq(min(dataset$Cell.size) - 0.5, max(dataset$Cell.size) + 0.5, length.out = 100)
grid_points <- expand.grid(Cl.thickness = x_vals, Cell.size = y_vals)
# Melakukan prediksi kelas pada grid titik
grid_points$Class <- predict(model, grid_points)
# Membuat plot dengan titik data dan latar warna sesuai prediksi
ggplot() +
geom_point(data = grid_points, aes(x = Cl.thickness, y = Cell.size, color = Class),
alpha = 0.25, size = 0.6) +
geom_point(data = dataset, aes(x = Cl.thickness, y = Cell.size, color = Class), size = 2) +
labs(title = plot_title,
x = "Cl.thickness (Standarisasi)",
y = "Cell.size (Standarisasi)") +
theme_classic() +
scale_color_brewer(type = "qual", palette = "Dark2")
}
# Menampilkan decision boundary untuk SVM linear dan RBF secara berdampingan
plot1 <- plot_svm_boundary(svm_linear_2d, train_vis, "Batas Keputusan SVM Linear")
plot2 <- plot_svm_boundary(svm_rbf_2d, train_vis, "Batas Keputusan SVM RBF")
grid.arrange(plot1, plot2, ncol = 2)
Analisis ini mengeksplorasi pengaruh nilai parameter C terhadap akurasi model SVM. Model dilatih dengan beberapa nilai C tetap menggunakan gamma yang sama, dan akurasinya dicatat. Hasil kemudian divisualisasikan untuk melihat tren hubungan antara C dan performa model.
# Mengevaluasi performa SVM dengan kernel RBF pada beberapa nilai parameter C, gamma tetap di 0.25
parameter_c <- c(0.01, 0.1, 1, 10, 100)
results_c <- data.frame(Cost = parameter_c, Accuracy = numeric(length(parameter_c)))
for (idx in seq_along(parameter_c)) {
model_c <- svm(Class ~ ., data = train_data, kernel = "radial",
cost = parameter_c[idx], gamma = 0.25, scale = FALSE)
predictions_c <- predict(model_c, test_data)
cm_c <- confusionMatrix(predictions_c, test_data$Class)
results_c$Accuracy[idx] <- cm_c$overall['Accuracy']
}
# Grafik perubahan akurasi terhadap nilai logaritma basis 10 dari parameter C
ggplot(results_c, aes(x = log10(Cost), y = Accuracy)) +
geom_line(color = "#0072B2", size = 1.2) +
geom_point(color = "#D55E00", size = 3.5) +
labs(title = "Dampak Parameter C pada Akurasi Model SVM",
x = expression(log[10](C)),
y = "Akurasi (%)") +
theme_light()
# Tabel hasil akurasi untuk tiap nilai parameter C
kable(results_c, digits = 4, caption = "Perbandingan Akurasi Model pada Berbagai Nilai C")
Cost | Accuracy |
---|---|
1e-02 | 0.9630 |
1e-01 | 0.9556 |
1e+00 | 0.9704 |
1e+01 | 0.9704 |
1e+02 | 0.9778 |
Serupa dengan sebelumnya, bagian ini mengevaluasi pengaruh parameter gamma terhadap akurasi model, dengan C tetap. Eksperimen dilakukan dengan beberapa nilai gamma, dan hasilnya divisualisasikan untuk memudahkan interpretasi.
# Menguji performa SVM RBF pada berbagai nilai gamma dengan cost tetap (C = 1)
gamma_set <- c(0.001, 0.01, 0.1, 1, 10)
results_gamma <- data.frame(Gamma = gamma_set, Accuracy = numeric(length(gamma_set)))
for (j in seq_along(gamma_set)) {
model_gamma <- svm(Class ~ ., data = train_data, kernel = "radial",
cost = 1, gamma = gamma_set[j], scale = FALSE)
preds_gamma <- predict(model_gamma, test_data)
cm_gamma <- confusionMatrix(preds_gamma, test_data$Class)
results_gamma$Accuracy[j] <- cm_gamma$overall['Accuracy']
}
# Visualisasi perubahan akurasi terhadap logaritma basis 10 dari nilai gamma
ggplot(results_gamma, aes(x = log10(Gamma), y = Accuracy)) +
geom_line(color = "#009E73", size = 1.2) + # hijau yang agak tegas
geom_point(color = "#E69F00", size = 3.5) + # oranye sebagai titik
labs(title = "Dampak Nilai Gamma pada Akurasi Model SVM",
x = expression(log[10](Gamma)),
y = "Akurasi (%)") +
theme_light()
# Tabel hasil akurasi per nilai gamma yang diuji
kable(results_gamma, digits = 4, caption = "Hasil Akurasi untuk Berbagai Nilai Gamma")
Gamma | Accuracy |
---|---|
1e-03 | 0.9778 |
1e-02 | 0.9704 |
1e-01 | 0.9778 |
1e+00 | 0.9556 |
1e+01 | 0.8444 |
# Menampilkan total jumlah support vectors untuk masing-masing model SVM
cat("Total Support Vectors pada SVM Linear :", svm_linear$tot.nSV, "\n")
## Total Support Vectors pada SVM Linear : 43
cat("Total Support Vectors pada SVM RBF :", svm_rbf$tot.nSV, "\n")
## Total Support Vectors pada SVM RBF : 149
# Jumlah support vectors per kelas untuk tiap model
sv_linear_counts <- svm_linear$nSV
sv_rbf_counts <- svm_rbf$nSV
sv_tuned_counts <- svm_tuned$nSV
# Validasi panjang support vector (harus 2: benign dan malignant)
if (length(sv_linear_counts) == 2 &&
length(sv_rbf_counts) == 2 &&
length(sv_tuned_counts) == 2) {
# Menyiapkan data frame perbandingan jumlah support vectors
sv_df <- data.frame(
Class = c("benign", "malignant"),
Linear_SVM = sv_linear_counts,
RBF_SVM = sv_rbf_counts,
Tuned_SVM = sv_tuned_counts
)
# Mengubah format data menjadi long untuk mempermudah plotting
sv_long_format <- sv_df %>%
tidyr::pivot_longer(cols = -Class, names_to = "Model", values_to = "SupportVectorCount")
# Visualisasi perbandingan jumlah support vectors
ggplot(sv_long_format, aes(x = Class, y = SupportVectorCount, fill = Model)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
labs(title = "Perbandingan Jumlah Support Vectors per Kelas",
x = "Kategori Kelas",
y = "Jumlah Support Vectors") +
theme_light() +
scale_fill_brewer(type = "qual", palette = "Pastel1") +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))
} else {
message(" ")
}
Untuk model linear, bobot atau koefisien fitur dapat digunakan untuk mengukur pentingnya fitur terhadap keputusan klasifikasi. Pada bagian ini, dilakukan perhitungan dan visualisasi kontribusi absolut masing-masing fitur untuk membantu memahami fitur mana yang paling berpengaruh.
# Koefisien untuk SVM linear (weight vector)
weights <- t(svm_linear$coefs) %*% svm_linear$SV
feature_names <- colnames(train_data)[-1]
importance_df <- data.frame(
Feature = feature_names,
Importance = abs(as.numeric(weights))
)
importance_df <- importance_df[order(importance_df$Importance, decreasing = TRUE), ]
ggplot(importance_df, aes(x = reorder(Feature, Importance), y = Importance)) +
geom_col(fill = "steelblue") +
coord_flip() +
labs(title = "Feature Importance - SVM Linear",
x = "Fitur", y = "Absolute Weight") +
theme_minimal()
kable(importance_df, digits = 4, caption = "Feature Importance SVM Linear")
Feature | Importance | |
---|---|---|
3 | Cell.shape | 0.6650 |
6 | Bare.nuclei | 0.6199 |
1 | Cl.thickness | 0.5299 |
7 | Bl.cromatin | 0.4316 |
9 | Mitoses | 0.3811 |
8 | Normal.nucleoli | 0.3423 |
4 | Marg.adhesion | 0.1675 |
5 | Epith.c.size | 0.1167 |
2 | Cell.size | 0.0107 |
SVM terbukti efektif dalam klasifikasi dataset Breast Cancer.