Support Vector Regression

Support Vector Regression (SVR) adalah metode regresi yang merupakan pengembangan dari algoritma Support Vector Machine (SVM), yang awalnya dirancang untuk klasifikasi. SVR digunakan untuk memodelkan hubungan antara variabel input (fitur) dan variabel output (target) dalam bentuk regresi. Tujuannya adalah mencari fungsi regresi yang tidak hanya akurat tetapi juga memiliki kemampuan generalisasi yang baik dan tahan terhadap noise.

1. Konsep Dasar SVR

Berbeda dengan regresi linear biasa yang berusaha meminimalkan jumlah kesalahan kuadrat (mean squared error), SVR menggunakan pendekatan yang memperbolehkan toleransi kesalahan tertentu (ε). Artinya, prediksi yang berada dalam selang toleransi (±ε dari nilai aktual) dianggap cukup baik dan tidak dikenai penalti.

Pendekatan ini dikenal dengan epsilon-insensitive tube (ε-tube), yaitu sebuah pita selebar 2ε yang mengelilingi fungsi regresi. Prediksi yang jatuh di dalam pita ini tidak dianggap sebagai kesalahan.

2. Fungsi Regresi SVR

Fungsi regresi dalam SVR dituliskan sebagai:

\[ f(x) = w \cdot x + b \]

dengan :

  • \(w\): vektor bobot
  • \(x\): vektor fitur input
  • \(b\): bias (intersep)

Tujuan dari SVR adalah meminimalkan kompleksitas model, yang diwujudkan dengan meminimalkan norma \(||w||^2\), agar model tidak terlalu rumit dan bisa digeneralisasi ke data baru.

3. Fungsi Loss Epsilon-Insensitive

SVR menggunakan fungsi loss epsilon-insensitive, yaitu fungsi yang hanya memberikan penalti terhadap prediksi yang melampaui batas toleransi. Fungsi loss ini dapat dituliskan sebagai:

\[ L_{\varepsilon}(y, f(x)) = \begin{cases} 0, & \text{jika } |y - f(x)| \leq \varepsilon \\ |y - f(x)| - \varepsilon, & \text{jika } |y - f(x)| > \varepsilon \end{cases} \]

4. Optimisasi SVR

Masalah optimasi SVR dapat diformulasikan sebagai:

Minimalkan:

\[ \frac{1}{2} \|w\|^2 + C \sum_{i=1}^{n} (\xi_i + \xi_i^*) \]

Dengan batasan:

\[ \begin{cases} y_i - w \cdot x_i - b \leq \varepsilon + \xi_i \\\\ w \cdot x_i + b - y_i \leq \varepsilon + \xi_i^* \\\\ \xi_i, \xi_i^* \geq 0 \end{cases} \]

Di sini:

  • \(\xi_i, \xi_i^*\): Slack variables (untuk kesalahan di luar \(\varepsilon\))
  • \(C\): parameter regulasi yang mengontrol trade-off antara kompleksitas model dan tingkat kesalahan yang diperbolehkan

5. Fungsi Kernel

Untuk menangani hubungan non-linear, SVR menggunakan fungsi kernel yang memetakan data ke ruang berdimensi lebih tinggi:

  • Linear: \[ K(x_i, x_j) = x_i^T x_j \]

  • Polynomial: \[ K(x_i, x_j) = (x_i^T x_j + r)^d \]

  • RBF (Radial Basis Function): \[ K(x_i, x_j) = \exp(-\gamma \|x_i - x_j\|^2) \]

  • Sigmoid: \[ K(x_i, x_j) = \tanh(\kappa x_i^T x_j + \theta) \]

Support vectors adalah titik data yang berada di luar batas toleransi dan berkontribusi langsung terhadap pembentukan model. Titik-titik ini menentukan parameter akhir model dan menjadikan SVR lebih efisien karena hanya sejumlah kecil data yang benar-benar memengaruhi fungsi prediksi.

keunggulan SVR:

  • Robust terhadap noise: Tidak memberikan penalti pada kesalahan kecil sehingga lebih tahan terhadap fluktuasi data yang tidak signifikan.
  • Menghindari overfitting: Dengan memusatkan perhatian hanya pada data penting, model menjadi lebih sederhana dan tidak menyesuaikan seluruh data secara berlebihan.
  • Fleksibel: Dapat diaplikasikan pada hubungan linear maupun non-linear dengan bantuan fungsi kernel seperti linear, polynomial, dan radial basis function (RBF).

