Support Vector Machine (SVM) adalah algoritma pembelajaran terawasi (supervised learning) yang digunakan untuk klasifikasi dan regresi. SVM bekerja dengan menemukan hyperplane atau garis pemisah optimal yang memisahkan data dari kelas berbeda dengan margin maksimal. SVM dapa digunakan untuk pengenalan wajah, deteksi spam, klasifikasi teks, diagnosis medis, dan lain-lain
SVM memiliki beberapa kelebihan, di antaranya:
Namun, SVM juga memiliki beberapa kekurangan, di antaranya:
SVM Linear merupakan jenis SVM yang menggunakan hyperplane linear untuk memisahkan data untuk tiap kelas. Bentuk SVM ini merupakan bentuk paling sederhana dari SVM dan cocok digunakan jika data dapat dipisahkan secara linear (garis lurus atau bidang datar dalam dimensi lebih tinggi). Formulasi matematisnya mengoptimalkan:
\[\min_{w, b} \frac{1}{2} ||w||^2\]
dengan batasan \(y_i(w^T x_i + b) \geq 1\) untuk semua data \(i\), di mana:
SVM Linear memiliki kelebihan cepat dan efisien untuk dataset dengan banyak fitur seperti teks, sederhana untuk diinterpretasi, dan tidak memerlukan transformasi nonlinear. Tetapi, SVM linear tidak cocok untuk data yang tidak bisa dipisahkan secara linear dan jika ada banyak overlap antarkelas, akurasi model bisa turun.
SVM Nonlinear adalah versi dari SVM yang digunakan ketika data tidak dapat dipisahkan secara linear, yang berarti tidak meungkin menggambar satu garis lurus (atau bidang datar) untuk memisahkan kelas data secara sempurna. Untuk data yang tidak dapat dipisahkan secara linear, SVM menggunakan “kernel trick” untuk memetakan data ke dimensi yang lebih tinggi di mana pemisahan linear mungkin dilakukan. Kernel yang umum digunakan adalah:
Beberapa kelebihan dari SVM Nonlinear di antaranya:
SVM Nonlinear juga memiliki kelemahan, di antaranya:
Parameter C: Parameter regularisasi yang mengontrol trade-off antara mencapai margin maksimal dan meminimalkan kesalahan klasifikasi. Nilai C yang lebih kecil menghasilkan margin yang lebih lebar tetapi memungkinkan lebih banyak kesalahan klasifikasi.
Parameter Gamma (γ): Parameter kernel yang mengontrol “pengaruh” dari setiap titik data. Gamma yang lebih tinggi berarti titik data memiliki pengaruh yang lebih lokal.
Untuk memahami penerapan algoritma SVM dalam klasifikasi, dilakukan percobaan menggunakan dataset Penguin dari library palmerpenguins. Dataset Palmer Penguin berisi data morfologi dari tiga spesies penguin yang berbeda: Adelie, Gentoo, dan Chinstrap. Dataset ini mencakup ukuran fisik seperti panjang paruh, kedalaman paruh, panjang sirip, dan berat tubuh.
# Memuat dataset Palmer Penguin
data(package = 'palmerpenguins')
data("penguins")
# Melihat struktur data
str(penguins)## tibble [344 Ă— 8] (S3: tbl_df/tbl/data.frame)
## $ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ island : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
## $ bill_length_mm : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
## $ bill_depth_mm : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
## $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
## $ body_mass_g : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
## $ sex : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
## $ year : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
## species island bill_length_mm bill_depth_mm
## Adelie :152 Biscoe :168 Min. :32.10 Min. :13.10
## Chinstrap: 68 Dream :124 1st Qu.:39.23 1st Qu.:15.60
## Gentoo :124 Torgersen: 52 Median :44.45 Median :17.30
## Mean :43.92 Mean :17.15
## 3rd Qu.:48.50 3rd Qu.:18.70
## Max. :59.60 Max. :21.50
## NA's :2 NA's :2
## flipper_length_mm body_mass_g sex year
## Min. :172.0 Min. :2700 female:165 Min. :2007
## 1st Qu.:190.0 1st Qu.:3550 male :168 1st Qu.:2007
## Median :197.0 Median :4050 NA's : 11 Median :2008
## Mean :200.9 Mean :4202 Mean :2008
## 3rd Qu.:213.0 3rd Qu.:4750 3rd Qu.:2009
## Max. :231.0 Max. :6300 Max. :2009
## NA's :2 NA's :2
## Jumlah nilai yang hilang: 19
## species island bill_length_mm bill_depth_mm
## 0 0 2 2
## flipper_length_mm body_mass_g sex year
## 2 2 11 0
Dikarenakan adanya data yang hilang, maka dilakukan cleaning data dengan menghapus baris yang memiliki komponen missing data
# Menghapus baris dengan nilai yang hilang
penguins_clean <- penguins %>% drop_na()
# Melihat ukuran dataset setelah pembersihan
cat("Ukuran dataset setelah dilakukan cleaning:", dim(penguins_clean)[1], "baris dan",
dim(penguins_clean)[2], "kolom\n")## Ukuran dataset setelah dilakukan cleaning: 333 baris dan 8 kolom
# Distribusi spesies penguin
penguin_counts <- penguins_clean %>%
count(species) %>%
mutate(percentage = n / sum(n) * 100)
kable(penguin_counts, caption = "Distribusi Data Spesies Penguin") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))| species | n | percentage |
|---|---|---|
| Adelie | 146 | 43.84384 |
| Chinstrap | 68 | 20.42042 |
| Gentoo | 119 | 35.73574 |
Data yang sudah bersih kemudian dilakukan visualisasi untuk melihat karakteristik kelompok data.
# Visualisasi distribusi spesies berdasarkan pulau
ggplot(penguins_clean, aes(x = island, fill = species)) +
geom_bar(position = "dodge") +
labs(title = "Distribusi Spesies Penguin berdasarkan Pulau",
x = "Pulau", y = "Jumlah") +
theme_minimal() +
scale_fill_brewer(palette = "Pastel1")# Visualisasi hubungan antara panjang paruh dan kedalaman paruh berdasarkan spesies
ggplot(penguins_clean, aes(x = bill_length_mm, y = bill_depth_mm, color = species, shape = species)) +
geom_point(size = 3, alpha = 0.7) +
labs(title = "Hubungan antara Panjang dan Kedalaman Paruh",
x = "Panjang Paruh (mm)", y = "Kedalaman Paruh (mm)") +
theme_minimal() +
scale_color_brewer(palette = "Pastel1")# Visualisasi hubungan antara panjang sirip dan berat tubuh berdasarkan spesies
ggplot(penguins_clean, aes(x = flipper_length_mm, y = body_mass_g, color = species, shape = species)) +
geom_point(size = 3, alpha = 0.7) +
labs(title = "Hubungan antara Panjang Sirip dan Berat Tubuh",
x = "Panjang Sirip (mm)", y = "Berat Tubuh (g)") +
theme_minimal() +
scale_color_brewer(palette = "Pastel1")# Visualisasi boxplot untuk setiap fitur numerik berdasarkan spesies
p1 <- ggplot(penguins_clean, aes(x = species, y = bill_length_mm, fill = species)) +
geom_boxplot() +
labs(title = "Panjang Paruh", x = "", y = "mm") +
theme_minimal() +
theme(legend.position = "none") +
scale_fill_brewer(palette = "Pastel1")
p2 <- ggplot(penguins_clean, aes(x = species, y = bill_depth_mm, fill = species)) +
geom_boxplot() +
labs(title = "Kedalaman Paruh", x = "", y = "mm") +
theme_minimal() +
theme(legend.position = "none") +
scale_fill_brewer(palette = "Pastel1")
p3 <- ggplot(penguins_clean, aes(x = species, y = flipper_length_mm, fill = species)) +
geom_boxplot() +
labs(title = "Panjang Sirip", x = "", y = "mm") +
theme_minimal() +
theme(legend.position = "none") +
scale_fill_brewer(palette = "Pastel1")
p4 <- ggplot(penguins_clean, aes(x = species, y = body_mass_g, fill = species)) +
geom_boxplot() +
labs(title = "Berat Tubuh", x = "", y = "g") +
theme_minimal() +
theme(legend.position = "none") +
scale_fill_brewer(palette = "Pastel1")
grid.arrange(p1, p2, p3, p4, ncol = 2,
top = "Sebaran Karakteristik Morfologi berdasarkan Spesies Penguin")# Matriks korelasi fitur numerik
penguin_numeric <- penguins_clean %>%
select(bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g)
ggpairs(penguin_numeric, title = "Matriks Korelasi Fitur Penguin")Dari visualisasi di atas, kita dapat mengamati beberapa pola sebagai berikut:
Sebelum data dimodelkan, data dipersiapkan terlebih dahulu dengan membagi data menjadi data training dan data testing dengan rasio data training:testing 70:30
# Memilih fitur yang akan digunakan untuk prediksi
penguin_features <- penguins_clean %>%
select(bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g, species)
# Membagi data menjadi set pelatihan (70%) dan pengujian (30%)
set.seed(275)
trainIndex <- createDataPartition(penguin_features$species, p = 0.7, list = FALSE)
penguin_train <- penguin_features[trainIndex, ]
penguin_test <- penguin_features[-trainIndex, ]
# Melihat pembagian data
cat("Ukuran data training:", dim(penguin_train)[1], "baris\n")## Ukuran data training: 235 baris
## Ukuran data testing: 98 baris
# Memeriksa distribusi kelas di kedua set data
train_dist <- table(penguin_train$species)
test_dist <- table(penguin_test$species)
par(mfrow = c(1, 2))
barplot(train_dist, main = "Distribusi Spesies di Data Pelatihan",
col = c("lightcoral", "lightskyblue", "lightgreen"), las = 2)
barplot(test_dist, main = "Distribusi Spesies di Data Pengujian",
col = c("lightcoral", "lightskyblue", "lightgreen"), las = 2)# Membuat objek preProcess untuk standardisasi
preproc <- preProcess(penguin_train[, 1:4], method = c("center", "scale"))
# Menerapkan standardisasi pada data traing dan testing
penguin_train_scaled <- predict(preproc, penguin_train)
penguin_test_scaled <- predict(preproc, penguin_test)
# Melihat ringkasan data yang telah distandarisasi
summary(penguin_train_scaled[, 1:4])## bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
## Min. :-2.12337 Min. :-2.0020 Min. :-1.9306 Min. :-1.8753
## 1st Qu.:-0.84450 1st Qu.:-0.8845 1st Qu.:-0.7719 1st Qu.:-0.8020
## Median : 0.02299 Median : 0.0839 Median :-0.2650 Median :-0.2653
## Mean : 0.00000 Mean : 0.0000 Mean : 0.0000 Mean : 0.0000
## 3rd Qu.: 0.80998 3rd Qu.: 0.7792 3rd Qu.: 0.8212 3rd Qu.: 0.7133
## Max. : 2.79536 Max. : 2.1698 Max. : 2.1971 Max. : 2.6705
# Melatih model SVM Linear dengan parameter default
set.seed(275)
svm_linear <- svm(species ~ ., data = penguin_train_scaled,
kernel = "linear", cost = 1)
# Ringkasan model
summary(svm_linear)##
## Call:
## svm(formula = species ~ ., data = penguin_train_scaled, kernel = "linear",
## cost = 1)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: linear
## cost: 1
##
## Number of Support Vectors: 24
##
## ( 10 4 10 )
##
##
## Number of Classes: 3
##
## Levels:
## Adelie Chinstrap Gentoo
# Prediksi pada data testing
predictions_linear <- predict(svm_linear, penguin_test_scaled)
# COnfusion Matrix
conf_matrix_linear <- confusionMatrix(predictions_linear, penguin_test_scaled$species)
conf_matrix_linear## Confusion Matrix and Statistics
##
## Reference
## Prediction Adelie Chinstrap Gentoo
## Adelie 43 3 0
## Chinstrap 0 17 0
## Gentoo 0 0 35
##
## Overall Statistics
##
## Accuracy : 0.9694
## 95% CI : (0.9131, 0.9936)
## No Information Rate : 0.4388
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9515
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Adelie Class: Chinstrap Class: Gentoo
## Sensitivity 1.0000 0.8500 1.0000
## Specificity 0.9455 1.0000 1.0000
## Pos Pred Value 0.9348 1.0000 1.0000
## Neg Pred Value 1.0000 0.9630 1.0000
## Prevalence 0.4388 0.2041 0.3571
## Detection Rate 0.4388 0.1735 0.3571
## Detection Prevalence 0.4694 0.1735 0.3571
## Balanced Accuracy 0.9727 0.9250 1.0000
# Grid parameter untuk SVM linear
linear_grid <- expand.grid(C = c(0.001, 0.01, 0.1, 1, 10, 100))
# Kontrol untuk cross-validation
ctrl <- trainControl(method = "cv", number = 5)
# Tuning model SVM linear
set.seed(275)
svm_linear_tuned <- train(species ~ .,
data = penguin_train_scaled,
method = "svmLinear",
trControl = ctrl,
tuneGrid = linear_grid)
# Hasil tuning
print(svm_linear_tuned)## Support Vector Machines with Linear Kernel
##
## 235 samples
## 4 predictor
## 3 classes: 'Adelie', 'Chinstrap', 'Gentoo'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 188, 189, 188, 188, 187
## Resampling results across tuning parameters:
##
## C Accuracy Kappa
## 1e-03 0.4933472 0.1044625
## 1e-02 0.9277367 0.8836483
## 1e-01 0.9829787 0.9730462
## 1e+00 0.9914894 0.9866238
## 1e+01 0.9829749 0.9732823
## 1e+02 0.9829749 0.9732823
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was C = 1.
ggplot(svm_linear_tuned) +
labs(title = "Pengaruh Parameter C terhadap Akurasi (SVM Linear)") +
theme_minimal()# Model SVM linear dengan parameter terbaik
best_C_linear <- svm_linear_tuned$bestTune$C
cat("Parameter C terbaik untuk SVM linear:", best_C_linear, "\n")## Parameter C terbaik untuk SVM linear: 1
# Training model dengan parameter terbaik
svm_linear_best <- svm(species ~ ., data = penguin_train_scaled,
kernel = "linear", cost = best_C_linear)
# Prediksi dengan model terbaik
predictions_linear_best <- predict(svm_linear_best, penguin_test_scaled)
# COnfusion Matrix
conf_matrix_linear_best <- confusionMatrix(predictions_linear_best, penguin_test_scaled$species)
conf_matrix_linear_best## Confusion Matrix and Statistics
##
## Reference
## Prediction Adelie Chinstrap Gentoo
## Adelie 43 3 0
## Chinstrap 0 17 0
## Gentoo 0 0 35
##
## Overall Statistics
##
## Accuracy : 0.9694
## 95% CI : (0.9131, 0.9936)
## No Information Rate : 0.4388
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9515
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Adelie Class: Chinstrap Class: Gentoo
## Sensitivity 1.0000 0.8500 1.0000
## Specificity 0.9455 1.0000 1.0000
## Pos Pred Value 0.9348 1.0000 1.0000
## Neg Pred Value 1.0000 0.9630 1.0000
## Prevalence 0.4388 0.2041 0.3571
## Detection Rate 0.4388 0.1735 0.3571
## Detection Prevalence 0.4694 0.1735 0.3571
## Balanced Accuracy 0.9727 0.9250 1.0000
# Melatih model SVM dengan kernel RBF menggunakan parameter default
set.seed(275)
svm_rbf <- svm(species ~ ., data = penguin_train_scaled,
kernel = "radial", gamma = 0.25, cost = 1)
# Ringkasan model
summary(svm_rbf)##
## Call:
## svm(formula = species ~ ., data = penguin_train_scaled, kernel = "radial",
## gamma = 0.25, cost = 1)
##
##
## Parameters:
## SVM-Type: C-classification
## SVM-Kernel: radial
## cost: 1
##
## Number of Support Vectors: 47
##
## ( 20 9 18 )
##
##
## Number of Classes: 3
##
## Levels:
## Adelie Chinstrap Gentoo
# Prediksi pada data Testing
predictions_rbf <- predict(svm_rbf, penguin_test_scaled)
# Matriks konfusi
conf_matrix_rbf <- confusionMatrix(predictions_rbf, penguin_test_scaled$species)
conf_matrix_rbf## Confusion Matrix and Statistics
##
## Reference
## Prediction Adelie Chinstrap Gentoo
## Adelie 43 2 0
## Chinstrap 0 18 0
## Gentoo 0 0 35
##
## Overall Statistics
##
## Accuracy : 0.9796
## 95% CI : (0.9282, 0.9975)
## No Information Rate : 0.4388
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9678
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Adelie Class: Chinstrap Class: Gentoo
## Sensitivity 1.0000 0.9000 1.0000
## Specificity 0.9636 1.0000 1.0000
## Pos Pred Value 0.9556 1.0000 1.0000
## Neg Pred Value 1.0000 0.9750 1.0000
## Prevalence 0.4388 0.2041 0.3571
## Detection Rate 0.4388 0.1837 0.3571
## Detection Prevalence 0.4592 0.1837 0.3571
## Balanced Accuracy 0.9818 0.9500 1.0000
# Grid parameter untuk SVM kernel RBF
rbf_grid <- expand.grid(sigma = c(0.01, 0.1, 0.5, 1),
C = c(0.1, 1, 10, 100))
# Tuning model SVM dengan kernel RBF
set.seed(275)
svm_rbf_tuned <- train(species ~ .,
data = penguin_train_scaled,
method = "svmRadial",
trControl = ctrl,
tuneGrid = rbf_grid)
# Hasil tuning
print(svm_rbf_tuned)## Support Vector Machines with Radial Basis Function Kernel
##
## 235 samples
## 4 predictor
## 3 classes: 'Adelie', 'Chinstrap', 'Gentoo'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 188, 189, 188, 188, 187
## Resampling results across tuning parameters:
##
## sigma C Accuracy Kappa
## 0.01 0.1 0.7957986 0.6542293
## 0.01 1.0 0.9659536 0.9460221
## 0.01 10.0 0.9872340 0.9798619
## 0.01 100.0 0.9828862 0.9730285
## 0.10 0.1 0.9533688 0.9251581
## 0.10 1.0 0.9828862 0.9730823
## 0.10 10.0 0.9913969 0.9865108
## 0.10 100.0 0.9787195 0.9666157
## 0.50 0.1 0.9788121 0.9665180
## 0.50 1.0 0.9828862 0.9730823
## 0.50 10.0 0.9700278 0.9529613
## 0.50 100.0 0.9785384 0.9663803
## 1.00 0.1 0.9491096 0.9186830
## 1.00 1.0 0.9828862 0.9729168
## 1.00 10.0 0.9742831 0.9595646
## 1.00 100.0 0.9742831 0.9595646
##
## Accuracy was used to select the optimal model using the largest value.
## The final values used for the model were sigma = 0.1 and C = 10.
ggplot(svm_rbf_tuned) +
labs(title = "Pengaruh Parameter C dan Sigma terhadap Akurasi (SVM RBF)") +
theme_minimal()# Parameter terbaik
best_C_rbf <- svm_rbf_tuned$bestTune$C
best_sigma <- svm_rbf_tuned$bestTune$sigma
cat("Parameter terbaik untuk SVM dengan kernel RBF:\n")## Parameter terbaik untuk SVM dengan kernel RBF:
## C = 10
## Sigma = 0.1
# Training model dengan parameter terbaik
svm_rbf_best <- svm(species ~ ., data = penguin_train_scaled,
kernel = "radial", gamma = best_sigma, cost = best_C_rbf)
# Prediksi dengan model terbaik
predictions_rbf_best <- predict(svm_rbf_best, penguin_test_scaled)
# Confusion Matrix
conf_matrix_rbf_best <- confusionMatrix(predictions_rbf_best, penguin_test_scaled$species)
conf_matrix_rbf_best## Confusion Matrix and Statistics
##
## Reference
## Prediction Adelie Chinstrap Gentoo
## Adelie 43 2 0
## Chinstrap 0 18 0
## Gentoo 0 0 35
##
## Overall Statistics
##
## Accuracy : 0.9796
## 95% CI : (0.9282, 0.9975)
## No Information Rate : 0.4388
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9678
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: Adelie Class: Chinstrap Class: Gentoo
## Sensitivity 1.0000 0.9000 1.0000
## Specificity 0.9636 1.0000 1.0000
## Pos Pred Value 0.9556 1.0000 1.0000
## Neg Pred Value 1.0000 0.9750 1.0000
## Prevalence 0.4388 0.2041 0.3571
## Detection Rate 0.4388 0.1837 0.3571
## Detection Prevalence 0.4592 0.1837 0.3571
## Balanced Accuracy 0.9818 0.9500 1.0000
Untuk memvisualisasikan decision boundary, permasalahan
disederhanakan dengan hanya menggunakan dua fitur. Berdasarkan hasil
eksplorasi data sebelumnya, fitur yang dipilih adalah
bill_length_mm dan bill_depth_mm, karena
keduanya menunjukkan pemisahan antar spesies yang cukup jelas.
# Memilih 2 fitur untuk visualisasi decision boundary
penguin_2d <- penguin_train_scaled %>%
select(bill_length_mm, bill_depth_mm, species)
# Membuat grid untuk visualisasi
set.seed(275)
x_min <- min(penguin_2d$bill_length_mm) - 0.5
x_max <- max(penguin_2d$bill_length_mm) + 0.5
y_min <- min(penguin_2d$bill_depth_mm) - 0.5
y_max <- max(penguin_2d$bill_depth_mm) + 0.5
grid_size <- 100
x_grid <- seq(x_min, x_max, length.out = grid_size)
y_grid <- seq(y_min, y_max, length.out = grid_size)
grid_data <- expand.grid(bill_length_mm = x_grid, bill_depth_mm = y_grid)
# Melatih model SVM Linear pada data 2D
svm_2d_linear <- svm(species ~ ., data = penguin_2d,
kernel = "linear", cost = best_C_linear)
# Prediksi pada grid untuk SVM Linear
grid_predictions_linear <- predict(svm_2d_linear, grid_data)
grid_data$prediction_linear <- grid_predictions_linear
# Melatih model SVM RBF pada data 2D
svm_2d_rbf <- svm(species ~ ., data = penguin_2d,
kernel = "radial", gamma = best_sigma, cost = best_C_rbf)
# Prediksi pada grid untuk SVM RBF
grid_predictions_rbf <- predict(svm_2d_rbf, grid_data)
grid_data$prediction_rbf <- grid_predictions_rbf
# Visualisasi decision boundary untuk SVM Linear
p_linear <- ggplot() +
geom_tile(data = grid_data, aes(x = bill_length_mm, y = bill_depth_mm, fill = prediction_linear), alpha = 0.3) +
geom_point(data = penguin_2d, aes(x = bill_length_mm, y = bill_depth_mm, color = species, shape = species), size = 3) +
labs(title = "Decision Boundary SVM Linear",
x = "Panjang Paruh (mm) [Standardized]",
y = "Kedalaman Paruh (mm) [Standardized]") +
theme_minimal() +
scale_fill_brewer(palette = "Pastel1", name = "Prediksi") +
scale_color_brewer(palette = "Pastel1", name = "Aktual") +
theme(legend.position = "bottom")
# Visualisasi decision boundary untuk SVM RBF
p_rbf <- ggplot() +
geom_tile(data = grid_data, aes(x = bill_length_mm, y = bill_depth_mm, fill = prediction_rbf), alpha = 0.3) +
geom_point(data = penguin_2d, aes(x = bill_length_mm, y = bill_depth_mm, color = species, shape = species), size = 3) +
labs(title = "Decision Boundary SVM dengan Kernel RBF",
x = "Panjang Paruh (mm) [Standardized]",
y = "Kedalaman Paruh (mm) [Standardized]") +
theme_minimal() +
scale_fill_brewer(palette = "Pastel1", name = "Prediksi") +
scale_color_brewer(palette = "Pastel1", name = "Aktual") +
theme(legend.position = "bottom")
# Menampilkan kedua plot
grid.arrange(p_linear, p_rbf, ncol = 2)Selanjutnya, kita akan membandingkan kinerja semua model yang telah dibangun sebelumnya.
# Mengumpulkan hasil evaluasi semua model
models <- c("SVM Linear (Default)", "SVM Linear (Tuned)",
"SVM RBF (Default)", "SVM RBF (Tuned)")
accuracy <- c(conf_matrix_linear$overall["Accuracy"],
conf_matrix_linear_best$overall["Accuracy"],
conf_matrix_rbf$overall["Accuracy"],
conf_matrix_rbf_best$overall["Accuracy"])
kappa <- c(conf_matrix_linear$overall["Kappa"],
conf_matrix_linear_best$overall["Kappa"],
conf_matrix_rbf$overall["Kappa"],
conf_matrix_rbf_best$overall["Kappa"])
# Menghitung Precision, Recall, dan F1-Score untuk setiap model
# Untuk SVM Linear (Default)
precision_linear <- mean(conf_matrix_linear$byClass[, "Precision"])
recall_linear <- mean(conf_matrix_linear$byClass[, "Recall"])
f1_linear <- mean(conf_matrix_linear$byClass[, "F1"])
# Untuk SVM Linear (Tuned)
precision_linear_best <- mean(conf_matrix_linear_best$byClass[, "Precision"])
recall_linear_best <- mean(conf_matrix_linear_best$byClass[, "Recall"])
f1_linear_best <- mean(conf_matrix_linear_best$byClass[, "F1"])
# Untuk SVM RBF (Default)
precision_rbf <- mean(conf_matrix_rbf$byClass[, "Precision"])
recall_rbf <- mean(conf_matrix_rbf$byClass[, "Recall"])
f1_rbf <- mean(conf_matrix_rbf$byClass[, "F1"])
# Untuk SVM RBF (Tuned)
precision_rbf_best <- mean(conf_matrix_rbf_best$byClass[, "Precision"])
recall_rbf_best <- mean(conf_matrix_rbf_best$byClass[, "Recall"])
f1_rbf_best <- mean(conf_matrix_rbf_best$byClass[, "F1"])
precision <- c(precision_linear, precision_linear_best, precision_rbf, precision_rbf_best)
recall <- c(recall_linear, recall_linear_best, recall_rbf, recall_rbf_best)
f1 <- c(f1_linear, f1_linear_best, f1_rbf, f1_rbf_best)
model_comparison <- data.frame(
Model = models,
Accuracy = accuracy,
Kappa = kappa,
Precision = precision,
Recall = recall,
F1_Score = f1
)
# Menampilkan tabel perbandingan
kable(model_comparison, caption = "Perbandingan Kinerja Model SVM") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F) %>%
column_spec(1, bold = TRUE)| Model | Accuracy | Kappa | Precision | Recall | F1_Score |
|---|---|---|---|---|---|
| SVM Linear (Default) | 0.9693878 | 0.9514932 | 0.9782609 | 0.9500000 | 0.9617370 |
| SVM Linear (Tuned) | 0.9693878 | 0.9514932 | 0.9782609 | 0.9500000 | 0.9617370 |
| SVM RBF (Default) | 0.9795918 | 0.9677844 | 0.9851852 | 0.9666667 | 0.9748804 |
| SVM RBF (Tuned) | 0.9795918 | 0.9677844 | 0.9851852 | 0.9666667 | 0.9748804 |
# Visualisasi perbandingan akurasi
ggplot(model_comparison, aes(x = reorder(Model, Accuracy), y = Accuracy, fill = Model)) +
geom_bar(stat = "identity") +
coord_flip() +
labs(title = "Perbandingan Akurasi Model",
x = "Model", y = "Akurasi") +
theme_minimal() +
theme(legend.position = "none") +
scale_fill_brewer(palette = "Accent")Dalam algoritma SVM, parameter C memiliki peran krusial dalam menyeimbangkan antara memperlebar margin pemisah dan mengurangi jumlah kesalahan klasifikasi. Pemilihan nilai C akan sangat berpengaruh terhadap kinerja model secara keseluruhan.
Nilai C yang rendah: Cenderung menghasilkan margin pemisah yang lebih lebar, meskipun mengizinkan lebih banyak kesalahan klasifikasi. Hal ini bisa menyebabkan model mengalami underfitting, tetapi model menjadi lebih sederhana dan umumnya memiliki kemampuan generalisasi yang lebih baik terhadap data yang belum pernah dilihat.
Nilai C yang tinggi: Fokus utama adalah mengurangi kesalahan klasifikasi sebanyak mungkin, sehingga margin menjadi lebih sempit. Model menjadi lebih kompleks dan mampu menangkap pola detail dalam data pelatihan, namun berisiko overfitting sehingga performanya bisa menurun saat diterapkan pada data baru.
Melalui proses tuning, diperoleh nilai C optimal yaitu 1 untuk model SVM linear, dan 10 untuk model SVM dengan kernel RBF. Temuan ini menunjukkan bahwa:
# Visualisasi pengaruh parameter C
c_values <- c(0.001, 0.01, 0.1, 1, 10, 100)
linear_results <- svm_linear_tuned$results
ggplot(linear_results, aes(x = C, y = Accuracy)) +
geom_line() +
geom_point(size = 3) +
scale_x_log10() +
labs(title = "Pengaruh Parameter C terhadap Akurasi (SVM Linear)",
x = "Nilai C (skala logaritmik)", y = "Akurasi") +
theme_minimal()Gamma (Îł) berfungsi untuk mengatur seberapa jauh sebuah titik data memengaruhi pembentukan decision boundary (batas keputusan). Nilai gamma ini sangat memengaruhi tingkat kompleksitas model, yaitu sejauh mana model mampu menyesuaikan diri terhadap pola dalam data.
Gamma bernilai kecil: Setiap titik data memiliki pengaruh yang meluas:
Model cenderung membentuk batas keputusan yang halus dan sederhana.
Cocok untuk menangkap pola umum atau global dalam data.
Namun, berisiko kehilangan detail penting dan dapat menyebabkan underfitting.
Gamma bernilai besar: Pengaruh titik data sangat terbatas pada area sekitarnya:
Model membentuk batas keputusan yang tajam dan kompleks.
Mampu mengenali pola lokal secara rinci.
Tetapi rentan terhadap overfitting, terutama jika data mengandung noise.
Berdasarkan hasil tuning, diperoleh nilai gamma optimal sebesar 0.1 untuk model SVM dengan kernel RBF. Nilai ini menunjukkan bahwa:
# Visualisasi pengaruh parameter gamma dan C
rbf_results <- svm_rbf_tuned$results
ggplot(rbf_results, aes(x = C, y = Accuracy, color = as.factor(sigma))) +
geom_line() +
geom_point(size = 3) +
scale_x_log10() +
labs(title = "Pengaruh Parameter C dan Sigma terhadap Akurasi (SVM RBF)",
x = "Nilai C (skala logaritmik)", y = "Akurasi",
color = "Nilai Sigma") +
theme_minimal()Berdasarkan visualisasi di atas, terlihat bahwa terdapat interaksi antara parameter C dan gamma. Setiap nilai gamma memiliki nilai C optimal masing-masing. Namun, kombinasi parameter yang memberikan akurasi tertinggi adalah saat C = 10 dan gamma = 0.1.
Untuk menilai seberapa andal model yang dihasilkan, dilakukan k-fold cross-validation. Metode ini berguna untuk memastikan bahwa performa model tidak bergantung pada pembagian data tertentu, sehingga hasil evaluasi menjadi lebih umum dan dapat dipercaya.
# Melakukan 5-fold cross-validation untuk model SVM linear terbaik
set.seed(275)
cv_control <- trainControl(method = "cv", number = 5,
savePredictions = "all",
classProbs = TRUE)
cv_linear <- train(species ~ .,
data = penguin_features,
method = "svmLinear",
trControl = cv_control,
tuneGrid = data.frame(C = best_C_linear),
preProcess = c("center", "scale"))
# Melakukan 5-fold cross-validation untuk model SVM RBF terbaik
cv_rbf <- train(species ~ .,
data = penguin_features,
method = "svmRadial",
trControl = cv_control,
tuneGrid = data.frame(sigma = best_sigma, C = best_C_rbf),
preProcess = c("center", "scale"))
# Menampilkan hasil validasi silang
cv_results <- data.frame(
Model = c("SVM Linear", "SVM RBF"),
Mean_Accuracy = c(mean(cv_linear$results$Accuracy), mean(cv_rbf$results$Accuracy)),
Std_Accuracy = c(NA, NA) # Kita perlu ekstrak standar deviasi dari resamples
)
# Mendapatkan standar deviasi dari resamples
linear_resamples <- cv_linear$resample$Accuracy
rbf_resamples <- cv_rbf$resample$Accuracy
cv_results$Std_Accuracy <- c(sd(linear_resamples), sd(rbf_resamples))
# Menampilkan hasil
kable(cv_results, caption = "Hasil Validasi Silang 5-Fold") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F)| Model | Mean_Accuracy | Std_Accuracy |
|---|---|---|
| SVM Linear | 0.9820443 | 0.0124744 |
| SVM RBF | 0.9880597 | 0.0124875 |
# Visualisasi akurasi per fold
fold_results <- data.frame(
Fold = rep(1:5, 2),
Model = c(rep("SVM Linear", 5), rep("SVM RBF", 5)),
Accuracy = c(cv_linear$resample$Accuracy, cv_rbf$resample$Accuracy)
)
ggplot(fold_results, aes(x = as.factor(Fold), y = Accuracy, fill = Model)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Akurasi per Fold dalam Validasi Silang 5-Fold",
x = "Fold", y = "Akurasi") +
theme_minimal() +
scale_fill_brewer(palette = "Accent")Untuk evaluasi lebih menyeluruh, kita dapat menganalisis kurva ROC ( Receiver Operating Characteristic ) dan nilai AUC ( Area Under Curve ) untuk setiap kelas.
# Membuat model probability SVM untuk analisis ROC
svm_linear_prob <- svm(species ~ ., data = penguin_train_scaled,
kernel = "linear", cost = best_C_linear, probability = TRUE)
svm_rbf_prob <- svm(species ~ ., data = penguin_train_scaled,
kernel = "radial", gamma = best_sigma, cost = best_C_rbf, probability = TRUE)
# Prediksi probabilitas
pred_prob_linear <- predict(svm_linear_prob, penguin_test_scaled, probability = TRUE)
prob_linear <- attr(pred_prob_linear, "probabilities")
pred_prob_rbf <- predict(svm_rbf_prob, penguin_test_scaled, probability = TRUE)
prob_rbf <- attr(pred_prob_rbf, "probabilities")
# Mengubah ke format one-vs-all untuk ROC
species_levels <- levels(as.factor(penguin_test_scaled$species))
# Menghitung ROC dan AUC untuk SVM Linear
roc_linear <- list()
auc_linear <- numeric(length(species_levels))
names(auc_linear) <- species_levels
for(i in 1:length(species_levels)) {
species <- species_levels[i]
actual <- ifelse(penguin_test_scaled$species == species, 1, 0)
roc_linear[[i]] <- roc(actual, prob_linear[, species])
auc_linear[i] <- auc(roc_linear[[i]])
}
# Menghitung ROC dan AUC untuk SVM RBF
roc_rbf <- list()
auc_rbf <- numeric(length(species_levels))
names(auc_rbf) <- species_levels
for(i in 1:length(species_levels)) {
species <- species_levels[i]
actual <- ifelse(penguin_test_scaled$species == species, 1, 0)
roc_rbf[[i]] <- roc(actual, prob_rbf[, species])
auc_rbf[i] <- auc(roc_rbf[[i]])
}
# Menampilkan nilai AUC
auc_results <- data.frame(
Species = species_levels,
AUC_Linear = auc_linear,
AUC_RBF = auc_rbf
)
kable(auc_results, caption = "Nilai AUC untuk Setiap Spesies") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F)| Species | AUC_Linear | AUC_RBF | |
|---|---|---|---|
| Adelie | Adelie | 1 | 1 |
| Chinstrap | Chinstrap | 1 | 1 |
| Gentoo | Gentoo | 1 | 1 |
# Plot ROC Curves untuk SVM Linear
par(mfrow = c(1, 2))
plot(roc_linear[[1]], main = "ROC Curves - SVM Linear", col = "red")
for(i in 2:length(species_levels)) {
plot(roc_linear[[i]], add = TRUE, col = i + 1)
}
legend("bottomright", legend = paste0(species_levels, " (AUC = ", round(auc_linear, 3), ")"),
col = 2:(length(species_levels) + 1), lwd = 2)
# Plot ROC Curves untuk SVM RBF
plot(roc_rbf[[1]], main = "ROC Curves - SVM RBF", col = "red")
for(i in 2:length(species_levels)) {
plot(roc_rbf[[i]], add = TRUE, col = i + 1)
}
legend("bottomright", legend = paste0(species_levels, " (AUC = ", round(auc_rbf, 3), ")"),
col = 2:(length(species_levels) + 1), lwd = 2)Berdasarkan analisis klasifikasi spesies penguin menggunakan SVM, kita dapat menyimpulkan beberapa hal:
Dalam studi ini, kita berhasil menerapkan algoritma Support Vector Machine (SVM) untuk mengklasifikasikan tiga spesies penguin—Adelie, Chinstrap, dan Gentoo—berdasarkan ciri morfologi mereka. Kedua model SVM yang digunakan, yakni linear dan non-linear dengan kernel RBF, menunjukkan hasil klasifikasi yang sangat baik dengan akurasi melebihi 95%.
Penggunaan SVM sangat tepat untuk dataset ini karena kemampuannya dalam menentukan hyperplane optimal yang memisahkan kelas dengan margin terbesar. Selain itu, proses tuning parameter turut meningkatkan kinerja model, menegaskan pentingnya optimasi hyperparameter dalam pengembangan model machine learning.
Analisis ini tidak hanya menghasilkan klasifikasi yang akurat, tetapi juga memberikan pemahaman yang lebih dalam mengenai fitur morfologi yang membedakan ketiga spesies penguin, yang dapat berguna untuk penelitian taksonomi maupun upaya pelestarian keanekaragaman hayati.