Support Vector Machine

Konsep Dasar SVM

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:

  • Bekerja baik di ruang dimensi tinggi
  • Efektif ketika jumlah fitur lebih banyak daripada jumlah sampel
  • Menggunakan subset data (support vectors), jadi efisien dalam penggunaan memori

Namun, SVM juga memiliki beberapa kekurangan, di antaranya:

  • Tidak cocok untuk dataset yang sangat besar
  • Pemilihan kernel dan parameter tuning yang cukup kompleks
  • Kurang cocok untuk data dengan banyak noise atau overlapping

SVM Linear

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:

  • \(w\) adalah vektor normal terhadap hyperplane
  • \(b\) adalah bias
  • \(x_i\) adalah vektor fitur dari data ke-i
  • \(y_i\) adalah label kelas (-1 atau 1)

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 Non-linear dengan Kernel

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:

  • Kernel RBF (Radial Basis Function): \(K(x_i, x_j) = \exp(-\gamma ||x_i - x_j||^2)\)
  • Kernel Polinomial: \(K(x_i, x_j) = (\gamma x_i^T x_j + r)^d\)
  • Kernel Sigmoid: \(K(x_i, x_j) = \tanh(\gamma x_i^T x_j + r)\)

Beberapa kelebihan dari SVM Nonlinear di antaranya:

  • Dapat menangani data dengan pola pemisahan kompleks
  • Fleksibel karena tersedia berbagai jenis kernel
  • Tetap efisien walaupun bekerja di ruang fitur berdimensi tinggi karena adanya kernel trick.

SVM Nonlinear juga memiliki kelemahan, di antaranya:

  • Lebih lambat daripada SVM linear, terutama untuk dataset besar
  • Pemilihan kernel dan parameter tuning (seperti C, gamma) sangat mempengaruhi hasil
  • Kurang transparan (sulit untuk diinterpretasikan dibanding model linear)

Parameter Penting dalam SVM

  1. 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.

  2. Parameter Gamma (γ): Parameter kernel yang mengontrol “pengaruh” dari setiap titik data. Gamma yang lebih tinggi berarti titik data memiliki pengaruh yang lebih lokal.

Eksplorasi Dataset Penguin

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 ...
# Ringkasan statistik
summary(penguins)
##       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
# Memeriksa nilai yang hilang
cat("Jumlah nilai yang hilang:", sum(is.na(penguins)), "\n")
## Jumlah nilai yang hilang: 19
colSums(is.na(penguins))
##           species            island    bill_length_mm     bill_depth_mm 
##                 0                 0                 2                 2 
## flipper_length_mm       body_mass_g               sex              year 
##                 2                 2                11                 0

Cleaning Data

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"))
Distribusi Data Spesies Penguin
species n percentage
Adelie 146 43.84384
Chinstrap 68 20.42042
Gentoo 119 35.73574
# Mengubah variable kategoris menjadi faktor
penguins_clean$species <- as.factor(penguins_clean$species)
penguins_clean$island <- as.factor(penguins_clean$island)
penguins_clean$sex <- as.factor(penguins_clean$sex)

Visualisasi Data

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")

Analisis dari Visualisasi Data

Dari visualisasi di atas, kita dapat mengamati beberapa pola sebagai berikut:

  1. Persebaran Spesies pada Setiap Pulau:
    • Spesies Adelie ditemukan di semua pulau, yaitu Biscoe, Dream, dan Torgersen
    • Spesies Chinstrap hanya ditemukan di pulau Dream
    • Spesies Gentoo hanya ditemukan di pulau Biscoe
  2. Ciri Morfologi Spesies Penguin:
    • Panjang Paruh: Penguin Chinstrap dan Gentoo umumnya memiliki paruh yang lebih panjang dibandingkan Adelie.
    • Kedalaman Paruh: Spesies Adelie dan Chinstrap cenderung memiliki paruh yang lebih dalam dibandingkan Gentoo.
    • Panjang Sirip: Spesies Gentoo memiliki sirip yang paling panjang di antara ketiga spesies penguin.
    • Berat Tubuh: Spesies Gentoo memiliki bobot tubuh yang paling besar dibandingkan spesies lainnya.
  3. Pola Pemisahan Antarspesies: Terdapat pemisahan yang cukup jelas antar spesies, terutama pada visualisasi panjang paruh terhadap kedalaman paruh, serta panjang sirip terhadap berat tubuh. Hal ini mengindikasikan bahwa fitur-fitur tersebut sangat berguna untuk mengklasifikasikan jenis penguin secara akurat.

Persiapan Data untuk Pemodelan

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
cat("Ukuran data testing:", dim(penguin_test)[1], "baris\n")
## 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)

Standardisasi Data

# 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

Membangun Model SVM Linear

# 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

Parameter Tuning untuk Model SVM Linear

# 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

Membangun Model SVM Nonlinear (Kernel RBF)

# 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

Tuning Parameter untuk Model SVM dengan Kernel RBF

# 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:
cat("C =", best_C_rbf, "\n")
## C = 10
cat("Sigma =", best_sigma, "\n")
## 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

Visualisasi Decision Boundary

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)

Perbandingan Model

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)
Perbandingan Kinerja Model SVM
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")