Pendekatan ini menjadikan SVR sebagai metode regresi yang efektif dan robust, khususnya pada data yang mengandung noise atau variasi kecil yang tidak relevan.

kelemahan SVR:

  • Pemilihan parameter yang sensitif: Parameter \(C\), \(\varepsilon\), dan parameter kernel (misalnya \(\gamma\) pada RBF) sangat memengaruhi performa model.

  • Skalabilitas: SVR memerlukan komputasi yang tinggi untuk dataset besar karena kompleksitasnya bergantung pada jumlah data.

  • Kurang transparan: Interpretasi model bisa lebih sulit dibanding regresi linear biasa.

SVR cocok untuk berbagai kasus regresi yang memiliki:

  • Hubungan non-linear antar variabel
  • Adanya noise atau fluktuasi kecil
  • Kebutuhan akan prediksi yang stabil dan tahan terhadap outlier

Contoh aplikasi:

  • Prediksi harga saham atau komoditas (misal harga cabai)
  • Peramalan beban listrik
  • Prediksi permintaan barang
  • Analisis keuangan dan ekonomi

Library

# Load required libraries
library(MASS)        # untuk dataset Boston
library(e1071)       # untuk SVR
library(ggplot2)     # untuk plotting
library(caret)       # untuk evaluasi model
library(gridExtra)   # untuk multiple plots
library(knitr)       # untuk tabel
library(corrplot)    # untuk correlation plot
library(dplyr)       # untuk data manipulation
library(reshape2)    # untuk data reshaping

# Set seed untuk reproducibility
set.seed(123)

Eksplorasi Data

Data yang digunakan dalam analisis ini yaitu dataset Boston House Price. Dataset Boston Housing adalah dataset klasik yang sering digunakan dalam analisis regresi, yang berisi data mengenai perumahan di wilayah Boston, Massachusetts. Data ini berasal dari arsip StatLib (http://lib.stat.cmu.edu/datasets/boston) dan pertama kali dipublikasikan oleh Harrison, D. dan Rubinfeld, D.L. pada tahun 1978.

Dataset ini terdiri dari 506 sampel dengan 13 variabel prediktor dan satu variabel target, yaitu:

  1. CRIM: Tingkat kriminalitas per kapita berdasarkan kota
  2. ZN: Proporsi lahan perumahan yang ditetapkan untuk lot di atas 25.000 sq.ft
  3. INDUS: Proporsi luas lahan non-retail bisnis per kota
  4. CHAS: Variabel dummy Charles River (1 jika berbatasan dengan sungai; 0 jika tidak)
  5. NOX: Konsentrasi oksida nitrat (bagian per 10 juta)
  6. RM: Rata-rata jumlah kamar per hunian
  7. AGE: Proporsi unit hunian yang dibangun sebelum tahun 1940
  8. DIS: Jarak tertimbang ke lima pusat kerja di Boston
  9. RAD: Indeks aksesibilitas ke jalan raya radial
  10. TAX: Nilai pajak properti penuh per $10.000
  11. PTRATIO: Rasio murid-guru berdasarkan kota
  12. B: 1000(Bk - 0.63)^2 dimana Bk adalah proporsi penduduk keturunan Afrika-Amerika berdasarkan kota
  13. LSTAT: Persentase status populasi yang lebih rendah

Variabel targetnya adalah MEDV, yang menunjukkan nilai median rumah yang ditempati oleh pemiliknya dalam satuan ribu dolar Amerika.

data(Boston)
head(Boston)
# Melihat struktur data
str(Boston)
## 'data.frame':    506 obs. of  14 variables:
##  $ crim   : num  0.00632 0.02731 0.02729 0.03237 0.06905 ...
##  $ zn     : num  18 0 0 0 0 0 12.5 12.5 12.5 12.5 ...
##  $ indus  : num  2.31 7.07 7.07 2.18 2.18 2.18 7.87 7.87 7.87 7.87 ...
##  $ chas   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ nox    : num  0.538 0.469 0.469 0.458 0.458 0.458 0.524 0.524 0.524 0.524 ...
##  $ rm     : num  6.58 6.42 7.18 7 7.15 ...
##  $ age    : num  65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
##  $ dis    : num  4.09 4.97 4.97 6.06 6.06 ...
##  $ rad    : int  1 2 2 3 3 3 5 5 5 5 ...
##  $ tax    : num  296 242 242 222 222 222 311 311 311 311 ...
##  $ ptratio: num  15.3 17.8 17.8 18.7 18.7 18.7 15.2 15.2 15.2 15.2 ...
##  $ black  : num  397 397 393 395 397 ...
##  $ lstat  : num  4.98 9.14 4.03 2.94 5.33 ...
##  $ medv   : num  24 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9 ...
# Melihat dimensi data
dim(Boston)
## [1] 506  14
# Memeriksa nilai yang hilang
sum(is.na(Boston))
## [1] 0
# Ringkasan statistik data
summary(Boston)
##       crim                zn             indus            chas        
##  Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46   Min.   :0.00000  
##  1st Qu.: 0.08205   1st Qu.:  0.00   1st Qu.: 5.19   1st Qu.:0.00000  
##  Median : 0.25651   Median :  0.00   Median : 9.69   Median :0.00000  
##  Mean   : 3.61352   Mean   : 11.36   Mean   :11.14   Mean   :0.06917  
##  3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10   3rd Qu.:0.00000  
##  Max.   :88.97620   Max.   :100.00   Max.   :27.74   Max.   :1.00000  
##       nox               rm             age              dis        
##  Min.   :0.3850   Min.   :3.561   Min.   :  2.90   Min.   : 1.130  
##  1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02   1st Qu.: 2.100  
##  Median :0.5380   Median :6.208   Median : 77.50   Median : 3.207  
##  Mean   :0.5547   Mean   :6.285   Mean   : 68.57   Mean   : 3.795  
##  3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08   3rd Qu.: 5.188  
##  Max.   :0.8710   Max.   :8.780   Max.   :100.00   Max.   :12.127  
##       rad              tax           ptratio          black       
##  Min.   : 1.000   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 4.000   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 5.000   Median :330.0   Median :19.05   Median :391.44  
##  Mean   : 9.549   Mean   :408.2   Mean   :18.46   Mean   :356.67  
##  3rd Qu.:24.000   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :24.000   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##      lstat            medv      
##  Min.   : 1.73   Min.   : 5.00  
##  1st Qu.: 6.95   1st Qu.:17.02  
##  Median :11.36   Median :21.20  
##  Mean   :12.65   Mean   :22.53  
##  3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :37.97   Max.   :50.00
# Histogram target variable (medv)
p1 <- ggplot(Boston, aes(x = medv)) +
  geom_histogram(bins = 30, fill = "skyblue", alpha = 0.7) +
  labs(title = "Distribusi Harga Rumah (medv)", x = "Median Value ($1000s)", y = "Frequency") +
  theme_bw()

# Boxplot untuk deteksi outlier
p2 <- ggplot(Boston, aes(y = medv)) +
  geom_boxplot(fill = "lightcoral", alpha = 0.7) +
  labs(title = "Boxplot Harga Rumah", y = "Median Value ($1000s)") +
  theme_bw()

grid.arrange(p1, p2, ncol = 2)

Distribusi dari variabel medv terlihat mengandung data pencilan

# Melihat korelasi variabel penjelas dengan target (medv)
correlation_matrix <- cor(Boston)
correlation_with_medv <- correlation_matrix[,"medv"]
correlation_data <- data.frame(
  Variabel = names(correlation_with_medv),
  Korelasi = correlation_with_medv
)
correlation_data <- correlation_data[order(abs(correlation_data$Korelasi), decreasing = TRUE), ]
kable(correlation_data, caption = "Korelasi Variabel dengan Target (medv)")
Korelasi Variabel dengan Target (medv)
Variabel Korelasi
medv medv 1.0000000
lstat lstat -0.7376627
rm rm 0.6953599
ptratio ptratio -0.5077867
indus indus -0.4837252
tax tax -0.4685359
nox nox -0.4273208
crim crim -0.3883046
rad rad -0.3816262
age age -0.3769546
zn zn 0.3604453
black black 0.3334608
dis dis 0.2499287
chas chas 0.1752602
  1. Variabel target (medv) memiliki rentang nilai antara 5 hingga 50
  2. Terdapat beberapa variabel yang memiliki korelasi kuat dengan variabel target, seperti:
    • lstat (korelasi negatif kuat: -0.738)
    • rm (korelasi positif kuat: 0.695)
    • ptratio (korelasi negatif sedang: -0.508)
# Scatter plot beberapa variabel penting vs medv
p1 <- ggplot(Boston, aes(x = lstat, y = medv)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(title = "LSTAT vs MEDV", x = "Status populasi yang lebih rendah (%)", y = "Nilai median rumah") +
  theme_bw()

p2 <- ggplot(Boston, aes(x = rm, y = medv)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "blue") +
  labs(title = "RM vs MEDV", x = "Rata-rata jumlah kamar per hunian", y = "Nilai median rumah") +
  theme_bw()

p3 <- ggplot(Boston, aes(x = ptratio, y = medv)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "green") +
  labs(title = "PTRATIO vs MEDV", x = "Rasio murid-guru berdasarkan kota", y = "Nilai median rumah") +
  theme_bw()

grid.arrange(p1, p2, p3, ncol = 2, nrow = 2)

# Membagi data menjadi training (80%) dan testing (20%)
train_indices <- createDataPartition(Boston$medv, p = 0.8, list = FALSE)
train_data <- Boston[train_indices, ]
test_data <- Boston[-train_indices, ]

# Memeriksa dimensi data training dan testing
cat("Dimensi data training:", dim(train_data), "\n")
## Dimensi data training: 407 14
cat("Dimensi data testing:", dim(test_data))
## Dimensi data testing: 99 14

SVR Linear

# SVR Linear
svr_linear <- svm(medv ~ ., data = train_data, 
                  type = "eps-regression", 
                  kernel = "linear", 
                  cost = 1, 
                  epsilon = 0.1)

# Prediksi
pred_svr_linear_train <- predict(svr_linear, train_data)
pred_svr_linear_test <- predict(svr_linear, test_data)

summary(svr_linear)
## 
## Call:
## svm(formula = medv ~ ., data = train_data, type = "eps-regression", 
##     kernel = "linear", cost = 1, epsilon = 0.1)
## 
## 
## Parameters:
##    SVM-Type:  eps-regression 
##  SVM-Kernel:  linear 
##        cost:  1 
##       gamma:  0.07692308 
##     epsilon:  0.1 
## 
## 
## Number of Support Vectors:  307

SVR Non-linear (RBF Kernel)

# SVR dengan RBF kernel
svr_rbf <- svm(medv ~ ., data = train_data, 
               type = "eps-regression", 
               kernel = "radial", 
               cost = 10, 
               gamma = 0.1,
               epsilon = 0.1)

# Prediksi
pred_svr_rbf_train <- predict(svr_rbf, train_data)
pred_svr_rbf_test <- predict(svr_rbf, test_data)
summary(svr_rbf)
## 
## Call:
## svm(formula = medv ~ ., data = train_data, type = "eps-regression", 
##     kernel = "radial", cost = 10, gamma = 0.1, epsilon = 0.1)
## 
## 
## Parameters:
##    SVM-Type:  eps-regression 
##  SVM-Kernel:  radial 
##        cost:  10 
##       gamma:  0.1 
##     epsilon:  0.1 
## 
## 
## Number of Support Vectors:  277

OLS

# Model OLS
ols_model <- lm(medv ~ ., data = train_data)

# Prediksi
pred_ols_train <- predict(ols_model, train_data)
pred_ols_test <- predict(ols_model, test_data)

summary(ols_model)
## 
## Call:
## lm(formula = medv ~ ., data = train_data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -14.9550  -2.7996  -0.4647   1.7767  25.0993 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  37.733617   5.619935   6.714 6.63e-11 ***
## crim         -0.093857   0.039157  -2.397 0.016999 *  
## zn            0.039436   0.015987   2.467 0.014062 *  
## indus        -0.012988   0.069595  -0.187 0.852059    
## chas          2.290187   0.940621   2.435 0.015346 *  
## nox         -17.130560   4.342272  -3.945 9.45e-05 ***
## rm            3.499219   0.451445   7.751 7.87e-14 ***
## age           0.009823   0.015510   0.633 0.526905    
## dis          -1.390769   0.230614  -6.031 3.77e-09 ***
## rad           0.330939   0.077135   4.290 2.25e-05 ***
## tax          -0.012386   0.004342  -2.852 0.004568 ** 
## ptratio      -0.960676   0.150307  -6.391 4.66e-10 ***
## black         0.009841   0.002935   3.353 0.000877 ***
## lstat        -0.562095   0.059180  -9.498  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4.801 on 393 degrees of freedom
## Multiple R-squared:  0.7346, Adjusted R-squared:  0.7258 
## F-statistic: 83.68 on 13 and 393 DF,  p-value: < 2.2e-16

Perbandingan SVR dengan OLS

calculate_metrics <- function(actual, predicted) {
  rmse <- sqrt(mean((actual - predicted)^2))
  mae <- mean(abs(actual - predicted))
  r2 <- 1 - sum((actual - predicted)^2) / sum((actual - mean(actual))^2)
  
  return(c(RMSE = rmse, MAE = mae, R2 = r2))
}
# Evaluasi untuk data training
train_metrics <- data.frame(
  Model = c("SVR Linear", "SVR RBF", "OLS"),
  rbind(
    calculate_metrics(train_data$medv, pred_svr_linear_train),
    calculate_metrics(train_data$medv, pred_svr_rbf_train),
    calculate_metrics(train_data$medv, pred_ols_train)
  )
)

# Evaluasi untuk data testing
test_metrics <- data.frame(
  Model = c("SVR Linear", "SVR RBF", "OLS"),
  rbind(
    calculate_metrics(test_data$medv, pred_svr_linear_test),
    calculate_metrics(test_data$medv, pred_svr_rbf_test),
    calculate_metrics(test_data$medv, pred_ols_test)
  )
)

kable(train_metrics, digits = 4, caption = "Metrik Evaluasi - Data Training")
Metrik Evaluasi - Data Training
Model RMSE MAE R2
SVR Linear 5.0158 3.0860 0.7000
SVR RBF 1.6612 1.0852 0.9671
OLS 4.7173 3.2781 0.7346
kable(test_metrics, digits = 4, caption = "Metrik Evaluasi - Data Testing")
Metrik Evaluasi - Data Testing
Model RMSE MAE R2
SVR Linear 4.6854 3.1500 0.7470
SVR RBF 2.6743 1.9644 0.9176
OLS 4.5889 3.3655 0.7573

Data Training:

SVR RBF
- RMSE dan MAE paling rendah.
- R² tertinggi (0.9671), menunjukkan kemampuan sangat baik dalam mempelajari pola dari data.
- Menunjukkan performa terbaik di antara ketiga model pada data training.

OLS (Ordinary Least Squares)
- R² sedikit lebih tinggi dari SVR Linear.
- MAE sedikit lebih besar dibanding SVR Linear.

SVR Linear
- MAE lebih kecil dari OLS, namun R² lebih rendah.
- Kurang mampu menangkap kompleksitas data dibanding SVR RBF.

Simpulan:
- SVR RBF secara signifikan mengungguli model lain pada data training.
- Model ini mampu menangkap pola kompleks secara efisien.

Data Testing:

SVR RBF
- RMSE dan MAE terendah di antara semua model.
- R² paling tinggi (0.9176), menunjukkan performa umum terbaik pada data yang belum pernah dilihat sebelumnya.

OLS (Ordinary Least Squares)
- R² sedikit lebih tinggi dari SVR Linear (0.7573 vs. 0.7470).
- Namun, memiliki MAE yang lebih besar, artinya rata-rata kesalahan prediksinya lebih tinggi.

SVR Linear
- Performa serupa dengan OLS.
- Namun, R² masih lebih rendah dibandingkan OLS, sehingga menjelaskan variasi data dengan sedikit kurang akurat.

Simpulan:
- SVR RBF tetap menjadi model terbaik pada data testing, dengan kemampuan generalisasi yang sangat baik terhadap data baru.
- Hal ini ditunjukkan oleh kombinasi RMSE & MAE yang rendah, serta R² yang tinggi.
- Selisih antara R² Training dan Testing tidak terlalu besar (sekitar 0.05 poin atau 5%), menandakan konsistensi performa.

Plot Residual Model

# Residual plots
residuals_data <- data.frame(
  Predicted_SVR_Linear = pred_svr_linear_test,
  Residuals_SVR_Linear = test_data$medv - pred_svr_linear_test,
  Predicted_SVR_RBF = pred_svr_rbf_test,
  Residuals_SVR_RBF = test_data$medv - pred_svr_rbf_test,
  Predicted_OLS = pred_ols_test,
  Residuals_OLS = test_data$medv - pred_ols_test
)

p1 <- ggplot(residuals_data, aes(x = Predicted_SVR_Linear, y = Residuals_SVR_Linear)) +
  geom_point(alpha = 0.6) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "SVR Linear - Residuals", x = "Predicted Values", y = "Residuals") +
  theme_bw()

p2 <- ggplot(residuals_data, aes(x = Predicted_SVR_RBF, y = Residuals_SVR_RBF)) +
  geom_point(alpha = 0.6) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "SVR RBF - Residuals", x = "Predicted Values", y = "Residuals") +
  theme_bw()