Interpretasi Parameter C dan Gamma

Parameter C (Regularisasi)

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:

  • Pada SVM dengan kernel linear, nilai C = 1 memberikan keseimbangan optimal antara margin yang cukup lebar dan tingkat kesalahan klasifikasi yang minimal.
  • Sedangkan pada SVM dengan kernel RBF, nilai C = 10 mengindikasikan bahwa model memerlukan tingkat kompleksitas yang lebih tinggi untuk secara efektif mengenali pola non-linear dalam data..
# 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()

Parameter Gamma (Îł)

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:

  • Gamma = 0.1 berhasil menemukan keseimbangan yang tepat antara model yang terlalu sederhana (tidak menangkap pola lokal) dan model yang terlalu kompleks (menangkap noise).
  • Nilai gamma ini memungkinkan terbentuknya decision boundary yang cukup fleksibel untuk memisahkan ketiga spesies penguin secara efektif, tanpa menyebabkan overfitting.
# 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.

Analisis Validasi Silang (Cross-Validation)

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)
Hasil Validasi Silang 5-Fold
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")

Analisis ROC dan AUC

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)
Nilai AUC untuk Setiap Spesies
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)

Kesimpulan dan Refleksi

Berdasarkan analisis klasifikasi spesies penguin menggunakan SVM, kita dapat menyimpulkan beberapa hal:

Temuan Utama

  1. Performa Model: Model SVM dengan kernel RBF yang telah di-tuning berhasil mencapai akurasi tertinggi, yakni sekitar 97.96%, yang sedikit lebih unggul dibandingkan dengan model SVM linear dengan akurasi sebesar 96.94%. Selain itu, model SVM RBF juga memiliki nilai F1-Score yang lebih tinggi, menandakan keseimbangan yang baik antara precision dan recall.
  2. Fitur yang Informatif: Dari visualisasi batas keputusan (decision boundary), terlihat bahwa hanya dengan menggunakan dua fitur saja, yaitu panjang dan kedalaman paruh, kita sudah dapat membedakan ketiga spesies penguin dengan cukup jelas. Selain itu, fitur panjang sirip dan berat tubuh juga sangat membantu dalam membedakan spesies Gentoo dari dua spesies lainnya.
  3. Pengaruh Parameter: Nilai parameter C yang optimal untuk SVM linear adalah 1, sedangkan untuk SVM dengan kernel RBF adalah 10, yang menunjukkan bahwa kedua model memerlukan tingkat regularisasi yang berbeda. Sementara itu, parameter gamma yang terbaik untuk kernel RBF adalah 0.1, yang menggambarkan preferensi model terhadap pengaruh yang cukup moderat dari setiap titik data.

Refleksi

  1. Efektivitas SVM untuk Klasifikasi Biologi:
    • SVM menunjukkan kemampuan yang sangat baik dalam mengklasifikasikan spesies penguin berdasarkan ciri morfologisnya. Ini menandakan bahwa SVM memiliki potensi besar untuk digunakan dalam bidang taksonomi dan klasifikasi biologi secara umum.
  2. Linear vs Non-linear SVM:
    • Walaupun SVM dengan kernel RBF memberikan akurasi yang sedikit lebih tinggi, SVM linear juga mampu memberikan hasil yang memuaskan. Hal ini mengindikasikan bahwa data penguin relatif dapat dipisahkan secara linear.
    • Di sisi lain, decision boundary pada SVM RBF lebih fleksibel sehingga dapat menangani data yang tidak sepenuhnya dapat dipisahkan dengan garis lurus.
  3. Implikasi Parameter Tuning:
    • Peningkatan performa yang diperoleh setelah melakukan tuning parameter menegaskan pentingnya proses optimasi hyperparameter dalam membangun model SVM.
    • Nilai parameter C yang optimal mencerminkan keseimbangan yang baik antara kompleksitas model dan kemampuan untuk melakukan generalisasi..
  4. Keuntungan Standardisasi Fitur:
    • Proses standardisasi fitur sangat penting dalam pemodelan SVM karena memastikan bahwa setiap fitur memiliki kontribusi yang setara terhadap model, tanpa dipengaruhi oleh perbedaan skala asli data.

Rekomendasi untuk Analisis Lanjutan

  1. Fitur Engineering:
    • Meski model sudah cukup baik, penelitian lebih lanjut dapat dilakukan dengan menciptakan fitur baru, misalnya rasio antara panjang dan kedalaman paruh, yang mungkin bisa menambah informasi penting untuk klasifikasi.
  2. Eksplorasi Kernel Lain:
    • Selain kernel linear dan RBF, sebaiknya dicoba juga kernel polinomial atau sigmoid untuk melihat apakah dapat meningkatkan performa model..
  3. Analisis Sensitivitas:
    • Melakukan analisis sensitivitas terhadap ukuran data pelatihan untuk mengetahui berapa banyak data yang diperlukan agar model dapat bekerja optimal.
  4. Perbandingan dengan Algoritma Lain:
    • Membandingkan hasil SVM dengan algoritma klasifikasi lain seperti Random Forest, Gradient Boosting, atau Neural Networks bisa memberikan insight tambahan mengenai karakteristik data penguin.

Kesimpulan Akhir

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.