p3 <- ggplot(residuals_data, aes(x = Predicted_OLS, y = Residuals_OLS)) +
  geom_point(alpha = 0.6) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "OLS - Residuals", x = "Predicted Values", y = "Residuals") +
  theme_bw()

grid.arrange(p1, p2, p3, ncol = 3)

Aktual vs Prediksi

# Buat dataframe untuk plotting
plot_data_test <- data.frame(
  Actual = test_data$medv,
  SVR_Linear = pred_svr_linear_test,
  SVR_RBF = pred_svr_rbf_test,
  OLS = pred_ols_test
)

# Reshape data untuk ggplot
plot_data_melted <- melt(plot_data_test, id.vars = "Actual", 
                        variable.name = "Model", value.name = "Predicted")

# Plot Actual vs Predicted
ggplot(plot_data_melted, aes(x = Actual, y = Predicted, color = Model)) +
  geom_point(alpha = 0.6, size = 2) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "black") +
  facet_wrap(~Model, ncol = 3) +
  labs(title = "Actual vs Predicted Values - Test Data", 
       x = "Actual Values", y = "Predicted Values") +
  theme_bw() +
  theme(legend.position = "bottom")

Visualisasi Epsilon-Tube dan Support Vector(1D)

# Menggunakan lstat sebagai predictor tunggal

# Model SVR 1D
train_1d <- train_data[, c("lstat", "medv")]
test_1d <- test_data[, c("lstat", "medv")]

svr_1d_linear <- svm(medv ~ lstat, data = train_1d, 
                     type = "eps-regression", 
                     kernel = "linear", 
                     cost = 1, 
                     epsilon = 0.5)

svr_1d_rbf <- svm(medv ~ lstat, data = train_1d, 
                  type = "eps-regression", 
                  kernel = "radial", 
                  cost = 10, 
                  gamma = 0.1,
                  epsilon = 0.5)

# Prediksi untuk plotting
lstat_range <- seq(min(train_1d$lstat), max(train_1d$lstat), length.out = 100)
pred_data <- data.frame(lstat = lstat_range)

pred_1d_linear <- predict(svr_1d_linear, pred_data)
pred_1d_rbf <- predict(svr_1d_rbf, pred_data)


# Identifikasi support vectors
sv_indices_linear <- svr_1d_linear$index
sv_indices_rbf <- svr_1d_rbf$index

support_vectors_linear <- train_1d[sv_indices_linear, ]
support_vectors_rbf <- train_1d[sv_indices_rbf, ]

# Fungsi untuk membuat plot SVR dengan support vectors
create_svr_plot <- function(train_data, lstat_range, predictions, support_vectors, 
                           title, color, epsilon = 0.1) {
  
  plot_data <- data.frame(lstat = lstat_range, pred = predictions)
  
  p <- ggplot() +
    # Data points
    geom_point(data = train_data, aes(x = lstat, y = medv), 
               alpha = 0.6, size = 2, color = "gray50") +
    
    # Support vectors (highlighted)
    geom_point(data = support_vectors, aes(x = lstat, y = medv), 
               color = color, size = 3, shape = 21, fill = "white", stroke = 2) +
    
    # Epsilon-tube (zona toleransi)
    geom_ribbon(data = plot_data, 
                aes(x = lstat, ymin = pred - epsilon, ymax = pred + epsilon), 
                alpha = 0.2, fill = "yellow") +
    
    # Batas atas epsilon-tube
    geom_line(data = plot_data, 
              aes(x = lstat, y = pred + epsilon), 
              color = color, linetype = "dashed", alpha = 0.7) +
    
    # Batas bawah epsilon-tube
    geom_line(data = plot_data, 
              aes(x = lstat, y = pred - epsilon), 
              color = color, linetype = "dashed", alpha = 0.7) +
    
    # Regression line
    geom_line(data = plot_data, 
              aes(x = lstat, y = pred), 
              color = color, size = 1.2) +
    
    labs(title = title, 
         x = "LSTAT", 
         y = "MEDV",
         subtitle = paste("ε-tube (ε =", epsilon, "), Support Vectors:", nrow(support_vectors))) +
    
    theme_minimal() +
    theme(plot.title = element_text(size = 14, face = "bold"),
          plot.subtitle = element_text(size = 11),
          axis.title = element_text(size = 11),
          axis.text = element_text(size = 10),
          panel.grid.minor = element_blank(),
          plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), "cm"))
  
  return(p)
}

# Buat plot untuk SVR Linear
p1 <- create_svr_plot(train_1d, lstat_range, pred_1d_linear, support_vectors_linear, 
                      "SVR Linear dengan Epsilon-Tube", "blue")

# Buat plot untuk SVR RBF
p2 <- create_svr_plot(train_1d, lstat_range, pred_1d_rbf, support_vectors_rbf, 
                      "SVR RBF dengan Epsilon-Tube", "red")

# Tampilkan plot dengan layout yang lebih baik
grid.arrange(p1, p2, ncol = 2, nrow = 1)

Parameter Epsilon, Cost(C), dan Gamma

epsilon

# Test berbagai nilai epsilon
epsilon_values <- c(0.01, 0.1, 0.5, 1.0, 2.0)
epsilon_results <- data.frame()

for (eps in epsilon_values) {
  svr_temp <- svm(medv ~ ., data = train_data, 
                  type = "eps-regression", 
                  kernel = "radial", 
                  cost = 10, 
                  gamma = 0.1,
                  epsilon = eps)
  
  pred_temp <- predict(svr_temp, test_data)
  metrics_temp <- calculate_metrics(test_data$medv, pred_temp)
  
  epsilon_results <- rbind(epsilon_results, 
                          data.frame(Epsilon = eps, 
                                   RMSE = metrics_temp[1], 
                                   MAE = metrics_temp[2], 
                                   R2 = metrics_temp[3]))
}

kable(epsilon_results, digits = 4, caption = "Pengaruh Parameter Epsilon")
Pengaruh Parameter Epsilon
Epsilon RMSE MAE R2
RMSE 0.01 2.7857 2.0143 0.9106
RMSE1 0.10 2.6743 1.9644 0.9176
RMSE2 0.50 3.5178 2.5759 0.8574
RMSE3 1.00 5.5122 4.6506 0.6498
RMSE4 2.00 10.7648 9.6435 -0.3356
# Test berbagai nilai cost
cost_values <- c(0.1, 1, 10, 100, 1000)
cost_results <- data.frame()

for (c_val in cost_values) {
  svr_temp <- svm(medv ~ ., data = train_data, 
                  type = "eps-regression", 
                  kernel = "radial", 
                  cost = c_val, 
                  gamma = 0.1,
                  epsilon = 0.1)
  
  pred_temp <- predict(svr_temp, test_data)
  metrics_temp <- calculate_metrics(test_data$medv, pred_temp)
  
  cost_results <- rbind(cost_results, 
                       data.frame(Cost = c_val, 
                                RMSE = metrics_temp[1], 
                                MAE = metrics_temp[2], 
                                R2 = metrics_temp[3]))
}

kable(cost_results, digits = 4, caption = "Pengaruh Parameter Cost")
Pengaruh Parameter Cost
Cost RMSE MAE R2
RMSE 1e-01 6.1386 3.5381 0.5657
RMSE1 1e+00 3.8619 2.3528 0.8281
RMSE2 1e+01 2.6743 1.9644 0.9176
RMSE3 1e+02 3.4411 2.5219 0.8635
RMSE4 1e+03 4.0788 2.9768 0.8083
# Plot pengaruh cost
p1 <- ggplot(cost_results, aes(x = log10(Cost), y = RMSE)) +
  geom_line(color = "blue") + geom_point(color = "blue") +
  labs(title = "Pengaruh Cost terhadap RMSE", x = "log10(Cost)") + theme_bw()

p2 <- ggplot(cost_results, aes(x = log10(Cost), y = R2)) +
  geom_line(color = "red") + geom_point(color = "red") +
  labs(title = "Pengaruh Cost terhadap R²", x = "log10(Cost)") + theme_bw()

grid.arrange(p1, p2, ncol = 2)

# Test berbagai nilai gamma
gamma_values <- c(0.001, 0.01, 0.1, 1, 10)
gamma_results <- data.frame()

for (g_val in gamma_values) {
  svr_temp <- svm(medv ~ ., data = train_data, 
                  type = "eps-regression", 
                  kernel = "radial", 
                  cost = 10, 
                  gamma = g_val,
                  epsilon = 0.1)
  
  pred_temp <- predict(svr_temp, test_data)
  metrics_temp <- calculate_metrics(test_data$medv, pred_temp)
  
  gamma_results <- rbind(gamma_results, 
                        data.frame(Gamma = g_val, 
                                 RMSE = metrics_temp[1], 
                                 MAE = metrics_temp[2], 
                                 R2 = metrics_temp[3]))
}

kable(gamma_results, digits = 4, caption = "Pengaruh Parameter Gamma")
Pengaruh Parameter Gamma
Gamma RMSE MAE R2
RMSE 1e-03 4.6989 3.1067 0.7455
RMSE1 1e-02 3.7887 2.3406 0.8346
RMSE2 1e-01 2.6743 1.9644 0.9176
RMSE3 1e+00 4.7893 3.3144 0.7356
RMSE4 1e+01 8.7717 6.2238 0.1132
# Plot pengaruh gamma
p1 <- ggplot(gamma_results, aes(x = log10(Gamma), y = RMSE)) +
  geom_line(color = "blue") + geom_point(color = "blue") +
  labs(title = "Pengaruh Gamma terhadap RMSE", x = "log10(Gamma)") +
  theme_bw()

p2 <- ggplot(gamma_results, aes(x = log10(Gamma), y = R2)) +
  geom_line(color = "red") + geom_point(color = "red") +
  labs(title = bquote("Pengaruh Gamma terhadap" ~ R^2), x = "log10(Gamma)") +
  theme_bw()

grid.arrange(p1, p2, ncol = 2)

Parameter Optimal

# Grid search untuk parameter optimal
tune_result <- tune(svm, medv ~ ., data = train_data,
                   type = "eps-regression",
                   kernel = "radial",
                   ranges = list(cost = c(1, 10, 100),
                               gamma = c(0.001, 0.01, 0.1, 1, 10),
                               epsilon = c(0.01, 0.1, 0.5, 1.0, 2.0)))

print(tune_result$best.parameters)
##    cost gamma epsilon
## 23   10   0.1     0.1
print(tune_result$best.performance)
## [1] 13.13684
# Model dengan parameter optimal
svr_optimal <- tune_result$best.model
pred_optimal_test <- predict(svr_optimal, test_data)
metrics_optimal <- calculate_metrics(test_data$medv, pred_optimal_test)

print(metrics_optimal)
##      RMSE       MAE        R2 
## 2.6742851 1.9643708 0.9175722

Simpulan:

  1. Performa Model: - SVR RBF umumnya memberikan performa terbaik dalam menangkap pola nonlinear dalam data - SVR Linear memiliki performa yang sebanding dengan OLS untuk hubungan linear - Model OLS memberikan baseline yang baik untuk perbandingan

  2. Pengaruh Parameter:

    • Epsilon (ε): Parameter yang mengontrol lebar epsilon-tube. Nilai yang terlalu kecil dapat menyebabkan overfitting, sedangkan nilai yang terlalu besar dapat menyebabkan underfitting
    • Cost (C): Parameter regularisasi yang mengontrol trade-off antara kompleksitas model dan toleransi error
    • Gamma (γ): Parameter kernel RBF yang mengontrol pengaruh setiap training example