Human Development Index (HDI) atau Indeks Pembangunan Manusia (IPM) merupakan salah satu indikator yang digunakan untuk melihat tingkat pembangunan manusia di suatu negara. HDI menggambarkan pencapaian pembangunan manusia melalui aspek kesehatan, pendidikan, dan standar hidup. Perbedaan nilai HDI antarnegara dapat dipengaruhi oleh berbagai kondisi sosial dan ekonomi.
Dalam praktikum ini, digunakan enam variabel prediktor, yaitu GDP per capita, social support, healthy life expectancy, freedom to make life choices, generosity, dan perceptions of corruption. Keenam variabel tersebut digunakan untuk menganalisis pola hubungan dengan HDI melalui pendekatan machine learning.
Metode yang digunakan adalah Support Vector Machine (SVM), Support Vector Regression (SVR), dan Neural Network (NN). SVM digunakan untuk mengklasifikasikan HDI ke dalam dua kategori, yaitu tinggi dan rendah, dengan batas nilai 0,700. Sementara itu, SVR digunakan untuk memprediksi nilai HDI dalam bentuk numerik. NN diterapkan untuk kedua permasalahan tersebut, baik klasifikasi maupun regresi. Setiap metode diuji menggunakan beberapa konfigurasi model. Pada SVM dan SVR dilakukan pengujian kernel serta kombinasi hyperparameter, sedangkan pada NN dilakukan perbandingan jumlah neuron dan struktur hidden layer, termasuk NN biasa dan Deep Neural Network. Selain itu, digunakan 5-fold dan 10-fold cross-validation untuk membandingkan hasil evaluasi dan menentukan konfigurasi model yang paling sesuai.
Melalui praktikum ini, dilakukan perbandingan performa SVM, SVR, dan NN dalam mengklasifikasikan serta memprediksi HDI. Hasil pengujian diharapkan dapat menunjukkan kombinasi parameter dan konfigurasi model yang memberikan performa terbaik berdasarkan metrik evaluasi klasifikasi dan regresi.
Memahami penerapan metode Support Vector Machine (SVM), Support Vector Regression (SVR), dan Neural Network (NN) dalam menyelesaikan permasalahan klasifikasi dan regresi.
Membangun model klasifikasi untuk mengelompokkan negara berdasarkan kategori Human Development Index (HDI), yaitu tinggi dan rendah, menggunakan metode SVM dan Neural Network.
Membangun model regresi untuk memprediksi nilai Human Development Index (HDI) menggunakan metode SVR dan Neural Network.
Melakukan optimasi hyperparameter pada setiap metode untuk memperoleh kombinasi parameter yang memberikan performa model terbaik, serta mengevaluasi model menggunakan cross-validation.
Membandingkan performa model klasifikasi dan regresi berdasarkan metrik evaluasi yang sesuai untuk menentukan model yang paling baik dalam menyelesaikan masing-masing permasalahan.
Data yang digunakan dalam praktikum ini merupakan data sekunder yang terdiri dari 153 observasi. Data mencakup informasi mengenai kondisi sosial, ekonomi, dan pembangunan manusia dari sejumlah negara. Data tersebut digunakan untuk membangun model klasifikasi dan regresi dengan HDI sebagai variabel yang dianalisis.
Sumber data berasal dari World Happiness Report dan Human Development Data Center yang dikelola oleh United Nations Development Programme (UNDP). Kedua sumber tersebut menyediakan informasi terkait kondisi kesejahteraan dan pembangunan manusia antarnegara.
tabel_y <- data.frame(
Kode = "Y",
Variabel = "Human Development Index (HDI)",
Keterangan = "Indeks yang menggambarkan tingkat pembangunan manusia berdasarkan dimensi kesehatan, pendidikan, dan standar hidup layak."
)
knitr::kable(
tabel_y,
caption = "Deskripsi Variabel Respons",
align = "c"
)| Kode | Variabel | Keterangan |
|---|---|---|
| Y | Human Development Index (HDI) | Indeks yang menggambarkan tingkat pembangunan manusia berdasarkan dimensi kesehatan, pendidikan, dan standar hidup layak. |
# Tabel variabel prediktor
tabel_x <- data.frame(
Kode = paste0("X", 1:6),
Variabel = c(
"GDP per Capita",
"Social Support",
"Healthy Life Expectancy",
"Freedom to Make Life Choices",
"Generosity",
"Perceptions of Corruption"
),
Keterangan = c(
"Menggambarkan tingkat pendapatan atau aktivitas ekonomi per kapita.",
"Menggambarkan dukungan sosial yang dirasakan individu.",
"Menggambarkan perkiraan harapan hidup sehat masyarakat.",
"Menggambarkan kebebasan individu dalam menentukan pilihan hidup.",
"Menggambarkan kecenderungan perilaku kedermawanan atau kepedulian terhadap orang lain.",
"Menggambarkan persepsi masyarakat terhadap tingkat korupsi dalam pemerintahan dan institusi."
)
)
knitr::kable(
tabel_x,
caption = "Deskripsi Variabel Prediktor",
align = c("c", "l", "l")
)| Kode | Variabel | Keterangan |
|---|---|---|
| X1 | GDP per Capita | Menggambarkan tingkat pendapatan atau aktivitas ekonomi per kapita. |
| X2 | Social Support | Menggambarkan dukungan sosial yang dirasakan individu. |
| X3 | Healthy Life Expectancy | Menggambarkan perkiraan harapan hidup sehat masyarakat. |
| X4 | Freedom to Make Life Choices | Menggambarkan kebebasan individu dalam menentukan pilihan hidup. |
| X5 | Generosity | Menggambarkan kecenderungan perilaku kedermawanan atau kepedulian terhadap orang lain. |
| X6 | Perceptions of Corruption | Menggambarkan persepsi masyarakat terhadap tingkat korupsi dalam pemerintahan dan institusi. |
Sebelum memasuki tahap pengolahan data dan pemodelan, dilakukan persiapan lingkungan analisis menggunakan perangkat lunak R. Tahap ini mencakup pengaturan konfigurasi code chunk, penetapan nilai random seed, serta instalasi dan pemanggilan package yang dibutuhkan selama proses analisis.
Pengaturan awal dilakukan untuk memastikan proses analisis berjalan secara konsisten, meminimalkan gangguan pada tampilan output, serta mempermudah penyajian hasil dalam dokumen R Markdown.
Konfigurasi awal dilakukan melalui fungsi
knitr::opts_chunk$set() untuk mengatur perilaku setiap
code chunk dalam dokumen. Pada analisis ini, kode secara
default ditampilkan, sedangkan pesan dan peringatan dari package
disembunyikan agar hasil analisis terlihat lebih ringkas.
Selain itu, digunakan set.seed(2026) untuk menjaga
konsistensi hasil dari proses yang melibatkan bilangan acak, seperti
pembagian data menjadi data latih dan data uji.
Analisis ini memanfaatkan beberapa package R yang memiliki fungsi berbeda, mulai dari pengolahan data, visualisasi, hingga pembentukan model Support Vector Regression (SVR).
Berikut merupakan package yang digunakan beserta fungsinya.
| Package | Fungsi |
|---|---|
e1071 |
Membentuk model Support Vector Regression (SVR). |
ggplot2 |
Membuat visualisasi data dan hasil analisis. |
dplyr |
Melakukan manipulasi dan pengolahan data. |
knitr |
Mendukung penyajian tabel dan output dalam dokumen R Markdown. |
readr |
Membaca dan mengimpor data. |
janitor |
Membersihkan dan merapikan nama kolom serta struktur data. |
corrplot |
Memvisualisasikan matriks korelasi antarvariabel. |
tidyr |
Merapikan data dan menangani missing value. |
rsample |
Membantu proses pembagian data dan cross-validation. |
kernlab |
Membentuk model SVM dan SVR dengan berbagai kernel. |
yardstick |
Menghitung metrik evaluasi performa model. |
purrr |
Membantu melakukan iterasi dan pengolahan data secara berulang. |
tibble |
Membuat dan mengelola tabel data dalam bentuk tibble. |
Sebelum digunakan, dilakukan pemeriksaan ketersediaan package pada
sistem. Apabila terdapat package yang belum terpasang, R akan
menginstalnya secara otomatis. Selanjutnya, seluruh package dipanggil
menggunakan fungsi library() agar dapat digunakan dalam
tahapan analisis berikutnya.
# Package yang digunakan
paket <- c(
"e1071",
"ggplot2",
"dplyr",
"knitr",
"readr",
"janitor",
"corrplot",
"tidyr",
"rsample",
"kernlab",
"yardstick",
"purrr",
"tibble"
)
# Instalasi package jika belum tersedia
belum <- paket[
!vapply(paket, requireNamespace, logical(1), quietly = TRUE)
]
if (length(belum) > 0) {
install.packages(belum, repos = "https://cloud.r-project.org")
}
# Memanggil package
library(e1071)
library(ggplot2)
library(dplyr)
library(knitr)
library(janitor)
library(corrplot)
library(tidyr)
library(rsample)
library(kernlab)
library(yardstick)
library(purrr)
library(tibble)Sebelum masuk ke tahap pengolahan dan analisis data, dilakukan proses import dataset yang akan digunakan dalam pemodelan. Dataset yang digunakan merupakan data yang telah melalui tahap preprocessing dan disimpan dalam format CSV dengan nama data_preprocessed.csv. Data tersebut memuat informasi mengenai sejumlah negara, termasuk indikator sosial ekonomi dan nilai Human Development Index (HDI).
Proses import dilakukan menggunakan fungsi read.csv() untuk membaca dataset ke dalam lingkungan kerja R. Setelah data berhasil diimpor, dilakukan pemeriksaan awal menggunakan fungsi head(), tail(), summary(), dan str() untuk memperoleh gambaran mengenai isi, karakteristik, serta struktur dataset sebelum memasuki tahapan analisis lebih lanjut.
calon <- unique(c(params$file_hdi, "data_preprocessed.csv"))
ada <- calon[file.exists(calon)]
if (!length(ada)) stop("CSV HDI tidak ditemukan. Simpan di output/data_preprocessed.csv atau ubah params$file_hdi. Untuk contoh saja, set jalankan_hdi: false.")
raw_hdi <- readr::read_csv(ada[1], show_col_types=FALSE)
asal <- c("GDP per capita", "Social support", "Healthy life expectancy",
"Freedom to make life choices", "Generosity", "Perceptions of corruption")
aman <- c("gdp", "support", "health", "freedom", "generosity", "corruption")
wajib <- c("hdi", asal)
hilang <- setdiff(wajib, names(raw_hdi))
if (length(hilang)) stop("Kolom tidak ditemukan: ", paste(hilang, collapse=", "))
hdi <- as.data.frame(raw_hdi[, wajib])
names(hdi) <- c("hdi", aman)
if (!all(vapply(hdi, is.numeric, logical(1))))
stop("Seluruh variabel harus numerik. Periksa CSV/preprocessing.")
valid <- Reduce(`&`, lapply(hdi, is.finite))
cat("Baris awal:", nrow(hdi), "| Tidak lengkap/tidak finite:", sum(!valid), "\n")## Baris awal: 153 | Tidak lengkap/tidak finite: 0
baris_asal <- which(valid)
hdi <- hdi[valid, , drop=FALSE]
if (nrow(hdi)<30) stop("Minimal 30 baris lengkap untuk rancangan praktikum ini.")
if (any(hdi$hdi<0 | hdi$hdi>1)) stop("HDI harus pada rentang 0–1; periksa sumber.")
knitr::kable(summary(hdi), digits=3)| hdi | gdp | support | health | freedom | generosity | corruption | |
|---|---|---|---|---|---|---|---|
| Min. :0.3880 | Min. :0.0000 | Min. :0.000 | Min. :0.0000 | Min. :0.0000 | Min. :0.0000 | Min. :0.000 | |
| 1st Qu.:0.6170 | 1st Qu.:0.5780 | 1st Qu.:1.055 | 1st Qu.:0.5380 | 1st Qu.:0.3050 | 1st Qu.:0.1080 | 1st Qu.:0.047 | |
| Median :0.7760 | Median :0.9600 | Median :1.274 | Median :0.7890 | Median :0.4170 | Median :0.1770 | Median :0.085 | |
| Mean :0.7455 | Mean :0.8999 | Mean :1.207 | Mean :0.7217 | Mean :0.3921 | Mean :0.1839 | Mean :0.111 | |
| 3rd Qu.:0.8890 | 3rd Qu.:1.2210 | 3rd Qu.:1.454 | 3rd Qu.:0.8810 | 3rd Qu.:0.5080 | 3rd Qu.:0.2470 | 3rd Qu.:0.141 | |
| Max. :0.9720 | Max. :1.6840 | Max. :1.624 | Max. :1.1410 | Max. :0.6310 | Max. :0.5660 | Max. :0.453 |
## Overall.rank Country.or.region Score GDP.per.capita Social.support
## 1 1 Finland 7.769 1.340 1.587
## 2 2 Denmark 7.600 1.383 1.573
## 3 3 Norway 7.554 1.488 1.582
## 4 4 Iceland 7.494 1.380 1.624
## 5 5 Netherlands 7.488 1.396 1.522
## 6 6 Switzerland 7.480 1.452 1.526
## Healthy.life.expectancy Freedom.to.make.life.choices Generosity
## 1 0.986 0.596 0.153
## 2 0.996 0.592 0.252
## 3 1.028 0.603 0.271
## 4 1.026 0.591 0.354
## 5 0.999 0.557 0.322
## 6 1.052 0.572 0.263
## Perceptions.of.corruption hdi_name join_key hdi
## 1 0.393 <NA> Finland 0.948
## 2 0.410 <NA> Denmark 0.962
## 3 0.341 <NA> Norway 0.970
## 4 0.118 <NA> Iceland 0.972
## 5 0.298 <NA> Netherlands 0.955
## 6 0.343 <NA> Switzerland 0.970
## Overall.rank Country.or.region Score GDP.per.capita Social.support
## 148 151 Yemen 3.380 0.287 1.163
## 149 152 Rwanda 3.334 0.359 0.711
## 150 153 Tanzania 3.231 0.476 0.885
## 151 154 Afghanistan 3.203 0.350 0.517
## 152 155 Central African Republic 3.083 0.026 0.000
## 153 156 South Sudan 2.853 0.306 0.575
## Healthy.life.expectancy Freedom.to.make.life.choices Generosity
## 148 0.463 0.143 0.108
## 149 0.614 0.555 0.217
## 150 0.499 0.417 0.276
## 151 0.361 0.000 0.158
## 152 0.105 0.225 0.235
## 153 0.295 0.010 0.202
## Perceptions.of.corruption hdi_name join_key hdi
## 148 0.077 <NA> Yemen 0.470
## 149 0.411 <NA> Rwanda 0.578
## 150 0.147 <NA> Tanzania 0.555
## 151 0.025 <NA> Afghanistan 0.496
## 152 0.035 <NA> Central African Republic 0.414
## 153 0.091 <NA> South Sudan 0.388
## Overall.rank Country.or.region Score GDP.per.capita
## Min. : 1.00 Length:153 Min. :2.853 Min. :0.0000
## 1st Qu.: 40.00 Class :character 1st Qu.:4.534 1st Qu.:0.5780
## Median : 80.00 Mode :character Median :5.339 Median :0.9600
## Mean : 79.16 Mean :5.394 Mean :0.8999
## 3rd Qu.:118.00 3rd Qu.:6.182 3rd Qu.:1.2210
## Max. :156.00 Max. :7.769 Max. :1.6840
## Social.support Healthy.life.expectancy Freedom.to.make.life.choices
## Min. :0.000 Min. :0.0000 Min. :0.0000
## 1st Qu.:1.055 1st Qu.:0.5380 1st Qu.:0.3050
## Median :1.274 Median :0.7890 Median :0.4170
## Mean :1.207 Mean :0.7217 Mean :0.3921
## 3rd Qu.:1.454 3rd Qu.:0.8810 3rd Qu.:0.5080
## Max. :1.624 Max. :1.1410 Max. :0.6310
## Generosity Perceptions.of.corruption hdi_name
## Min. :0.0000 Min. :0.000 Length:153
## 1st Qu.:0.1080 1st Qu.:0.047 Class :character
## Median :0.1770 Median :0.085 Mode :character
## Mean :0.1839 Mean :0.111
## 3rd Qu.:0.2470 3rd Qu.:0.141
## Max. :0.5660 Max. :0.453
## join_key hdi
## Length:153 Min. :0.3880
## Class :character 1st Qu.:0.6170
## Mode :character Median :0.7760
## Mean :0.7455
## 3rd Qu.:0.8890
## Max. :0.9720
## 'data.frame': 153 obs. of 12 variables:
## $ Overall.rank : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Country.or.region : chr "Finland" "Denmark" "Norway" "Iceland" ...
## $ Score : num 7.77 7.6 7.55 7.49 7.49 ...
## $ GDP.per.capita : num 1.34 1.38 1.49 1.38 1.4 ...
## $ Social.support : num 1.59 1.57 1.58 1.62 1.52 ...
## $ Healthy.life.expectancy : num 0.986 0.996 1.028 1.026 0.999 ...
## $ Freedom.to.make.life.choices: num 0.596 0.592 0.603 0.591 0.557 0.572 0.574 0.585 0.584 0.532 ...
## $ Generosity : num 0.153 0.252 0.271 0.354 0.322 0.263 0.267 0.33 0.285 0.244 ...
## $ Perceptions.of.corruption : num 0.393 0.41 0.341 0.118 0.298 0.343 0.373 0.38 0.308 0.226 ...
## $ hdi_name : chr NA NA NA NA ...
## $ join_key : chr "Finland" "Denmark" "Norway" "Iceland" ...
## $ hdi : num 0.948 0.962 0.97 0.972 0.955 0.97 0.959 0.938 0.939 0.93 ...
Berdasarkan hasil pemeriksaan awal, dataset yang digunakan terdiri atas 153 observasi dan 12 variabel. Variabel tersebut mencakup informasi peringkat negara, skor kebahagiaan, enam indikator prediktor, serta nilai HDI.
Hasil summary() menunjukkan bahwa nilai HDI memiliki rata-rata sebesar 0,7455, median sebesar 0,776, nilai minimum sebesar 0,388, dan maksimum sebesar 0,972. Hal ini menunjukkan bahwa nilai HDI pada observasi yang digunakan memiliki rentang yang cukup beragam.
Sementara itu, hasil str() menunjukkan bahwa keenam variabel prediktor dan variabel HDI memiliki tipe data numerik. Dengan demikian, variabel-variabel tersebut dapat digunakan dalam pemodelan SVR yang merupakan metode regresi untuk memprediksi respons numerik.
Setelah dataset berhasil diimpor, tahap selanjutnya adalah melakukan pemeriksaan data untuk mengetahui kondisi dan kelengkapan dataset yang akan digunakan dalam analisis. Pemeriksaan ini dilakukan untuk mengidentifikasi keberadaan missing value (data yang hilang), data duplikat, serta memastikan dimensi dan struktur dataset telah sesuai dengan kebutuhan analisis. Selain itu, dilakukan pemeriksaan terhadap nama dan tipe variabel untuk memperoleh gambaran awal mengenai karakteristik data.
Tahap ini penting dilakukan agar permasalahan pada data dapat diketahui sejak awal sehingga tidak mengganggu proses pengolahan maupun pemodelan menggunakan metode Support Vector Machine (SVM), Support Vector Regression (SVR), dan Neural Network (NN).
## Overall.rank Country.or.region
## 0 0
## Score GDP.per.capita
## 0 0
## Social.support Healthy.life.expectancy
## 0 0
## Freedom.to.make.life.choices Generosity
## 0 0
## Perceptions.of.corruption hdi_name
## 0 147
## join_key hdi
## 0 0
## [1] 0
## [1] 153 12
## 'data.frame': 153 obs. of 12 variables:
## $ Overall.rank : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Country.or.region : chr "Finland" "Denmark" "Norway" "Iceland" ...
## $ Score : num 7.77 7.6 7.55 7.49 7.49 ...
## $ GDP.per.capita : num 1.34 1.38 1.49 1.38 1.4 ...
## $ Social.support : num 1.59 1.57 1.58 1.62 1.52 ...
## $ Healthy.life.expectancy : num 0.986 0.996 1.028 1.026 0.999 ...
## $ Freedom.to.make.life.choices: num 0.596 0.592 0.603 0.591 0.557 0.572 0.574 0.585 0.584 0.532 ...
## $ Generosity : num 0.153 0.252 0.271 0.354 0.322 0.263 0.267 0.33 0.285 0.244 ...
## $ Perceptions.of.corruption : num 0.393 0.41 0.341 0.118 0.298 0.343 0.373 0.38 0.308 0.226 ...
## $ hdi_name : chr NA NA NA NA ...
## $ join_key : chr "Finland" "Denmark" "Norway" "Iceland" ...
## $ hdi : num 0.948 0.962 0.97 0.972 0.955 0.97 0.959 0.938 0.939 0.93 ...
## [1] "Overall.rank" "Country.or.region"
## [3] "Score" "GDP.per.capita"
## [5] "Social.support" "Healthy.life.expectancy"
## [7] "Freedom.to.make.life.choices" "Generosity"
## [9] "Perceptions.of.corruption" "hdi_name"
## [11] "join_key" "hdi"
## Rows: 153
## Columns: 12
## $ Overall.rank <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13…
## $ Country.or.region <chr> "Finland", "Denmark", "Norway", "Iceland"…
## $ Score <dbl> 7.769, 7.600, 7.554, 7.494, 7.488, 7.480,…
## $ GDP.per.capita <dbl> 1.340, 1.383, 1.488, 1.380, 1.396, 1.452,…
## $ Social.support <dbl> 1.587, 1.573, 1.582, 1.624, 1.522, 1.526,…
## $ Healthy.life.expectancy <dbl> 0.986, 0.996, 1.028, 1.026, 0.999, 1.052,…
## $ Freedom.to.make.life.choices <dbl> 0.596, 0.592, 0.603, 0.591, 0.557, 0.572,…
## $ Generosity <dbl> 0.153, 0.252, 0.271, 0.354, 0.322, 0.263,…
## $ Perceptions.of.corruption <dbl> 0.393, 0.410, 0.341, 0.118, 0.298, 0.343,…
## $ hdi_name <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ join_key <chr> "Finland", "Denmark", "Norway", "Iceland"…
## $ hdi <dbl> 0.948, 0.962, 0.970, 0.972, 0.955, 0.970,…
Berdasarkan pemeriksaan missing value, ditemukan bahwa variabel hdi_name memiliki 147 nilai yang hilang. Namun, variabel tersebut tidak digunakan dalam analisis SVR sehingga tidak memengaruhi proses pemodelan. Seluruh variabel yang digunakan, yaitu enam variabel prediktor dan satu variabel respons HDI, tidak memiliki missing value.
Selain itu, hasil pemeriksaan duplikasi menunjukkan bahwa tidak terdapat observasi yang terduplikasi. Dataset juga memiliki dimensi 153 baris dan 12 kolom. Setelah dilakukan pemilihan variabel untuk pemodelan, diperoleh 153 observasi dengan tujuh variabel analisis.
Dengan demikian, data yang digunakan dalam pemodelan tidak memerlukan penanganan missing value maupun penghapusan data duplikat.
Setelah dilakukan pemeriksaan data, tahap selanjutnya adalah membersihkan nama variabel agar lebih sederhana dan konsisten. Proses ini dilakukan menggunakan fungsi clean_names() dari package janitor untuk mengubah nama variabel ke dalam format snake_case, yaitu menggunakan huruf kecil dan tanda garis bawah (_) sebagai pemisah antar kata. Dengan demikian, nama variabel menjadi lebih mudah dipanggil dalam kode R tanpa mengubah isi maupun nilai data.
## [1] "overall_rank" "country_or_region"
## [3] "score" "gdp_per_capita"
## [5] "social_support" "healthy_life_expectancy"
## [7] "freedom_to_make_life_choices" "generosity"
## [9] "perceptions_of_corruption" "hdi_name"
## [11] "join_key" "hdi"
Berdasarkan hasil pembersihan, nama-nama variabel berhasil diseragamkan ke dalam format snake_case. Sebagai contoh, variabel GDP.per.capita diubah menjadi gdp_per_capita, sedangkan Social.support menjadi social_support. Dengan demikian, seluruh nama variabel menjadi lebih sederhana dan konsisten sehingga memudahkan proses pemanggilan variabel dalam analisis selanjutnya.
Perlu diperhatikan bahwa proses ini hanya mengubah format penamaan variabel dan tidak mengubah nilai maupun isi data di dalamnya.
Pada penelitian ini, variabel yang digunakan terdiri atas satu variabel respons dan enam variabel prediktor. Variabel respons merupakan variabel yang akan diprediksi oleh model Support Vector Regression (SVR), sedangkan variabel prediktor merupakan variabel yang digunakan sebagai masukan untuk membantu menjelaskan dan memprediksi nilai variabel respons.
Variabel respons yang digunakan adalah Human Development Index (HDI). Variabel ini dipilih sebagai variabel yang akan diprediksi karena menggambarkan tingkat pembangunan manusia suatu negara. Dalam pemodelan SVR, nilai HDI berperan sebagai target yang ingin diestimasi berdasarkan enam indikator prediktor.
tabel_y <- data.frame(
Kode = "Y",
Variabel = "Human Development Index (HDI)",
Keterangan = "Indeks yang menggambarkan tingkat pembangunan manusia berdasarkan dimensi kesehatan, pendidikan, dan standar hidup layak."
)
knitr::kable(
tabel_y,
caption = "Deskripsi Variabel Respons",
align = "c"
)| Kode | Variabel | Keterangan |
|---|---|---|
| Y | Human Development Index (HDI) | Indeks yang menggambarkan tingkat pembangunan manusia berdasarkan dimensi kesehatan, pendidikan, dan standar hidup layak. |
## [1] 153
## [1] 0.948 0.962 0.970 0.972 0.955 0.970
Berdasarkan hasil pemeriksaan, variabel respons HDI memiliki 153 observasi, yang menunjukkan bahwa seluruh observasi dalam dataset digunakan sebagai variabel respons. Nilai HDI memiliki rentang antara 0,388 hingga 0,972. Sementara itu, enam nilai yang ditampilkan merupakan sebagian hasil pengamatan HDI, yang menunjukkan bahwa variabel respons telah tersimpan dalam bentuk numerik dan dapat digunakan dalam pemodelan regresi. Pada tahap selanjutnya, nilai HDI juga akan dikategorikan menjadi kelas tinggi dan rendah untuk kebutuhan pemodelan klasifikasi.
Setelah menentukan variabel respons, tahap selanjutnya adalah menentukan variabel prediktor (X) yang digunakan untuk menjelaskan dan memprediksi nilai Human Development Index (HDI). Dalam penelitian ini, terdapat enam variabel prediktor yang dipilih, yaitu GDP per Capita, Social Support, Healthy Life Expectancy, Freedom to Make Life Choices, Generosity, dan Perceptions of Corruption. Keenam variabel tersebut merepresentasikan berbagai aspek sosial dan ekonomi yang diduga berkaitan dengan tingkat pembangunan manusia. Variabel-variabel ini kemudian digunakan sebagai input dalam proses pemodelan SVM, SVR, dan Neural Network.
# Tabel variabel prediktor
tabel_x <- data.frame(
Kode = paste0("X", 1:6),
Variabel = c(
"GDP per Capita",
"Social Support",
"Healthy Life Expectancy",
"Freedom to Make Life Choices",
"Generosity",
"Perceptions of Corruption"
),
Keterangan = c(
"Menggambarkan tingkat pendapatan atau aktivitas ekonomi per kapita.",
"Menggambarkan dukungan sosial yang dirasakan individu.",
"Menggambarkan perkiraan harapan hidup sehat masyarakat.",
"Menggambarkan kebebasan individu dalam menentukan pilihan hidup.",
"Menggambarkan kecenderungan perilaku kedermawanan atau kepedulian terhadap orang lain.",
"Menggambarkan persepsi masyarakat terhadap tingkat korupsi dalam pemerintahan dan institusi."
)
)
knitr::kable(
tabel_x,
caption = "Deskripsi Variabel Prediktor",
align = c("c", "l", "l")
)| Kode | Variabel | Keterangan |
|---|---|---|
| X1 | GDP per Capita | Menggambarkan tingkat pendapatan atau aktivitas ekonomi per kapita. |
| X2 | Social Support | Menggambarkan dukungan sosial yang dirasakan individu. |
| X3 | Healthy Life Expectancy | Menggambarkan perkiraan harapan hidup sehat masyarakat. |
| X4 | Freedom to Make Life Choices | Menggambarkan kebebasan individu dalam menentukan pilihan hidup. |
| X5 | Generosity | Menggambarkan kecenderungan perilaku kedermawanan atau kepedulian terhadap orang lain. |
| X6 | Perceptions of Corruption | Menggambarkan persepsi masyarakat terhadap tingkat korupsi dalam pemerintahan dan institusi. |
Keenam variabel prediktor tersebut digunakan untuk menggambarkan berbagai aspek ekonomi, sosial, kesehatan, dan tata kelola yang berpotensi berkaitan dengan tingkat pembangunan manusia. Seluruh variabel prediktor digunakan secara bersamaan sebagai masukan dalam model SVR untuk memprediksi nilai HDI.
X <- data[, c(
"gdp_per_capita",
"social_support",
"healthy_life_expectancy",
"freedom_to_make_life_choices",
"generosity",
"perceptions_of_corruption"
)]
dim(X)## [1] 153 6
## gdp_per_capita social_support healthy_life_expectancy
## 1 1.340 1.587 0.986
## 2 1.383 1.573 0.996
## 3 1.488 1.582 1.028
## 4 1.380 1.624 1.026
## 5 1.396 1.522 0.999
## 6 1.452 1.526 1.052
## freedom_to_make_life_choices generosity perceptions_of_corruption
## 1 0.596 0.153 0.393
## 2 0.592 0.252 0.410
## 3 0.603 0.271 0.341
## 4 0.591 0.354 0.118
## 5 0.557 0.322 0.298
## 6 0.572 0.263 0.343
## gdp_per_capita social_support healthy_life_expectancy
## 1 1.340 1.587 0.986
## 2 1.383 1.573 0.996
## 3 1.488 1.582 1.028
## 4 1.380 1.624 1.026
## 5 1.396 1.522 0.999
## 6 1.452 1.526 1.052
## freedom_to_make_life_choices generosity perceptions_of_corruption hdi
## 1 0.596 0.153 0.393 0.948
## 2 0.592 0.252 0.410 0.962
## 3 0.603 0.271 0.341 0.970
## 4 0.591 0.354 0.118 0.972
## 5 0.557 0.322 0.298 0.955
## 6 0.572 0.263 0.343 0.970
## [1] 153 7
## 'data.frame': 153 obs. of 7 variables:
## $ gdp_per_capita : num 1.34 1.38 1.49 1.38 1.4 ...
## $ social_support : num 1.59 1.57 1.58 1.62 1.52 ...
## $ healthy_life_expectancy : num 0.986 0.996 1.028 1.026 0.999 ...
## $ freedom_to_make_life_choices: num 0.596 0.592 0.603 0.591 0.557 0.572 0.574 0.585 0.584 0.532 ...
## $ generosity : num 0.153 0.252 0.271 0.354 0.322 0.263 0.267 0.33 0.285 0.244 ...
## $ perceptions_of_corruption : num 0.393 0.41 0.341 0.118 0.298 0.343 0.373 0.38 0.308 0.226 ...
## $ hdi : num 0.948 0.962 0.97 0.972 0.955 0.97 0.959 0.938 0.939 0.93 ...
Pada penelitian ini, variabel respons yang digunakan adalah HDI (hdi), sedangkan variabel prediktor terdiri atas enam indikator dari World Happiness, yaitu GDP per capita, Social support, Healthy life expectancy, Freedom to make life choices, Generosity, dan Perceptions of corruption.
Pemilihan HDI sebagai variabel respons didasarkan pada tujuan analisis, yaitu membangun model yang dapat memprediksi nilai HDI berdasarkan indikator-indikator tersebut. Keenam prediktor digunakan secara bersamaan untuk menangkap informasi yang berpotensi berkaitan dengan variasi nilai HDI.
Selanjutnya, seluruh variabel digabungkan ke dalam satu dataset analisis yang terdiri atas 153 observasi dan tujuh variabel.
## gdp_per_capita social_support
## TRUE TRUE
## healthy_life_expectancy freedom_to_make_life_choices
## TRUE TRUE
## generosity perceptions_of_corruption
## TRUE TRUE
## hdi
## TRUE
## gdp_per_capita social_support
## 0 0
## healthy_life_expectancy freedom_to_make_life_choices
## 0 0
## generosity perceptions_of_corruption
## 0 0
## hdi
## 0
## gdp_per_capita social_support
## 0 0
## healthy_life_expectancy freedom_to_make_life_choices
## 0 0
## generosity perceptions_of_corruption
## 0 0
## hdi
## 0
## [1] 0
# Menghapus observasi yang memiliki missing value
data_svr <- data_svr[
complete.cases(data_svr),
]
# Memeriksa kembali missing value
colSums(is.na(data_svr))## gdp_per_capita social_support
## 0 0
## healthy_life_expectancy freedom_to_make_life_choices
## 0 0
## generosity perceptions_of_corruption
## 0 0
## hdi
## 0
## [1] 153 7
Berdasarkan hasil pemeriksaan tipe data, seluruh variabel yang digunakan dalam analisis memiliki tipe numerik. Hal ini sesuai dengan kebutuhan metode SVR karena variabel respons yang diprediksi berupa data kontinu.
Hasil pemeriksaan lanjutan juga menunjukkan bahwa tidak terdapat missing value pada ketujuh variabel analisis. Oleh karena itu, seluruh 153 observasi dapat dipertahankan dan digunakan dalam tahapan analisis selanjutnya tanpa perlu melakukan imputasi atau penghapusan observasi.
## gdp_per_capita social_support healthy_life_expectancy
## Min. :0.0000 Min. :0.000 Min. :0.0000
## 1st Qu.:0.5780 1st Qu.:1.055 1st Qu.:0.5380
## Median :0.9600 Median :1.274 Median :0.7890
## Mean :0.8999 Mean :1.207 Mean :0.7217
## 3rd Qu.:1.2210 3rd Qu.:1.454 3rd Qu.:0.8810
## Max. :1.6840 Max. :1.624 Max. :1.1410
## freedom_to_make_life_choices generosity perceptions_of_corruption
## Min. :0.0000 Min. :0.0000 Min. :0.000
## 1st Qu.:0.3050 1st Qu.:0.1080 1st Qu.:0.047
## Median :0.4170 Median :0.1770 Median :0.085
## Mean :0.3921 Mean :0.1839 Mean :0.111
## 3rd Qu.:0.5080 3rd Qu.:0.2470 3rd Qu.:0.141
## Max. :0.6310 Max. :0.5660 Max. :0.453
## hdi
## Min. :0.3880
## 1st Qu.:0.6170
## Median :0.7760
## Mean :0.7455
## 3rd Qu.:0.8890
## Max. :0.9720
# Statistik deskriptif
stat_deskriptif <- data.frame(
Variabel = names(data_svr),
Mean = sapply(data_svr, mean),
Median = sapply(data_svr, median),
SD = sapply(data_svr, sd),
Minimum = sapply(data_svr, min),
Maksimum = sapply(data_svr, max)
)
# Membulatkan hasil
stat_deskriptif[, -1] <- round(
stat_deskriptif[, -1],
4
)
# Menampilkan tabel
kable(
stat_deskriptif,
caption = "Statistik Deskriptif Variabel Penelitian"
)| Variabel | Mean | Median | SD | Minimum | Maksimum | |
|---|---|---|---|---|---|---|
| gdp_per_capita | gdp_per_capita | 0.8999 | 0.960 | 0.3995 | 0.000 | 1.684 |
| social_support | social_support | 1.2069 | 1.274 | 0.3016 | 0.000 | 1.624 |
| healthy_life_expectancy | healthy_life_expectancy | 0.7217 | 0.789 | 0.2426 | 0.000 | 1.141 |
| freedom_to_make_life_choices | freedom_to_make_life_choices | 0.3921 | 0.417 | 0.1444 | 0.000 | 0.631 |
| generosity | generosity | 0.1839 | 0.177 | 0.0959 | 0.000 | 0.566 |
| perceptions_of_corruption | perceptions_of_corruption | 0.1110 | 0.085 | 0.0950 | 0.000 | 0.453 |
| hdi | hdi | 0.7455 | 0.776 | 0.1596 | 0.388 | 0.972 |
Secara keseluruhan, nilai rata-rata dan median pada beberapa variabel memiliki perbedaan yang relatif kecil. Namun, pada variabel tertentu, seperti GDP per capita, terdapat perbedaan antara rata-rata sebesar 0,8999 dan median sebesar 0,9600. Hal ini memberikan gambaran bahwa distribusi data tidak selalu simetris.
Nilai standar deviasi juga menunjukkan tingkat keragaman masing-masing variabel. Semakin besar standar deviasi, semakin besar variasi data terhadap nilai rata-ratanya. Pada data ini, GDP per capita memiliki standar deviasi sebesar 0,3995, sedangkan Generosity memiliki standar deviasi sebesar 0,0959.
par(mfrow = c(2, 4))
for (i in 1:ncol(data_svr)) {
hist(
data_svr[[i]],
main = names(data_svr)[i],
xlab = names(data_svr)[i],
col = "skyblue",
border = "white"
)
}
par(mfrow = c(1, 1))GDP per Capita Sebagian besar data terkonsentrasi pada nilai 0,8–1,4. Distribusi cenderung mengarah ke nilai yang lebih tinggi.
Social Support Data didominasi oleh nilai 1,0–1,5, dengan frekuensi tertinggi pada rentang 1,3–1,5. Hal ini menunjukkan bahwa sebagian besar negara memiliki tingkat dukungan sosial yang relatif tinggi.
Healthy Life Expectancy Sebagian besar data terkonsentrasi pada rentang 0,7–1,0, dengan puncak frekuensi sekitar 0,8–0,9. Artinya, nilai harapan hidup sehat relatif banyak berada pada rentang tersebut.
Freedom to Make Life Choices Distribusi data terkonsentrasi pada rentang 0,3–0,6, dengan frekuensi tertinggi sekitar 0,4–0,5. Hal ini menunjukkan bahwa sebagian besar negara memiliki nilai kebebasan memilih pada rentang tersebut.
Generosity Sebagian besar data berada pada rentang 0,1–0,3, sedangkan nilai di atas 0,4 relatif jarang ditemukan. Distribusi cenderung menceng ke kanan (right-skewed).
Perceptions of Corruption Data didominasi oleh nilai rendah, terutama pada rentang 0,0–0,2. Distribusi menceng ke kanan karena hanya sedikit pengamatan yang memiliki nilai relatif tinggi.
HDI Sebagian besar nilai HDI terkonsentrasi pada rentang 0,7–1,0, dengan frekuensi tertinggi sekitar 0,9–1,0. Hal ini menunjukkan bahwa sebagian besar negara dalam dataset memiliki nilai HDI yang relatif tinggi.
par(mfrow = c(2, 4))
for (i in 1:ncol(data_svr)) {
boxplot(
data_svr[[i]],
main = names(data_svr)[i],
ylab = "Nilai",
col = "lightgreen"
)
}
par(mfrow = c(1, 1))GDP per capita Tidak terdapat outlier karena seluruh data masih berada dalam batas whisker boxplot.
Social support Terdapat beberapa outlier pada bagian bawah, yang menunjukkan adanya data dengan nilai social support lebih rendah dibandingkan sebagian besar pengamatan lainnya.
Healthy life expectancy Terdapat satu outlier pada bagian bawah, yang menunjukkan adanya data dengan nilai harapan hidup sehat lebih rendah dibandingkan pengamatan lainnya.
Freedom to make life choices Terdapat satu outlier pada bagian bawah, yang menunjukkan adanya data dengan tingkat kebebasan dalam menentukan pilihan hidup lebih rendah dibandingkan sebagian besar data.
Generosity Terdapat dua outlier pada bagian atas, yang menunjukkan adanya data dengan tingkat generosity lebih tinggi dibandingkan pengamatan lainnya.
Perceptions of corruption Terdapat beberapa outlier pada bagian atas, yang menunjukkan adanya data dengan nilai perceptions of corruption lebih tinggi dibandingkan sebagian besar pengamatan lainnya.
HDI Tidak terdapat outlier karena seluruh data masih berada dalam batas whisker boxplot.
cor_matrix <- cor(
data_svr,
method = "pearson",
use = "complete.obs"
)
# Menampilkan matriks korelasi
round(cor_matrix, 3)## gdp_per_capita social_support
## gdp_per_capita 1.000 0.755
## social_support 0.755 1.000
## healthy_life_expectancy 0.834 0.721
## freedom_to_make_life_choices 0.384 0.450
## generosity -0.085 -0.052
## perceptions_of_corruption 0.300 0.184
## hdi 0.948 0.771
## healthy_life_expectancy
## gdp_per_capita 0.834
## social_support 0.721
## healthy_life_expectancy 1.000
## freedom_to_make_life_choices 0.394
## generosity -0.034
## perceptions_of_corruption 0.296
## hdi 0.903
## freedom_to_make_life_choices generosity
## gdp_per_capita 0.384 -0.085
## social_support 0.450 -0.052
## healthy_life_expectancy 0.394 -0.034
## freedom_to_make_life_choices 1.000 0.269
## generosity 0.269 1.000
## perceptions_of_corruption 0.446 0.335
## hdi 0.396 -0.083
## perceptions_of_corruption hdi
## gdp_per_capita 0.300 0.948
## social_support 0.184 0.771
## healthy_life_expectancy 0.296 0.903
## freedom_to_make_life_choices 0.446 0.396
## generosity 0.335 -0.083
## perceptions_of_corruption 1.000 0.287
## hdi 0.287 1.000
# Visualisasi
library(corrplot)
corrplot(
cor_matrix,
method = "color",
type = "upper",
addCoef.col = "black",
tl.col = "black",
tl.srt = 45,
number.cex = 0.7
)GDP per capita Memiliki korelasi positif kuat dengan social support (0,76), healthy life expectancy (0,83), dan HDI (0,95). Artinya, semakin tinggi GDP per capita, cenderung semakin tinggi pula nilai ketiga variabel tersebut.
Social support Memiliki korelasi positif kuat dengan healthy life expectancy (0,72) dan HDI (0,77). Artinya, semakin tinggi social support, cenderung semakin tinggi pula healthy life expectancy dan HDI.
Healthy life expectancy Memiliki korelasi positif kuat dengan HDI (0,90). Artinya, semakin tinggi healthy life expectancy, cenderung semakin tinggi pula HDI.
Freedom to make life choices Memiliki korelasi positif sedang dengan perceptions of corruption (0,45), HDI (0,40), dan healthy life expectancy (0,39).
Generosity Memiliki korelasi yang cenderung lemah dengan variabel lainnya. Korelasi tertinggi terdapat pada perceptions of corruption, yaitu sebesar 0,34.
Perceptions of corruption Memiliki korelasi positif sedang dengan freedom to make life choices (0,45), serta korelasi positif lemah dengan variabel lainnya.
HDI Memiliki korelasi positif kuat dengan GDP per capita (0,95), healthy life expectancy (0,90), dan social support (0,77).
Sebagian besar variabel memiliki hubungan positif, artinya peningkatan suatu variabel cenderung diikuti peningkatan variabel lainnya. Korelasi paling kuat terdapat antara GDP per capita dan HDI sebesar 0,95. Sementara itu, korelasi negatif terlihat pada generosity dengan beberapa variabel, tetapi nilainya relatif lemah.
par(mfrow = c(2, 3))
for (i in 1:ncol(X)) {
plot(
X[[i]],
Y,
main = paste(names(X)[i], "vs HDI"),
xlab = names(X)[i],
ylab = "HDI",
pch = 19,
col = "steelblue"
)
# Menambahkan garis regresi linear
abline(
lm(Y ~ X[[i]]),
col = "red",
lwd = 2
)
}GDP per capita vs HDI Terlihat hubungan positif yang kuat. Semakin tinggi GDP per capita, cenderung semakin tinggi pula HDI. Hal ini terlihat dari pola titik yang mengikuti arah garis regresi ke atas.
Social support vs HDI Terlihat hubungan positif yang cukup kuat. Semakin tinggi social support, cenderung semakin tinggi pula HDI, meskipun titik data masih cukup menyebar.
Healthy life expectancy vs HDI Terlihat hubungan positif yang kuat. Semakin tinggi healthy life expectancy, cenderung semakin tinggi pula HDI. Pola titik data cukup mengikuti garis regresi.
Freedom to make life choices vs HDI Terlihat hubungan positif, tetapi cenderung lemah hingga sedang. Titik data cukup menyebar, sehingga hubungan antara kedua variabel tidak terlalu kuat.
Generosity vs HDI Terlihat hubungan negatif yang sangat lemah. Hal ini ditunjukkan oleh garis regresi yang sedikit menurun, sehingga peningkatan generosity tidak menunjukkan hubungan yang kuat dengan HDI.
Perceptions of corruption vs HDI Terlihat hubungan positif yang lemah. Meskipun garis regresi menunjukkan arah positif, titik data cukup menyebar dan tidak membentuk pola hubungan yang kuat.
Hubungan positif paling kuat terlihat pada GDP per capita dan healthy life expectancy terhadap HDI. Sementara itu, generosity menunjukkan hubungan negatif yang sangat lemah dengan HDI.
Pada tahap ini, data dipersiapkan untuk keperluan klasifikasi menggunakan metode Support Vector Machine (SVM). Variabel HDI yang awalnya berbentuk numerik akan diubah menjadi dua kategori, yaitu HDI tinggi dan HDI rendah. Selain itu, dipilih enam variabel prediktor yang akan digunakan untuk membantu proses klasifikasi.
Variabel HDI dikelompokkan menjadi dua kategori berdasarkan nilai 0,700. Negara dengan nilai HDI lebih besar atau sama dengan 0,700 dikategorikan sebagai HDI tinggi, sedangkan negara dengan nilai di bawah 0,700 dikategorikan sebagai HDI rendah. Pengelompokan ini dilakukan karena SVM yang digunakan pada tahap ini bertujuan untuk mengklasifikasikan negara ke dalam dua kelompok tersebut.
# Membentuk dataset khusus SVM Classification
data_svm <- data_svr %>%
dplyr::select(
hdi,
GDP = gdp_per_capita,
SocialSupport = social_support,
HealthyLife = healthy_life_expectancy,
Freedom = freedom_to_make_life_choices,
Generosity = generosity,
Corruption = perceptions_of_corruption
) %>%
tidyr::drop_na() %>%
dplyr::mutate(
hdi_class = factor(
dplyr::if_else(hdi >= 0.700, "Tinggi", "Rendah"),
levels = c("Tinggi", "Rendah")
)
)
# Melihat struktur data
str(data_svm)## 'data.frame': 153 obs. of 8 variables:
## $ hdi : num 0.948 0.962 0.97 0.972 0.955 0.97 0.959 0.938 0.939 0.93 ...
## $ GDP : num 1.34 1.38 1.49 1.38 1.4 ...
## $ SocialSupport: num 1.59 1.57 1.58 1.62 1.52 ...
## $ HealthyLife : num 0.986 0.996 1.028 1.026 0.999 ...
## $ Freedom : num 0.596 0.592 0.603 0.591 0.557 0.572 0.574 0.585 0.584 0.532 ...
## $ Generosity : num 0.153 0.252 0.271 0.354 0.322 0.263 0.267 0.33 0.285 0.244 ...
## $ Corruption : num 0.393 0.41 0.341 0.118 0.298 0.343 0.373 0.38 0.308 0.226 ...
## $ hdi_class : Factor w/ 2 levels "Tinggi","Rendah": 1 1 1 1 1 1 1 1 1 1 ...
## hdi GDP SocialSupport HealthyLife Freedom Generosity Corruption hdi_class
## 1 0.948 1.340 1.587 0.986 0.596 0.153 0.393 Tinggi
## 2 0.962 1.383 1.573 0.996 0.592 0.252 0.410 Tinggi
## 3 0.970 1.488 1.582 1.028 0.603 0.271 0.341 Tinggi
## 4 0.972 1.380 1.624 1.026 0.591 0.354 0.118 Tinggi
## 5 0.955 1.396 1.522 0.999 0.557 0.322 0.298 Tinggi
## 6 0.970 1.452 1.526 1.052 0.572 0.263 0.343 Tinggi
## [1] 153 8
# Distribusi kelas HDI
distribusi_hdi <- data_svm %>%
dplyr::count(hdi_class) %>%
dplyr::mutate(
Persentase = round(n / sum(n) * 100, 2)
)
knitr::kable(
distribusi_hdi,
caption = "Distribusi Kategori Human Development Index",
col.names = c("Kategori HDI", "Jumlah", "Persentase (%)"),
digits = 2
)| Kategori HDI | Jumlah | Persentase (%) |
|---|---|---|
| Tinggi | 99 | 64.71 |
| Rendah | 54 | 35.29 |
# Visualisasi distribusi kelas HDI
ggplot(data_svm, aes(x = hdi_class, fill = hdi_class)) +
geom_bar(width = 0.6, alpha = 0.85) +
geom_text(
stat = "count",
aes(label = after_stat(count)),
vjust = -0.5,
size = 5
) +
scale_fill_manual(
values = c(
"Tinggi" = "#E8B94F",
"Rendah" = "#B9A6D3"
)
) +
labs(
title = "Distribusi Kategori HDI",
subtitle = "Jumlah negara berdasarkan kategori HDI",
x = "Kategori HDI",
y = "Jumlah Negara",
fill = "Kategori"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
legend.position = "none"
)
Visualisasi distribusi dilakukan untuk mengetahui jumlah negara yang
termasuk dalam kategori HDI tinggi dan HDI rendah. Hasilnya menunjukkan
bahwa terdapat 99 negara (64,71%) dengan kategori HDI tinggi dan 54
negara (35,29%) dengan kategori HDI rendah. Dengan demikian, jumlah
negara pada kategori HDI tinggi lebih banyak dibandingkan kategori HDI
rendah.
ggplot(
data_svm,
aes(
x = GDP,
y = HealthyLife,
color = hdi_class
)
) +
geom_point(size = 3, alpha = 0.8) +
scale_color_manual(
values = c(
"Tinggi" = "#D9A441",
"Rendah" = "#9277B5"
)
) +
labs(
title = "Hubungan GDP per Capita dan Healthy Life Expectancy",
subtitle = "Berdasarkan kategori Human Development Index",
x = "GDP per Capita",
y = "Healthy Life Expectancy",
color = "Kategori HDI"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
legend.position = "bottom"
)
Berdasarkan scatter plot, terlihat bahwa terdapat hubungan positif
antara GDP per Capita dan Healthy Life Expectancy. Artinya, semakin
tinggi GDP per Capita suatu negara, cenderung semakin tinggi pula angka
harapan hidup sehatnya. Selain itu, negara dengan kategori HDI tinggi
(warna oranye) cenderung mengelompok pada nilai GDP per Capita dan
Healthy Life Expectancy yang lebih tinggi. Sementara itu, negara dengan
kategori HDI rendah (warna ungu) lebih banyak berada pada nilai yang
lebih rendah. Hal ini menunjukkan bahwa GDP per Capita dan Healthy Life
Expectancy memiliki pola hubungan yang searah dengan kategori HDI.
Data dibagi menjadi dua bagian, yaitu 80% data training dan 20% data testing. Data training digunakan untuk membentuk model SVM, sedangkan data testing digunakan untuk menguji kemampuan model dalam mengklasifikasikan data yang belum pernah dipelajari sebelumnya.
Pembagian dilakukan menggunakan metode stratified sampling agar proporsi kategori HDI tinggi dan rendah tetap terjaga pada kedua kelompok data. Berdasarkan hasil pembagian, diperoleh 122 observasi untuk data training dan 31 observasi untuk data testing.
set.seed(123)
# Pembagian data training dan testing
split_svm <- rsample::initial_split(
data_svm,
prop = 0.80,
strata = hdi_class
)
# Data training
train_raw <- rsample::training(split_svm)
# Data testing
test_raw <- rsample::testing(split_svm)
# Melihat ukuran data
cat("Jumlah data training:", nrow(train_raw), "\n")## Jumlah data training: 122
## Jumlah data testing: 31
##
## Tinggi Rendah
## 79 43
##
## Tinggi Rendah
## 20 11
Standardisasi dilakukan agar semua variabel prediktor memiliki skala yang sama sehingga tidak ada variabel yang lebih dominan karena perbedaan skala. Proses ini menggunakan metode Z-score berdasarkan rata-rata dan standar deviasi data training. Nilai tersebut juga digunakan pada data testing agar tidak terjadi data leakage.
# Daftar prediktor
predictors <- c(
"GDP",
"SocialSupport",
"HealthyLife",
"Freedom",
"Generosity",
"Corruption"
)
# Menghitung mean dan standar deviasi dari training
mean_train <- sapply(
train_raw[, predictors],
mean,
na.rm = TRUE
)
sd_train <- sapply(
train_raw[, predictors],
sd,
na.rm = TRUE
)
# Menghindari standar deviasi nol
sd_train[sd_train == 0 | is.na(sd_train)] <- 1
# Fungsi standardisasi
standardize_data <- function(data, mean_values, sd_values) {
data_scaled <- data
data_scaled[, predictors] <- scale(
data[, predictors],
center = mean_values,
scale = sd_values
)
return(data_scaled)
}
# Standardisasi training dan testing
train_scaled <- standardize_data(
train_raw,
mean_train,
sd_train
)
test_scaled <- standardize_data(
test_raw,
mean_train,
sd_train
)
# Melihat hasil standardisasi
head(train_scaled)## hdi GDP SocialSupport HealthyLife Freedom Generosity Corruption
## 1 0.645 -0.6707165 0.1026268 0.43385439 0.85379282 0.72873368 -0.30285599
## 2 0.544 -0.5816215 -1.0244735 -0.75609106 -0.43585990 0.44395565 -0.07435611
## 3 0.691 -1.0500067 -0.3417727 -0.01288281 0.06936488 0.55348566 0.45119362
## 4 0.698 -0.2354237 0.3763512 -0.47586500 0.52140810 2.08690579 0.71396848
## 5 0.588 -0.9074547 -0.9471867 -1.58458550 0.01618332 0.08250662 -0.77128075
## 6 0.628 -0.7496292 -1.0824387 -0.95509217 0.01618332 0.71778067 -0.73700576
## hdi_class
## 1 Rendah
## 2 Rendah
## 3 Rendah
## 4 Rendah
## 5 Rendah
## 6 Rendah
Pada tahap ini, model SVM dibentuk menggunakan tiga jenis kernel, yaitu Linear, Polynomial, dan Radial Basis Function (RBF). Penggunaan beberapa kernel bertujuan untuk melihat jenis kernel yang paling sesuai dalam memisahkan data ke dalam kategori HDI tinggi dan HDI rendah.
# Fungsi untuk membangun model SVM
fit_svm <- function(
train_data,
predictors_used,
kernel_type,
cost_value = 1,
degree_value = 2,
gamma_value = 1
) {
x_train <- as.matrix(
train_data[, predictors_used]
)
y_train <- train_data$hdi_class
# Menentukan kernel
if (kernel_type == "Linear") {
kernel_function <- kernlab::vanilladot()
} else if (kernel_type == "Polynomial") {
kernel_function <- kernlab::polydot(
degree = degree_value,
scale = 1,
offset = 1
)
} else if (kernel_type == "RBF") {
kernel_function <- kernlab::rbfdot(
sigma = gamma_value
)
}
# Membentuk model SVM
model <- kernlab::ksvm(
x = x_train,
y = y_train,
type = "C-svc",
kernel = kernel_function,
C = cost_value,
prob.model = TRUE,
scaled = FALSE
)
return(model)
}Kernel Linear digunakan untuk membentuk batas pemisah antarkelas dalam bentuk garis lurus atau bidang linear. Kernel ini sesuai digunakan ketika hubungan antarvariabel dan kelas dapat dipisahkan secara linear.
svm_linear <- fit_svm(
train_scaled,
predictors,
kernel_type = "Linear",
cost_value = 1
)
svm_linear## Support Vector Machine object of class "ksvm"
##
## SV type: C-svc (classification)
## parameter : cost C = 1
##
## Linear (vanilla) kernel function.
##
## Number of Support Vectors : 16
##
## Objective Function Value : -10.2229
## Training error : 0.032787
## Probability model included.
Kernel Polynomial digunakan untuk membentuk batas pemisah yang lebih fleksibel dengan mempertimbangkan hubungan nonlinier antarvariabel. Pada pemodelan ini digunakan nilai degree sebesar 2, yang menunjukkan tingkat pangkat dalam fungsi kernel polynomial.
svm_poly <- fit_svm(
train_scaled,
predictors,
kernel_type = "Polynomial",
cost_value = 1,
degree_value = 2
)
svm_poly## Support Vector Machine object of class "ksvm"
##
## SV type: C-svc (classification)
## parameter : cost C = 1
##
## Polynomial kernel function.
## Hyperparameters : degree = 2 scale = 1 offset = 1
##
## Number of Support Vectors : 17
##
## Objective Function Value : -4.8116
## Training error : 0.008197
## Probability model included.
Kernel RBF (Radial Basis Function) digunakan untuk menangani hubungan nonlinier dengan membentuk batas pemisah yang lebih fleksibel. Kernel ini memanfaatkan parameter gamma untuk mengatur seberapa jauh pengaruh suatu observasi terhadap observasi lainnya.
svm_rbf <- fit_svm(
train_scaled,
predictors,
kernel_type = "RBF",
cost_value = 1,
gamma_value = 1
)
svm_rbf## Support Vector Machine object of class "ksvm"
##
## SV type: C-svc (classification)
## parameter : cost C = 1
##
## Gaussian Radial Basis kernel function.
## Hyperparameter : sigma = 1
##
## Number of Support Vectors : 96
##
## Objective Function Value : -26.9863
## Training error : 0.008197
## Probability model included.
# Fungsi mengambil probabilitas kelas Tinggi
get_probability <- function(model, new_data) {
probability <- predict(
model,
as.matrix(new_data),
type = "probabilities"
)
probability <- as.matrix(probability)
return(probability[, "Tinggi"])
}
# Fungsi evaluasi model
evaluate_svm <- function(model, test_data, predictors_used) {
# Prediksi kelas
prediction <- predict(
model,
as.matrix(test_data[, predictors_used]),
type = "response"
)
prediction <- factor(
prediction,
levels = levels(test_data$hdi_class)
)
# Prediksi probabilitas kelas Tinggi
probability <- get_probability(
model,
test_data[, predictors_used]
)
# Menghitung metrik evaluasi
hasil <- tibble::tibble(
Accuracy = yardstick::accuracy_vec(
truth = test_data$hdi_class,
estimate = prediction
),
AUC = yardstick::roc_auc_vec(
truth = test_data$hdi_class,
estimate = probability,
event_level = "first"
),
Sensitivity = yardstick::sens_vec(
truth = test_data$hdi_class,
estimate = prediction,
event_level = "first"
),
Specificity = yardstick::spec_vec(
truth = test_data$hdi_class,
estimate = prediction,
event_level = "first"
),
Precision = yardstick::precision_vec(
truth = test_data$hdi_class,
estimate = prediction,
event_level = "first"
),
F1_Score = yardstick::f_meas_vec(
truth = test_data$hdi_class,
estimate = prediction,
event_level = "first"
)
)
return(hasil)
}
# Evaluasi ketiga model
hasil_linear <- evaluate_svm(
svm_linear,
test_scaled,
predictors
)
hasil_poly <- evaluate_svm(
svm_poly,
test_scaled,
predictors
)
hasil_rbf <- evaluate_svm(
svm_rbf,
test_scaled,
predictors
)
# Menggabungkan hasil evaluasi
hasil_baseline <- dplyr::bind_rows(
Linear = hasil_linear,
Polynomial = hasil_poly,
RBF = hasil_rbf,
.id = "Kernel"
)
knitr::kable(
hasil_baseline,
digits = 4,
caption = "Perbandingan Performa Awal SVM Berdasarkan Kernel"
)| Kernel | Accuracy | AUC | Sensitivity | Specificity | Precision | F1_Score |
|---|---|---|---|---|---|---|
| Linear | 0.8710 | 0.9591 | 0.90 | 0.8182 | 0.9000 | 0.9000 |
| Polynomial | 0.8065 | 0.8682 | 0.85 | 0.7273 | 0.8500 | 0.8500 |
| RBF | 0.8065 | 0.8727 | 0.95 | 0.5455 | 0.7917 | 0.8636 |
Hasil evaluasi awal menunjukkan bahwa ketiga model memiliki nilai Accuracy yang cukup baik, dengan model Linear memiliki nilai accuracy tertinggi yaitu 0.8710, disusul oleh model polynomial dan RBF yang memiliki accuracy sama yaitu 0.8065.
Pada tahap ini dilakukan pencarian kombinasi parameter terbaik dari masing-masing kernel menggunakan metode 5-Fold dan 10-Fold Cross Validation. Proses ini bertujuan untuk memperoleh kombinasi parameter yang memberikan performa model paling baik dan stabil.
Parameter yang diuji meliputi:
Cost (C): Mengatur seberapa besar penalti terhadap kesalahan klasifikasi. Nilai C yang lebih besar memberikan penalti lebih tinggi terhadap kesalahan.
Degree: Menentukan tingkat pangkat pada kernel Polynomial.
Gamma: Mengatur jangkauan pengaruh setiap observasi pada kernel RBF.
Pengujian dilakukan menggunakan beberapa kombinasi parameter yang telah ditentukan. Setiap kombinasi dievaluasi melalui lima pembagian data, kemudian hasil Accuracy dan AUC dirata-ratakan untuk menentukan kombinasi terbaik.
# Fungsi Cross-Validation SVM
cv_svm <- function(
data,
predictors_used,
kernel_type,
cost_value,
degree_value = 2,
gamma_value = 0.1,
k = 5,
seed = 2026
) {
set.seed(seed)
# Membuat fold secara stratified
folds <- caret::createFolds(
y = data$hdi_class,
k = k,
list = TRUE
)
# Menyiapkan penyimpanan hasil
hasil_fold <- data.frame(
Accuracy = numeric(length(folds)),
AUC = numeric(length(folds))
)
# Proses setiap fold
for (i in seq_along(folds)) {
# Membagi data training dan validasi
index_valid <- folds[[i]]
fold_train <- data[-index_valid, ]
fold_valid <- data[index_valid, ]
# Standardisasi berdasarkan training fold
scaled <- scale_fold(
train_data = fold_train,
valid_data = fold_valid,
predictors_used = predictors_used
)
# Membentuk kernel
kernel_function <- make_kernel(
kernel_type = kernel_type,
degree_value = degree_value,
gamma_value = gamma_value
)
# Membentuk model SVM
model <- kernlab::ksvm(
x = as.matrix(
scaled$train[, predictors_used]
),
y = scaled$train$hdi_class,
type = "C-svc",
kernel = kernel_function,
C = cost_value,
prob.model = TRUE,
scaled = FALSE
)
# Prediksi kelas
pred <- predict(
model,
as.matrix(
scaled$valid[, predictors_used]
),
type = "response"
)
pred <- factor(
pred,
levels = levels(scaled$valid$hdi_class)
)
# Prediksi probabilitas kelas Tinggi
prob <- predict(
model,
as.matrix(
scaled$valid[, predictors_used]
),
type = "probabilities"
)
prob <- as.matrix(prob)
prob_tinggi <- prob[, "Tinggi"]
# Menghitung Accuracy
hasil_fold$Accuracy[i] <- yardstick::accuracy_vec(
truth = scaled$valid$hdi_class,
estimate = pred
)
# Menghitung AUC
hasil_fold$AUC[i] <- yardstick::roc_auc_vec(
truth = scaled$valid$hdi_class,
estimate = prob_tinggi,
event_level = "first"
)
}
# Menghitung rata-rata dan standar deviasi
hasil <- data.frame(
Mean_Accuracy = mean(hasil_fold$Accuracy),
SD_Accuracy = sd(hasil_fold$Accuracy),
Mean_AUC = mean(hasil_fold$AUC),
SD_AUC = sd(hasil_fold$AUC)
)
return(hasil)
}
# ============================================================
# MENENTUKAN GRID HYPERPARAMETER SVM
# ============================================================
# Kernel Linear
grid_linear <- expand.grid(
Kernel = "Linear",
C = c(0.01, 0.1, 1, 10, 100),
Degree = NA_real_,
Gamma = NA_real_
)
# Kernel Polynomial
grid_poly <- expand.grid(
Kernel = "Polynomial",
C = c(0.1, 1, 10),
Degree = c(2, 3),
Gamma = NA_real_
)
# Kernel RBF
grid_rbf <- expand.grid(
Kernel = "RBF",
C = c(0.1, 1, 10),
Degree = NA_real_,
Gamma = c(0.01, 0.1, 1)
)
# Fungsi untuk menentukan jenis kernel SVM
make_kernel <- function(
kernel_type,
degree_value = 2,
gamma_value = 0.1
) {
if (kernel_type == "Linear") {
kernel <- kernlab::vanilladot()
} else if (kernel_type == "Polynomial") {
kernel <- kernlab::polydot(
degree = degree_value,
scale = 1,
offset = 1
)
} else if (kernel_type == "RBF") {
kernel <- kernlab::rbfdot(
sigma = gamma_value
)
} else {
stop("Jenis kernel tidak dikenali.")
}
return(kernel)
}
# Fungsi Standardisasi Data pada Setiap Fold
scale_fold <- function(train_data, valid_data, predictors_used) {
# Menghitung mean dan standar deviasi dari data training
mean_train <- sapply(
train_data[, predictors_used, drop = FALSE],
mean,
na.rm = TRUE
)
sd_train <- sapply(
train_data[, predictors_used, drop = FALSE],
sd,
na.rm = TRUE
)
# Menghindari pembagian dengan nol
sd_train[sd_train == 0] <- 1
# Standardisasi data training
train_scaled <- train_data
train_scaled[, predictors_used] <- scale(
train_data[, predictors_used, drop = FALSE],
center = mean_train,
scale = sd_train
)
# Standardisasi data validasi menggunakan mean dan SD training
valid_scaled <- valid_data
valid_scaled[, predictors_used] <- scale(
valid_data[, predictors_used, drop = FALSE],
center = mean_train,
scale = sd_train
)
# Mengembalikan kedua data yang sudah distandardisasi
return(list(
train = train_scaled,
valid = valid_scaled
))
}
# Menggabungkan seluruh kombinasi
grid_svm <- dplyr::bind_rows(
grid_linear,
grid_poly,
grid_rbf
)
# Menampilkan jumlah kombinasi
cat(
"Jumlah kombinasi hyperparameter:",
nrow(grid_svm)
)## Jumlah kombinasi hyperparameter: 20
# Menampilkan grid hyperparameter
knitr::kable(
grid_svm,
caption = "Grid Hyperparameter SVM",
digits = 3
)| Kernel | C | Degree | Gamma |
|---|---|---|---|
| Linear | 1e-02 | NA | NA |
| Linear | 1e-01 | NA | NA |
| Linear | 1e+00 | NA | NA |
| Linear | 1e+01 | NA | NA |
| Linear | 1e+02 | NA | NA |
| Polynomial | 1e-01 | 2 | NA |
| Polynomial | 1e+00 | 2 | NA |
| Polynomial | 1e+01 | 2 | NA |
| Polynomial | 1e-01 | 3 | NA |
| Polynomial | 1e+00 | 3 | NA |
| Polynomial | 1e+01 | 3 | NA |
| RBF | 1e-01 | NA | 0.01 |
| RBF | 1e+00 | NA | 0.01 |
| RBF | 1e+01 | NA | 0.01 |
| RBF | 1e-01 | NA | 0.10 |
| RBF | 1e+00 | NA | 0.10 |
| RBF | 1e+01 | NA | 0.10 |
| RBF | 1e-01 | NA | 1.00 |
| RBF | 1e+00 | NA | 1.00 |
| RBF | 1e+01 | NA | 1.00 |
# Menyiapkan hasil 5-fold
hasil_kernel_5 <- grid_svm
hasil_kernel_5$Mean_Accuracy <- NA_real_
hasil_kernel_5$SD_Accuracy <- NA_real_
hasil_kernel_5$Mean_AUC <- NA_real_
hasil_kernel_5$SD_AUC <- NA_real_
# Menguji seluruh kombinasi parameter
for (i in seq_len(nrow(hasil_kernel_5))) {
hasil_cv <- cv_svm(
data = train_raw,
predictors_used = predictors,
kernel_type = hasil_kernel_5$Kernel[i],
cost_value = hasil_kernel_5$C[i],
degree_value = ifelse(
is.na(hasil_kernel_5$Degree[i]),
2,
hasil_kernel_5$Degree[i]
),
gamma_value = ifelse(
is.na(hasil_kernel_5$Gamma[i]),
0.1,
hasil_kernel_5$Gamma[i]
),
k = 5,
seed = 2026
)
hasil_kernel_5$Mean_Accuracy[i] <-
hasil_cv$Mean_Accuracy
hasil_kernel_5$SD_Accuracy[i] <-
hasil_cv$SD_Accuracy
hasil_kernel_5$Mean_AUC[i] <-
hasil_cv$Mean_AUC
hasil_kernel_5$SD_AUC[i] <-
hasil_cv$SD_AUC
}
# Mengurutkan hasil berdasarkan AUC
hasil_kernel_5 <- hasil_kernel_5 %>%
dplyr::arrange(
dplyr::desc(Mean_AUC),
dplyr::desc(Mean_Accuracy)
)
# Menampilkan hasil
knitr::kable(
hasil_kernel_5,
digits = 4,
caption = "Hasil Optimasi Hyperparameter SVM dengan 5-Fold CV"
)| Kernel | C | Degree | Gamma | Mean_Accuracy | SD_Accuracy | Mean_AUC | SD_AUC |
|---|---|---|---|---|---|---|---|
| RBF | 1e+00 | NA | 0.01 | 0.9663 | 0.0544 | 0.9967 | 0.0075 |
| RBF | 1e+00 | NA | 0.10 | 0.9663 | 0.0544 | 0.9967 | 0.0075 |
| Linear | 1e-01 | NA | NA | 0.9583 | 0.0510 | 0.9967 | 0.0075 |
| RBF | 1e+01 | NA | 0.01 | 0.9583 | 0.0510 | 0.9967 | 0.0075 |
| Linear | 1e+02 | NA | NA | 0.9499 | 0.0360 | 0.9967 | 0.0075 |
| Linear | 1e-02 | NA | NA | 0.9416 | 0.0483 | 0.9967 | 0.0075 |
| Linear | 1e+00 | NA | NA | 0.9416 | 0.0483 | 0.9967 | 0.0075 |
| RBF | 1e-01 | NA | 0.10 | 0.9416 | 0.0483 | 0.9967 | 0.0075 |
| Linear | 1e+01 | NA | NA | 0.9249 | 0.0558 | 0.9967 | 0.0075 |
| RBF | 1e-01 | NA | 0.01 | 0.6478 | 0.0118 | 0.9967 | 0.0075 |
| Polynomial | 1e+00 | 3 | NA | 0.9423 | 0.0377 | 0.9940 | 0.0060 |
| Polynomial | 1e+01 | 3 | NA | 0.9423 | 0.0377 | 0.9940 | 0.0060 |
| Polynomial | 1e-01 | 2 | NA | 0.9583 | 0.0510 | 0.9939 | 0.0084 |
| RBF | 1e+01 | NA | 0.10 | 0.9423 | 0.0471 | 0.9925 | 0.0077 |
| Polynomial | 1e-01 | 3 | NA | 0.9343 | 0.0372 | 0.9897 | 0.0097 |
| RBF | 1e-01 | NA | 1.00 | 0.6478 | 0.0118 | 0.9815 | 0.0192 |
| Polynomial | 1e+00 | 2 | NA | 0.9023 | 0.0453 | 0.9770 | 0.0240 |
| RBF | 1e+00 | NA | 1.00 | 0.9176 | 0.0501 | 0.9769 | 0.0220 |
| RBF | 1e+01 | NA | 1.00 | 0.9016 | 0.0458 | 0.9684 | 0.0276 |
| Polynomial | 1e+01 | 2 | NA | 0.9106 | 0.0427 | 0.9624 | 0.0385 |
# Menyiapkan hasil 10-fold
hasil_kernel_10 <- grid_svm
hasil_kernel_10$Mean_Accuracy <- NA_real_
hasil_kernel_10$SD_Accuracy <- NA_real_
hasil_kernel_10$Mean_AUC <- NA_real_
hasil_kernel_10$SD_AUC <- NA_real_
# Menguji seluruh kombinasi parameter
for (i in seq_len(nrow(hasil_kernel_10))) {
hasil_cv <- cv_svm(
data = train_raw,
predictors_used = predictors,
kernel_type = hasil_kernel_10$Kernel[i],
cost_value = hasil_kernel_10$C[i],
degree_value = ifelse(
is.na(hasil_kernel_10$Degree[i]),
2,
hasil_kernel_10$Degree[i]
),
gamma_value = ifelse(
is.na(hasil_kernel_10$Gamma[i]),
0.1,
hasil_kernel_10$Gamma[i]
),
k = 10,
seed = 2026
)
hasil_kernel_10$Mean_Accuracy[i] <-
hasil_cv$Mean_Accuracy
hasil_kernel_10$SD_Accuracy[i] <-
hasil_cv$SD_Accuracy
hasil_kernel_10$Mean_AUC[i] <-
hasil_cv$Mean_AUC
hasil_kernel_10$SD_AUC[i] <-
hasil_cv$SD_AUC
}
# Mengurutkan hasil berdasarkan AUC
hasil_kernel_10 <- hasil_kernel_10 %>%
dplyr::arrange(
dplyr::desc(Mean_AUC),
dplyr::desc(Mean_Accuracy)
)
# Menampilkan hasil
knitr::kable(
hasil_kernel_10,
digits = 4,
caption = "Hasil Optimasi Hyperparameter SVM dengan 10-Fold CV"
)| Kernel | C | Degree | Gamma | Mean_Accuracy | SD_Accuracy | Mean_AUC | SD_AUC |
|---|---|---|---|---|---|---|---|
| RBF | 1e+00 | NA | 0.01 | 0.9658 | 0.0617 | 0.9964 | 0.0113 |
| RBF | 1e-01 | NA | 0.10 | 0.9581 | 0.0617 | 0.9964 | 0.0113 |
| Linear | 1e+00 | NA | NA | 0.9491 | 0.0614 | 0.9950 | 0.0158 |
| RBF | 1e-01 | NA | 0.01 | 0.6483 | 0.0245 | 0.9939 | 0.0130 |
| Linear | 1e-02 | NA | NA | 0.9498 | 0.0611 | 0.9929 | 0.0226 |
| Linear | 1e+02 | NA | NA | 0.9422 | 0.0540 | 0.9912 | 0.0205 |
| Linear | 1e+01 | NA | NA | 0.9331 | 0.0665 | 0.9912 | 0.0142 |
| RBF | 1e+00 | NA | 0.10 | 0.9567 | 0.0872 | 0.9904 | 0.0231 |
| Linear | 1e-01 | NA | NA | 0.9575 | 0.0622 | 0.9879 | 0.0261 |
| RBF | 1e+01 | NA | 0.01 | 0.9575 | 0.0622 | 0.9879 | 0.0261 |
| Polynomial | 1e-01 | 2 | NA | 0.9498 | 0.0611 | 0.9879 | 0.0261 |
| RBF | 1e+01 | NA | 0.10 | 0.9247 | 0.0869 | 0.9879 | 0.0261 |
| Polynomial | 1e+00 | 2 | NA | 0.9009 | 0.0889 | 0.9816 | 0.0262 |
| Polynomial | 1e-01 | 3 | NA | 0.9408 | 0.0593 | 0.9789 | 0.0318 |
| Polynomial | 1e+00 | 3 | NA | 0.9241 | 0.0752 | 0.9785 | 0.0256 |
| Polynomial | 1e+01 | 3 | NA | 0.9241 | 0.0752 | 0.9785 | 0.0256 |
| RBF | 1e+00 | NA | 1.00 | 0.9100 | 0.0912 | 0.9754 | 0.0574 |
| RBF | 1e-01 | NA | 1.00 | 0.6483 | 0.0245 | 0.9754 | 0.0574 |
| Polynomial | 1e+01 | 2 | NA | 0.9017 | 0.0761 | 0.9685 | 0.0343 |
| RBF | 1e+01 | NA | 1.00 | 0.8934 | 0.1041 | 0.9629 | 0.0593 |
# Mengambil parameter terbaik dari 5-fold
best_5 <- hasil_kernel_5 %>%
dplyr::slice_max(
order_by = Mean_AUC,
n = 1,
with_ties = FALSE
) %>%
dplyr::mutate(
CV = "5-Fold"
)
# Mengambil parameter terbaik dari 10-fold
best_10 <- hasil_kernel_10 %>%
dplyr::slice_max(
order_by = Mean_AUC,
n = 1,
with_ties = FALSE
) %>%
dplyr::mutate(
CV = "10-Fold"
)
# Menggabungkan hasil terbaik
perbandingan_best <- dplyr::bind_rows(
best_5,
best_10
) %>%
dplyr::select(
CV,
Kernel,
C,
Degree,
Gamma,
Mean_Accuracy,
SD_Accuracy,
Mean_AUC,
SD_AUC
)
knitr::kable(
perbandingan_best,
digits = 4,
caption = "Perbandingan Kombinasi Parameter Terbaik SVM"
)| CV | Kernel | C | Degree | Gamma | Mean_Accuracy | SD_Accuracy | Mean_AUC | SD_AUC |
|---|---|---|---|---|---|---|---|---|
| 5-Fold | RBF | 1 | NA | 0.01 | 0.9663 | 0.0544 | 0.9967 | 0.0075 |
| 10-Fold | RBF | 1 | NA | 0.01 | 0.9658 | 0.0617 | 0.9964 | 0.0113 |
Berdasarkan hasil optimasi hyperparameter menggunakan 5-Fold Cross-Validation, kombinasi terbaik diperoleh pada kernel Radial Basis Function (RBF) dengan nilai Cost (C) sebesar 1 dan Gamma sebesar 0,01. Kombinasi tersebut menghasilkan Mean Accuracy sebesar 96,63% dan Mean AUC sebesar 99,67%. Hasil ini menunjukkan bahwa model memiliki kemampuan klasifikasi yang sangat baik dalam mengklasifikasikan negara ke dalam kategori HDI Tinggi dan HDI Rendah, serta kemampuan yang sangat tinggi dalam membedakan kedua kelas tersebut.
Hasil yang relatif konsisten diperoleh pada 10-Fold Cross-Validation dengan kombinasi hyperparameter terbaik yang sama, yaitu kernel RBF, C sebesar 1, dan Gamma sebesar 0,01. Model menghasilkan Mean Accuracy sebesar 96,58% dan Mean AUC sebesar 99,64%. Perbedaan performa antara kedua skema Cross-Validation relatif kecil, sehingga kombinasi hyperparameter tersebut dipilih sebagai model terbaik untuk tahap pemodelan SVM selanjutnya.
# Menggabungkan seluruh hasil 5-fold dan 10-fold
hasil_kernel_battle <- dplyr::bind_rows(
hasil_kernel_5 %>%
dplyr::mutate(CV = "5-Fold"),
hasil_kernel_10 %>%
dplyr::mutate(CV = "10-Fold")
)
# Mengambil kombinasi parameter terbaik
best_parameter <- hasil_kernel_battle %>%
dplyr::slice_max(
order_by = Mean_AUC,
n = 1,
with_ties = FALSE
)
# Menampilkan parameter terbaik
knitr::kable(
best_parameter,
digits = 4,
caption = "Kombinasi Hyperparameter SVM Terbaik"
)| Kernel | C | Degree | Gamma | Mean_Accuracy | SD_Accuracy | Mean_AUC | SD_AUC | CV |
|---|---|---|---|---|---|---|---|---|
| RBF | 1 | NA | 0.01 | 0.9663 | 0.0544 | 0.9967 | 0.0075 | 5-Fold |
# Membentuk model SVM final berdasarkan parameter terbaik
svm_best <- fit_svm(
train_data = train_scaled,
predictors_used = predictors,
kernel_type = as.character(best_parameter$Kernel[1]),
cost_value = best_parameter$C[1],
degree_value = ifelse(
is.na(best_parameter$Degree[1]),
2,
best_parameter$Degree[1]
),
gamma_value = ifelse(
is.na(best_parameter$Gamma[1]),
0.1,
best_parameter$Gamma[1]
)
)
# Ringkasan model
svm_best## Support Vector Machine object of class "ksvm"
##
## SV type: C-svc (classification)
## parameter : cost C = 1
##
## Gaussian Radial Basis kernel function.
## Hyperparameter : sigma = 0.01
##
## Number of Support Vectors : 54
##
## Objective Function Value : -38.4921
## Training error : 0.032787
## Probability model included.
# Evaluasi model SVM terbaik
hasil_final_svm <- evaluate_svm(
model = svm_best,
test_data = test_scaled,
predictors_used = predictors
)
# Menampilkan hasil evaluasi
knitr::kable(
hasil_final_svm,
digits = 4,
caption = "Evaluasi Model SVM Terbaik pada Data Testing"
)| Accuracy | AUC | Sensitivity | Specificity | Precision | F1_Score |
|---|---|---|---|---|---|
| 0.9032 | 0.9545 | 0.95 | 0.8182 | 0.9048 | 0.9268 |
Berdasarkan hasil analisis menggunakan metode Support Vector Machine (SVM), data HDI dari 153 negara dikelompokkan menjadi dua kategori, yaitu HDI tinggi dan HDI rendah. Hasil eksplorasi menunjukkan bahwa terdapat 99 negara (64,71%) dalam kategori HDI tinggi dan 54 negara (35,29%) dalam kategori HDI rendah. Pemodelan dilakukan menggunakan enam variabel prediktor, yaitu GDP, Social Support, Healthy Life Expectancy, Freedom, Generosity, dan Corruption, dengan pembagian data sebesar 80% untuk training dan 20% untuk testing.
Pada evaluasi awal, kernel Linear menunjukkan performa terbaik dengan Accuracy sebesar 87,10%. Namun, setelah dilakukan optimasi hyperparameter menggunakan 5-Fold dan 10-Fold Cross-Validation, kernel Radial Basis Function (RBF) dengan nilai Cost sebesar 1 dan Gamma sebesar 0,01 memberikan hasil terbaik pada kedua skema. Kombinasi tersebut menghasilkan Mean Accuracy sebesar 96,63% pada 5-Fold dan 96,58% pada 10-Fold, serta Mean AUC masing-masing sebesar 99,67% dan 99,64%. Konsistensi hasil tersebut menunjukkan bahwa kombinasi hyperparameter yang diperoleh relatif stabil pada kedua skema validasi.
# Formula enam prediktor
vars_x <- c(
"gdp_per_capita",
"social_support",
"healthy_life_expectancy",
"freedom_to_make_life_choices",
"generosity",
"perceptions_of_corruption"
)
form6 <- reformulate(
vars_x,
response = "hdi"
)
form6## hdi ~ gdp_per_capita + social_support + healthy_life_expectancy +
## freedom_to_make_life_choices + generosity + perceptions_of_corruption
Formula model digunakan untuk mendefinisikan HDI sebagai variabel respons yang diprediksi berdasarkan enam variabel prediktor. Dengan demikian, seluruh indikator Happiness dimasukkan secara bersamaan ke dalam model SVR.
set.seed(123)
# Menentukan jumlah data training
n <- nrow(data_svr)
# Membagi data dengan promosi 80 : 20
index_train <- sample(
seq_len(n),
size = floor(0.8 * n)
)
# Membentuk data training dan testing
train_hdi <- data_svr[index_train, ]
test_hdi <- data_svr[-index_train, ]
# Memeriksa jumlah observasi
cat("Jumlah data training:", nrow(train_hdi), "\n")## Jumlah data training: 122
## Jumlah data testing: 31
Dataset dibagi menjadi dua bagian dengan proporsi 80:20. Sebanyak 122 observasi digunakan sebagai data training untuk membentuk model, sedangkan 31 observasi digunakan sebagai data testing untuk mengevaluasi kemampuan model dalam memprediksi data yang belum digunakan pada proses pelatihan.
Pembagian ini dilakukan agar evaluasi model dapat memberikan gambaran mengenai kemampuan generalisasi model terhadap data baru.
fit_linear6 <- svm(
hdi ~ gdp_per_capita + social_support +
healthy_life_expectancy + freedom_to_make_life_choices +
generosity + perceptions_of_corruption,
data = train_hdi,
type = "eps-regression",
kernel = "linear",
cost = 1,
epsilon = 0.05,
scale = TRUE
)
# Melihat hasil model
summary(fit_linear6)##
## Call:
## svm(formula = hdi ~ gdp_per_capita + social_support + healthy_life_expectancy +
## freedom_to_make_life_choices + generosity + perceptions_of_corruption,
## data = train_hdi, type = "eps-regression", kernel = "linear",
## cost = 1, epsilon = 0.05, scale = TRUE)
##
##
## Parameters:
## SVM-Type: eps-regression
## SVM-Kernel: linear
## cost: 1
## gamma: 0.1666667
## epsilon: 0.05
##
##
## Number of Support Vectors: 102
Model SVR Linear dibangun menggunakan kernel linear dengan parameter cost = 1 dan epsilon = 0.05. Kernel linear digunakan untuk membentuk model berdasarkan pola hubungan yang bersifat linear dalam ruang fitur.
Berdasarkan hasil ringkasan model, diperoleh jumlah support vectors sebanyak 102. Support vectors merupakan observasi yang berperan dalam menentukan fungsi regresi SVR. Dengan kata lain, observasi tersebut menjadi bagian penting dalam pembentukan model.
fit_radial6 <- svm(
hdi ~ gdp_per_capita + social_support +
healthy_life_expectancy + freedom_to_make_life_choices +
generosity + perceptions_of_corruption,
data = train_hdi,
type = "eps-regression",
kernel = "radial",
cost = 1,
epsilon = 0.05,
scale = TRUE
)
# Melihat hasil model
summary(fit_radial6)##
## Call:
## svm(formula = hdi ~ gdp_per_capita + social_support + healthy_life_expectancy +
## freedom_to_make_life_choices + generosity + perceptions_of_corruption,
## data = train_hdi, type = "eps-regression", kernel = "radial",
## cost = 1, epsilon = 0.05, scale = TRUE)
##
##
## Parameters:
## SVM-Type: eps-regression
## SVM-Kernel: radial
## cost: 1
## gamma: 0.1666667
## epsilon: 0.05
##
##
## Number of Support Vectors: 100
Model SVR Radial dibangun menggunakan kernel radial atau Radial Basis Function (RBF), dengan nilai parameter cost = 1 dan epsilon = 0.05.
Berbeda dengan kernel linear, kernel radial memungkinkan model menangkap pola hubungan nonlinier antara variabel prediktor dan respons. Berdasarkan hasil ringkasan model, diperoleh jumlah support vectors sebanyak 100 observasi.
Jumlah support vectors pada kedua model tidak secara langsung menunjukkan model mana yang lebih baik. Kinerja keduanya perlu dibandingkan melalui hasil prediksi dan metrik evaluasi pada data testing.
Sebelum melakukan prediksi, terlebih dahulu dibuat fungsi evaluasi untuk mengukur kinerja model SVR. Evaluasi dilakukan menggunakan tiga metrik, yaitu Mean Absolute Error (MAE), Root Mean Squared Error (RMSE), dan Coefficient of Determination (\(R^2\)). Ketiga metrik tersebut digunakan untuk mengetahui besarnya kesalahan prediksi serta kemampuan model dalam menjelaskan variasi nilai HDI.
metrik_svr <- function(actual, predicted) {
MAE <- mean(abs(actual - predicted))
RMSE <- sqrt(mean((actual - predicted)^2))
R2 <- if (sum((actual - mean(actual))^2) > 0) {
1 - sum((actual - predicted)^2) /
sum((actual - mean(actual))^2)
} else {
NA_real_
}
return(c(
MAE = MAE,
RMSE = RMSE,
R2 = R2
))
}Setelah fungsi evaluasi dibuat, tahap selanjutnya adalah melakukan prediksi nilai HDI pada data testing menggunakan model SVR Linear dan SVR Radial yang telah dibangun sebelumnya. Prediksi ini dilakukan untuk memperoleh estimasi nilai HDI berdasarkan masing-masing model. Hasil prediksi kemudian disajikan bersama nilai HDI aktual agar dapat dibandingkan dan digunakan dalam proses evaluasi kinerja model.
# Prediksi SVR Linear
pred_linear <- predict(
fit_linear6,
newdata = test_hdi
)
# Prediksi SVR Radial
pred_radial <- predict(
fit_radial6,
newdata = test_hdi
)
# Membandingkan nilai aktual dan prediksi
hasil_prediksi <- data.frame(
Aktual = test_hdi$hdi,
Prediksi_Linear = as.numeric(pred_linear),
Prediksi_Radial = as.numeric(pred_radial)
)
head(hasil_prediksi)## Aktual Prediksi_Linear Prediksi_Radial
## 1 0.948 0.9304751 0.8822071
## 2 0.962 0.9439617 0.9230815
## 3 0.970 0.9777317 0.9457098
## 4 0.958 0.9496924 0.9522328
## 5 0.951 0.9331535 0.9252848
## 6 0.938 0.9248696 0.9253091
Setelah memperoleh hasil prediksi dari kedua model, selanjutnya dilakukan evaluasi model baseline untuk mengetahui kemampuan awal SVR Linear dan SVR Radial dalam memprediksi nilai HDI. Evaluasi dilakukan menggunakan metrik MAE, RMSE, dan \(R^2\) yang telah didefinisikan sebelumnya. Nilai MAE dan RMSE yang lebih kecil menunjukkan tingkat kesalahan prediksi yang lebih rendah, sedangkan nilai \(R^2\) yang lebih besar menunjukkan kemampuan model yang lebih baik dalam menjelaskan variasi nilai HDI.
# Evaluasi model linear
eval_linear <- metrik_svr(
test_hdi$hdi,
pred_linear
)
# Evaluasi model radial
eval_radial <- metrik_svr(
test_hdi$hdi,
pred_radial
)
# Membuat tabel perbandingan
hasil_evaluasi <- data.frame(
Model = c("SVR Linear", "SVR Radial"),
MAE = c(
eval_linear["MAE"],
eval_radial["MAE"]
),
RMSE = c(
eval_linear["RMSE"],
eval_radial["RMSE"]
),
R2 = c(
eval_linear["R2"],
eval_radial["R2"]
)
)
kable(
hasil_evaluasi,
digits = 4,
caption = "Perbandingan Kinerja Model SVR Baseline"
)| Model | MAE | RMSE | R2 |
|---|---|---|---|
| SVR Linear | 0.0286 | 0.0372 | 0.9213 |
| SVR Radial | 0.0312 | 0.0384 | 0.9163 |
Berdasarkan hasil evaluasi, SVR Linear menunjukkan kinerja yang sedikit lebih baik dibandingkan SVR Radial. Hal ini ditunjukkan oleh nilai MAE dan RMSE yang lebih rendah, masing-masing sebesar 0,0286 dan 0,0372. Selain itu, SVR Linear memiliki nilai \(R^2\) lebih tinggi, yaitu 0,9213, yang menunjukkan bahwa model mampu menjelaskan sekitar 92,13% variasi nilai HDI.
Dengan demikian, SVR Linear dipilih sebagai model baseline terbaik karena menghasilkan kesalahan prediksi yang lebih kecil dan kemampuan penjelasan variasi data yang lebih tinggi dibandingkan SVR Radial.
Setelah mengevaluasi model baseline, tahap selanjutnya adalah melakukan tuning hyperparameter untuk memperoleh kombinasi parameter terbaik yang dapat meningkatkan kinerja model SVR. Proses tuning dilakukan dengan menguji beberapa kombinasi nilai cost, epsilon, dan gamma pada kernel yang digunakan. Pengujian dilakukan menggunakan metode 5-Fold Cross-Validation dan 10-Fold Cross-Validation untuk memperoleh nilai RMSE pada setiap kombinasi parameter. Kombinasi dengan rata-rata RMSE terkecil akan dipertimbangkan sebagai kombinasi parameter terbaik.
Data training dibagi menjadi 5 fold dan 10 fold. Proses ini dilakukan untuk mengevaluasi kombinasi hyperparameter secara berulang sehingga penilaian model tidak hanya bergantung pada satu pembagian data training dan validasi.
set.seed(123)
# Membagi training set menjadi 5 fold
fold_id <- sample(
rep(1:5, length.out = nrow(train_hdi))
)
# Melihat jumlah observasi setiap fold
table(fold_id)## fold_id
## 1 2 3 4 5
## 25 25 24 24 24
Tuning dilakukan dengan menguji beberapa kombinasi nilai cost, epsilon, dan gamma untuk kernel yang sesuai. - cost: mengatur besarnya penalti terhadap kesalahan prediksi yang berada di luar epsilon tube. - epsilon: menentukan lebar toleransi kesalahan prediksi yang tidak dikenai penalti dalam fungsi loss SVR. - gamma: mengatur jangkauan pengaruh observasi pada kernel radial. Parameter ini tidak digunakan untuk kernel linear. Dalam penelitian ini, terdapat sembilan kombinasi parameter untuk kernel linear dan 27 kombinasi untuk kernel radial. Dengan demikian, total terdapat 36 kombinasi hyperparameter yang dievaluasi.
# Grid untuk kernel linear
grid_linear <- expand.grid(
kernel = "linear",
cost = c(0.1, 1, 10),
epsilon = c(0.02, 0.05, 0.1),
gamma = NA_real_
)
# Grid untuk kernel radial
grid_radial <- expand.grid(
kernel = "radial",
cost = c(0.1, 1, 10),
epsilon = c(0.02, 0.05, 0.1),
gamma = c(0.05, 0.2, 1)
)
# Menggabungkan seluruh kombinasi
grid <- rbind(
grid_linear,
grid_radial
)
# Melihat jumlah kombinasi
nrow(grid)## [1] 36
## kernel cost epsilon gamma
## 1 linear 0.1 0.02 NA
## 2 linear 1.0 0.02 NA
## 3 linear 10.0 0.02 NA
## 4 linear 0.1 0.05 NA
## 5 linear 1.0 0.05 NA
## 6 linear 10.0 0.05 NA
# Fungsi Cross-Validation SVR
cv_rmse <- function(
kernel,
cost,
epsilon,
gamma,
formula,
dataset,
k = 5,
seed = 123
) {
set.seed(seed)
# Membagi data training menjadi k fold
fold_id <- sample(
rep(1:k, length.out = nrow(dataset))
)
# Menyimpan RMSE setiap fold
hasil_fold <- vapply(1:k, function(i) {
# Membagi data training dan validasi
d_train <- dataset[fold_id != i, ]
d_valid <- dataset[fold_id == i, ]
# Menentukan parameter model
args <- list(
formula = formula,
data = d_train,
type = "eps-regression",
kernel = kernel,
cost = cost,
epsilon = epsilon,
scale = TRUE
)
# Gamma hanya digunakan untuk kernel radial
if (kernel == "radial") {
args$gamma <- gamma
}
# Membentuk model
fit <- do.call(
e1071::svm,
args
)
# Prediksi data validasi
pred <- predict(
fit,
newdata = d_valid
)
# Menghitung RMSE
sqrt(mean(
(d_valid$hdi - pred)^2
))
}, numeric(1))
return(hasil_fold)
}# Fungsi untuk melakukan tuning SVR
tune_svr <- function(grid, k, formula, dataset, seed = 123) {
hasil <- grid
hasil$Mean_RMSE <- NA_real_
hasil$SD_RMSE <- NA_real_
for (i in seq_len(nrow(hasil))) {
nilai_rmse <- cv_rmse(
kernel = hasil$kernel[i],
cost = hasil$cost[i],
epsilon = hasil$epsilon[i],
gamma = hasil$gamma[i],
formula = formula,
dataset = dataset,
k = k,
seed = seed
)
hasil$Mean_RMSE[i] <- mean(nilai_rmse)
hasil$SD_RMSE[i] <- sd(nilai_rmse)
}
# Mengurutkan berdasarkan RMSE terkecil
hasil <- hasil[
order(hasil$Mean_RMSE),
]
rownames(hasil) <- NULL
return(hasil)
}
# Tuning menggunakan 5-Fold CV
hasil_svr_5 <- tune_svr(
grid = grid,
k = 5,
formula = form6,
dataset = train_hdi,
seed = 123
)
# Menampilkan 10 kombinasi terbaik
knitr::kable(
head(hasil_svr_5, 10),
digits = 4,
caption = "10 Kombinasi Hyperparameter Terbaik SVR Berdasarkan 5-Fold CV"
)| kernel | cost | epsilon | gamma | Mean_RMSE | SD_RMSE |
|---|---|---|---|---|---|
| linear | 0.1 | 0.10 | NA | 0.0407 | 0.0086 |
| linear | 1.0 | 0.10 | NA | 0.0409 | 0.0080 |
| linear | 1.0 | 0.05 | NA | 0.0409 | 0.0083 |
| linear | 10.0 | 0.10 | NA | 0.0409 | 0.0079 |
| linear | 10.0 | 0.05 | NA | 0.0410 | 0.0083 |
| linear | 1.0 | 0.02 | NA | 0.0411 | 0.0087 |
| linear | 10.0 | 0.02 | NA | 0.0412 | 0.0087 |
| linear | 0.1 | 0.02 | NA | 0.0412 | 0.0087 |
| linear | 0.1 | 0.05 | NA | 0.0412 | 0.0086 |
| radial | 10.0 | 0.10 | 0.05 | 0.0429 | 0.0048 |
# Tuning menggunakan 10-Fold CV
hasil_svr_10 <- tune_svr(
grid = grid,
k = 10,
formula = form6,
dataset = train_hdi,
seed = 123
)
# Menampilkan 10 kombinasi terbaik
knitr::kable(
head(hasil_svr_10, 10),
digits = 4,
caption = "10 Kombinasi Hyperparameter Terbaik SVR Berdasarkan 10-Fold CV"
)| kernel | cost | epsilon | gamma | Mean_RMSE | SD_RMSE |
|---|---|---|---|---|---|
| linear | 10.0 | 0.10 | NA | 0.0410 | 0.0095 |
| linear | 1.0 | 0.10 | NA | 0.0410 | 0.0095 |
| linear | 1.0 | 0.05 | NA | 0.0410 | 0.0103 |
| linear | 10.0 | 0.05 | NA | 0.0411 | 0.0103 |
| linear | 10.0 | 0.02 | NA | 0.0412 | 0.0106 |
| linear | 1.0 | 0.02 | NA | 0.0413 | 0.0107 |
| linear | 0.1 | 0.02 | NA | 0.0413 | 0.0108 |
| linear | 0.1 | 0.05 | NA | 0.0413 | 0.0107 |
| linear | 0.1 | 0.10 | NA | 0.0413 | 0.0106 |
| radial | 10.0 | 0.10 | 0.05 | 0.0422 | 0.0071 |
# Mengambil kombinasi terbaik 5-Fold
best_5 <- hasil_svr_5[1, ]
# Mengambil kombinasi terbaik 10-Fold
best_10 <- hasil_svr_10[1, ]
# Membuat tabel perbandingan
perbandingan_best <- data.frame(
CV = c("5-Fold", "10-Fold"),
Kernel = c(best_5$kernel, best_10$kernel),
Cost = c(best_5$cost, best_10$cost),
Epsilon = c(best_5$epsilon, best_10$epsilon),
Gamma = c(best_5$gamma, best_10$gamma),
Mean_RMSE = c(
best_5$Mean_RMSE,
best_10$Mean_RMSE
),
SD_RMSE = c(
best_5$SD_RMSE,
best_10$SD_RMSE
)
)
knitr::kable(
perbandingan_best,
digits = 4,
caption = "Perbandingan Kombinasi Parameter Terbaik SVR"
)| CV | Kernel | Cost | Epsilon | Gamma | Mean_RMSE | SD_RMSE |
|---|---|---|---|---|---|---|
| 5-Fold | linear | 0.1 | 0.1 | NA | 0.0407 | 0.0086 |
| 10-Fold | linear | 10.0 | 0.1 | NA | 0.0410 | 0.0095 |
Berdasarkan hasil optimasi parameter, 5-Fold Cross-Validation menghasilkan kombinasi terbaik berupa kernel linear, cost sebesar 0,1, dan epsilon sebesar 0,1, dengan Mean RMSE sebesar 0,0407. Sementara itu, pada 10-Fold Cross-Validation, kombinasi terbaik diperoleh menggunakan kernel linear, cost sebesar 10, dan epsilon sebesar 0,1, dengan Mean RMSE sebesar 0,0410.
Kedua skema cross-validation sama-sama memilih kernel linear dengan nilai epsilon yang sama. Nilai Mean RMSE pada 5-Fold sedikit lebih rendah dibandingkan 10-Fold, sehingga kombinasi parameter 5-Fold memberikan hasil validasi yang sedikit lebih baik. Nilai SD_RMSE menunjukkan variasi RMSE antar-fold, dengan variasi pada 5-Fold (0,0086) yang juga sedikit lebih rendah dibandingkan 10-Fold (0,0095).
# Menggabungkan hasil 5-Fold dan 10-Fold
hasil_svr_battle <- merge(
hasil_svr_5,
hasil_svr_10,
by = c("kernel", "cost", "epsilon", "gamma"),
suffixes = c("_5Fold", "_10Fold")
)
# Menghitung rata-rata RMSE kedua skema
hasil_svr_battle$Mean_RMSE_Gabungan <- rowMeans(
hasil_svr_battle[, c(
"Mean_RMSE_5Fold",
"Mean_RMSE_10Fold"
)]
)
# Mengurutkan berdasarkan RMSE gabungan terkecil
hasil_svr_battle <- hasil_svr_battle[
order(hasil_svr_battle$Mean_RMSE_Gabungan),
]
# Menampilkan 10 kombinasi terbaik
knitr::kable(
head(hasil_svr_battle, 10),
digits = 4,
caption = "Perbandingan Kombinasi Hyperparameter SVR Berdasarkan 5-Fold dan 10-Fold CV"
)| kernel | cost | epsilon | gamma | Mean_RMSE_5Fold | SD_RMSE_5Fold | Mean_RMSE_10Fold | SD_RMSE_10Fold | Mean_RMSE_Gabungan | |
|---|---|---|---|---|---|---|---|---|---|
| 6 | linear | 1.0 | 0.10 | NA | 0.0409 | 0.0080 | 0.0410 | 0.0095 | 0.0409 |
| 9 | linear | 10.0 | 0.10 | NA | 0.0409 | 0.0079 | 0.0410 | 0.0095 | 0.0409 |
| 5 | linear | 1.0 | 0.05 | NA | 0.0409 | 0.0083 | 0.0410 | 0.0103 | 0.0410 |
| 3 | linear | 0.1 | 0.10 | NA | 0.0407 | 0.0086 | 0.0413 | 0.0106 | 0.0410 |
| 8 | linear | 10.0 | 0.05 | NA | 0.0410 | 0.0083 | 0.0411 | 0.0103 | 0.0410 |
| 4 | linear | 1.0 | 0.02 | NA | 0.0411 | 0.0087 | 0.0413 | 0.0107 | 0.0412 |
| 7 | linear | 10.0 | 0.02 | NA | 0.0412 | 0.0087 | 0.0412 | 0.0106 | 0.0412 |
| 1 | linear | 0.1 | 0.02 | NA | 0.0412 | 0.0087 | 0.0413 | 0.0108 | 0.0413 |
| 2 | linear | 0.1 | 0.05 | NA | 0.0412 | 0.0086 | 0.0413 | 0.0107 | 0.0413 |
| 34 | radial | 10.0 | 0.10 | 0.05 | 0.0429 | 0.0048 | 0.0422 | 0.0071 | 0.0425 |
# Mengambil parameter terbaik berdasarkan rata-rata
best <- hasil_svr_battle[1, ]
# Menampilkan parameter terbaik
best[, c(
"kernel",
"cost",
"epsilon",
"gamma",
"Mean_RMSE_5Fold",
"Mean_RMSE_10Fold",
"Mean_RMSE_Gabungan"
)]## kernel cost epsilon gamma Mean_RMSE_5Fold Mean_RMSE_10Fold Mean_RMSE_Gabungan
## 6 linear 1 0.1 NA 0.04086577 0.04100417 0.04093497
# Menyiapkan parameter model terbaik
args_best <- list(
formula = form6,
data = train_hdi,
type = "eps-regression",
kernel = best$kernel,
cost = best$cost,
epsilon = best$epsilon,
scale = TRUE
)
# Gamma hanya digunakan untuk kernel radial
if (best$kernel == "radial") {
args_best$gamma <- best$gamma
}
# Membentuk model terbaik
best_fit <- do.call(
e1071::svm,
args_best
)
# Melihat ringkasan model
summary(best_fit)##
## Call:
## svm(formula = hdi ~ gdp_per_capita + social_support + healthy_life_expectancy +
## freedom_to_make_life_choices + generosity + perceptions_of_corruption,
## data = structure(list(gdp_per_capita = c(1.609, 1.05, 0.512,
## 1.258, 0.306, 0.35, 1.029, 0.741, 0.619, 0.813, 0.755, 0.393,
## 1.155, 0.8, 1.387, 0.366, 1.067, 0.983, 0.476, 0.96, 0.308, 1.183,
## 1.124, 0, 0.274, 1.365, 1.238, 1.015, 1.07, 1.403, 1.201, 1.237,
## 0.35, 0.562, 0.094, 0.569, 1.231, 0.931, 0.794, 0.549, 1.044,
## 0.489, 0.811, 1.221, 1.276, 0.696, 0.446, 1.041, 1.159, 0.332,
## 1.503, 1.181, 0.949, 1.263, 0.191, 1.043, 0.611, 1.499, 1.092,
## 1.452, 0.331, 0.801, 0.323, 1.206, 1.004, 0.275, 0.026, 0.38,
## 1.38, 0.82, 0.85, 0.96, 1.301, 1.3, 0.336, 0.45, 1.294, 0.745,
## 1.149, 1.034, 0.886, 0.945, 0.677, 0.359, 1.004, 0.385, 1.246,
## 1.303, 1.187, 1.376, 1.043, 0.985, 0.694, 0.574, 0.493, 0.948,
## 0.268, 1.269, 1.162, 1.373, 1.12, 1.221, 0.138, 0.204, 1.1, 1.333,
## 1.324, 0.685, 0.578, 0.921, 1.286, 0.912, 0.879, 0.274, 0.947,
## 0.764, 0.855, 0.57, 1.396, 0.657, 0.287, 0.673), social_support = c(1.479,
## 1.409, 0.983, 1.523, 0.575, 0.517, 1.125, 1.346, 0.378, 1.321,
## 0.765, 0.437, 1.266, 1.269, 1.487, 1.114, 1.465, 1.294, 0.885,
## 1.351, 0.939, 1.36, 1.465, 0.698, 0.757, 1.505, 1.515, 1.401,
## 1.323, 1.357, 1.41, 1.528, 0.766, 0.928, 1.125, 0.808, 1.477,
## 1.203, 1.242, 0.91, 1.303, 1.169, 1.149, 1.431, 1.455, 1.111,
## 1.226, 1.145, 1.369, 1.069, 1.31, 1.156, 1.265, 1.223, 0.56,
## 0.98, 0.868, 1.553, 1.513, 1.526, 1.056, 0.782, 0.688, 1.438,
## 1.439, 0.572, 0, 0.829, 1.624, 1.39, 1.055, 1.427, 1.219, 1.52,
## 1.033, 1.134, 1.488, 1.529, 1.442, 1.441, 0.666, 1.212, 0.886,
## 0.711, 1.383, 1.105, 1.504, 1.557, 1.465, 1.475, 1.147, 1.41,
## 1.325, 1.122, 1.098, 1.531, 0.841, 1.487, 1.232, 1.454, 1.402,
## 1.171, 0.774, 0.986, 0.842, 1.538, 1.472, 1.328, 1.058, 1, 1.484,
## 1.312, 1.313, 0.916, 0.848, 1.03, 1.475, 1.167, 1.522, 1.247,
## 1.163, 0.799), healthy_life_expectancy = c(1.012, 0.828, 0.581,
## 0.953, 0.295, 0.361, 0.893, 0.851, 0.44, 0.604, 0.588, 0.397,
## 0.914, 0.746, 1.009, 0.433, 0.789, 0.838, 0.499, 0.469, 0.428,
## 0.808, 0.891, 0.268, 0.505, 1.039, 0.818, 0.779, 0.861, 0.795,
## 0.828, 0.874, 0.192, 0.723, 0.357, 0.232, 0.713, 0.66, 0.789,
## 0.331, 0.673, 0.168, 0, 0.999, 1.029, 0.245, 0.677, 0.538, 0.92,
## 0.443, 0.825, 0.999, 0.831, 1.042, 0.495, 0.574, 0.486, 0.999,
## 0.815, 1.052, 0.38, 0.782, 0.449, 0.884, 0.802, 0.41, 0.105,
## 0.375, 1.026, 0.739, 0.815, 0.805, 1.036, 0.999, 0.532, 0.571,
## 1.039, 0.756, 0.91, 0.963, 0.752, 0.845, 0.535, 0.614, 0.854,
## 0.308, 0.881, 1.026, 0.812, 1.016, 0.769, 0.841, 0.835, 0.637,
## 0.718, 0.667, 0.242, 0.92, 0.825, 0.987, 0.798, 0.828, 0.366,
## 0.39, 0.785, 0.996, 1.045, 0.739, 0.426, 0.815, 1.062, 0.868,
## 0.477, 0.555, 0.874, 0.551, 0.777, 0.489, 0.999, 0.672, 0.463,
## 0.508), freedom_to_make_life_choices = c(0.526, 0.557, 0.431,
## 0.564, 0.01, 0, 0.521, 0.543, 0.013, 0.457, 0.498, 0.349, 0.296,
## 0.535, 0.574, 0.361, 0.235, 0.345, 0.417, 0.389, 0.382, 0.195,
## 0.523, 0.559, 0.142, 0.584, 0.291, 0.497, 0.433, 0.439, 0.199,
## 0.495, 0.174, 0.527, 0.269, 0.352, 0.489, 0.491, 0.43, 0.381,
## 0.416, 0.359, 0.313, 0.508, 0.371, 0.426, 0.439, 0.455, 0.357,
## 0.356, 0.598, 0.067, 0.47, 0.406, 0.443, 0.241, 0.381, 0.516,
## 0.311, 0.572, 0.255, 0.418, 0.026, 0.483, 0.39, 0.293, 0.225,
## 0.332, 0.591, 0.178, 0.283, 0.154, 0.159, 0.564, 0.344, 0.292,
## 0.231, 0.631, 0.516, 0.558, 0.346, 0.212, 0.313, 0.555, 0.282,
## 0.327, 0.334, 0.585, 0.264, 0.532, 0.351, 0.47, 0.435, 0.609,
## 0.389, 0.317, 0.309, 0.457, 0.462, 0.495, 0.498, 0.508, 0.318,
## 0.494, 0.305, 0.45, 0.436, 0.245, 0.431, 0.167, 0.362, 0.498,
## 0.401, 0.148, 0.383, 0.547, 0.514, 0.066, 0.557, 0.225, 0.143,
## 0.372), generosity = c(0.194, 0.359, 0.372, 0.144, 0.202, 0.158,
## 0.058, 0.147, 0.331, 0.37, 0.2, 0.175, 0.119, 0.175, 0.267, 0.151,
## 0.094, 0.185, 0.276, 0.13, 0.269, 0.083, 0.127, 0.243, 0.275,
## 0.285, 0.043, 0.113, 0.074, 0.08, 0.081, 0.103, 0.198, 0.166,
## 0.212, 0.154, 0.185, 0.498, 0.093, 0.187, 0.133, 0.107, 0.074,
## 0.047, 0.261, 0.215, 0.285, 0.025, 0.187, 0.252, 0.262, 0, 0.244,
## 0.19, 0.218, 0.148, 0.245, 0.298, 0.081, 0.263, 0.177, 0.036,
## 0.419, 0.117, 0.099, 0.177, 0.235, 0.207, 0.354, 0.187, 0.095,
## 0.064, 0.175, 0.375, 0.209, 0.153, 0.158, 0.322, 0.109, 0.144,
## 0.043, 0.263, 0.22, 0.217, 0.137, 0.153, 0.121, 0.33, 0.075,
## 0.244, 0.035, 0.099, 0.2, 0.232, 0.23, 0.235, 0.252, 0.046, 0.083,
## 0.261, 0.215, 0.26, 0.188, 0.197, 0.27, 0.348, 0.111, 0.181,
## 0.247, 0.059, 0.153, 0.126, 0.07, 0.169, 0.178, 0.266, 0.184,
## 0.106, 0.322, 0.103, 0.108, 0.105), perceptions_of_corruption = c(0.316,
## 0.028, 0.053, 0.057, 0.091, 0.025, 0.1, 0.073, 0.141, 0.167,
## 0.085, 0.082, 0.022, 0.078, 0.373, 0.089, 0.142, 0.034, 0.147,
## 0.055, 0.167, 0.106, 0.15, 0.27, 0.078, 0.308, 0.042, 0.101,
## 0.073, 0.132, 0.02, 0.161, 0.078, 0.143, 0.053, 0.09, 0.016,
## 0.028, 0.074, 0.037, 0.152, 0.093, 0.135, 0.025, 0.082, 0.041,
## 0.089, 0.1, 0.056, 0.06, 0.182, 0.034, 0.047, 0.041, 0.089, 0.089,
## 0.04, 0.31, 0.004, 0.343, 0.113, 0.076, 0.11, 0.05, 0.086, 0.085,
## 0.035, 0.086, 0.118, 0.01, 0.064, 0.047, 0.056, 0.151, 0.1, 0.072,
## 0.03, 0.24, 0.054, 0.093, 0.164, 0.006, 0.098, 0.411, 0.039,
## 0.052, 0.014, 0.38, 0.064, 0.226, 0.182, 0.034, 0.127, 0.062,
## 0.144, 0.038, 0.045, 0.036, 0.005, 0.265, 0.06, 0.024, 0.102,
## 0.138, 0.125, 0.278, 0.183, 0, 0.087, 0.055, 0.079, 0.087, 0.056,
## 0.041, 0.027, 0.164, 0.08, 0.088, 0.298, 0.066, 0.077, 0.093),
## hdi = c(0.922, 0.798, 0.628, 0.931, 0.388, 0.496, 0.797,
## 0.766, 0.564, 0.698, 0.685, 0.515, 0.889, 0.662, 0.959, 0.598,
## 0.824, 0.815, 0.555, 0.741, 0.524, 0.853, 0.862, 0.404, 0.603,
## 0.939, 0.895, 0.776, 0.789, 0.9, 0.87, 0.905, 0.416, 0.685,
## 0.522, 0.582, 0.807, 0.728, 0.678, 0.588, 0.721, 0.55, 0.695,
## 0.89, 0.919, 0.56, 0.622, 0.731, 0.878, 0.582, 0.94, 0.908,
## 0.776, 0.913, 0.517, 0.695, 0.628, 0.949, 0.845, 0.97, 0.459,
## 0.71, 0.554, 0.906, 0.786, 0.571, 0.414, 0.5, 0.972, 0.779,
## 0.811, 0.709, 0.937, 0.924, 0.497, 0.53, 0.915, 0.74, 0.839,
## 0.833, 0.844, 0.804, 0.544, 0.578, 0.833, 0.419, 0.88, 0.938,
## 0.889, 0.93, 0.789, 0.788, 0.706, 0.606, 0.691, 0.747, 0.467,
## 0.915, 0.845, 0.959, 0.806, 0.819, 0.419, 0.493, 0.799, 0.946,
## 0.92, 0.785, 0.595, 0.746, 0.918, 0.777, 0.665, 0.487, 0.81,
## 0.617, 0.756, 0.563, 0.955, 0.674, 0.47, 0.649)), row.names = c(14L,
## 50L, 118L, 43L, 153L, 151L, 90L, 91L, 146L, 92L, 137L, 99L, 72L,
## 26L, 7L, 143L, 78L, 81L, 150L, 103L, 117L, 76L, 32L, 109L, 139L,
## 9L, 41L, 74L, 23L, 27L, 60L, 53L, 129L, 122L, 124L, 96L, 38L,
## 89L, 34L, 93L, 69L, 141L, 132L, 63L, 13L, 82L, 97L, 145L, 25L,
## 133L, 21L, 79L, 127L, 47L, 147L, 123L, 95L, 16L, 94L, 6L, 112L,
## 86L, 144L, 39L, 31L, 136L, 152L, 115L, 4L, 130L, 113L, 105L,
## 52L, 22L, 131L, 108L, 35L, 40L, 30L, 12L, 116L, 75L, 64L, 149L,
## 67L, 125L, 37L, 8L, 51L, 10L, 87L, 42L, 44L, 106L, 71L, 80L,
## 126L, 20L, 46L, 17L, 55L, 77L, 111L, 120L, 114L, 15L, 24L, 68L,
## 135L, 121L, 29L, 48L, 110L, 140L, 104L, 102L, 61L, 119L, 5L,
## 107L, 148L, 100L), class = "data.frame"), type = "eps-regression",
## kernel = structure(1L, levels = c("linear", "radial"), class = "factor"),
## cost = 1, epsilon = 0.1, scale = TRUE)
##
##
## Parameters:
## SVM-Type: eps-regression
## SVM-Kernel: linear
## cost: 1
## gamma: 0.1666667
## epsilon: 0.1
##
##
## Number of Support Vectors: 81
Jumlah support vectors pada model terbaik adalah 78 observasi. Nilai ini lebih sedikit dibandingkan model linear baseline yang menggunakan 102 support vectors. Namun, kualitas model tetap ditentukan berdasarkan kemampuan prediksi dan hasil evaluasi, bukan hanya jumlah support vectors.
# Prediksi menggunakan model terbaik
pred_best <- predict(
best_fit,
newdata = test_hdi
)
# Membandingkan tiga model
result_hdi <- rbind(
data.frame(
Model = "SVR Linear Baseline",
t(metrik_svr(test_hdi$hdi, pred_linear))
),
data.frame(
Model = "SVR Radial Baseline",
t(metrik_svr(test_hdi$hdi, pred_radial))
),
data.frame(
Model = "SVR Terbaik (Tuned 5-Fold & 10-Fold)",
t(metrik_svr(test_hdi$hdi, pred_best))
)
)
# Menampilkan hasil
kable(
result_hdi,
digits = 4,
caption = "Perbandingan Kinerja Model SVR pada Testing Set"
)| Model | MAE | RMSE | R2 |
|---|---|---|---|
| SVR Linear Baseline | 0.0286 | 0.0372 | 0.9213 |
| SVR Radial Baseline | 0.0312 | 0.0384 | 0.9163 |
| SVR Terbaik (Tuned 5-Fold & 10-Fold) | 0.0287 | 0.0366 | 0.9241 |
Berdasarkan hasil evaluasi pada testing set, SVR Terbaik (Tuned 5-Fold & 10-Fold) menunjukkan kinerja terbaik dibandingkan kedua model baseline. Model ini menghasilkan nilai RMSE terendah sebesar 0,0366 dan nilai \(R^2\) tertinggi sebesar 0,9241. Artinya, model mampu menjelaskan sekitar 92,41% variasi nilai HDI pada data testing.
Meskipun nilai MAE model tuned (0,0287) sedikit lebih tinggi dibandingkan SVR Linear Baseline (0,0286), model tuned tetap unggul dari segi RMSE dan \(R^2\). Dengan demikian, SVR Terbaik hasil tuning dipilih sebagai model final karena secara keseluruhan memberikan hasil prediksi yang lebih baik pada data testing dibandingkan model baseline.
plot_hdi <- data.frame(
Aktual = test_hdi$hdi,
Prediksi = as.numeric(pred_best)
)
ggplot(
plot_hdi,
aes(x = Aktual, y = Prediksi)
) +
geom_point(
color = "steelblue",
size = 2.5
) +
geom_abline(
intercept = 0,
slope = 1,
linetype = "dashed",
color = "red"
) +
coord_equal() +
labs(
title = "Perbandingan HDI Aktual dan Prediksi SVR",
subtitle = "Model terbaik berdasarkan 5-Fold dan 10-Fold Cross Validation",
x = "HDI Aktual",
y = "HDI Prediksi"
) +
theme_minimal()
Berdasarkan scatter plot tersebut, titik-titik prediksi HDI sebagian
besar berada di sekitar garis merah putus-putus yang menunjukkan kondisi
prediksi ideal (HDI prediksi = HDI aktual). Hal ini menunjukkan bahwa
model SVR mampu menghasilkan prediksi yang cukup mendekati nilai HDI
sebenarnya. Meskipun masih terdapat beberapa titik yang cukup jauh dari
garis, secara umum hasil prediksi model sudah cukup baik.
Berdasarkan hasil pemodelan Support Vector Regression (SVR), model dengan kernel linear menunjukkan kinerja yang sedikit lebih baik dibandingkan kernel radial pada tahap baseline. Hal ini ditunjukkan oleh nilai MAE, RMSE, dan \(R^2\) yang lebih baik. Selanjutnya, dilakukan optimasi parameter menggunakan 5-Fold dan 10-Fold Cross-Validation. Kedua skema tersebut sama-sama menghasilkan kombinasi terbaik dengan kernel linear, meskipun nilai parameter cost yang diperoleh berbeda.
Setelah dilakukan evaluasi pada testing set, model SVR hasil tuning menggunakan kombinasi 5-Fold dan 10-Fold menghasilkan kinerja terbaik secara keseluruhan, dengan nilai MAE sebesar 0,0287, RMSE sebesar 0,0366, dan \(R^2\) sebesar 0,9241. Nilai tersebut menunjukkan bahwa model mampu menjelaskan sekitar 92,41% variasi nilai HDI pada data testing. Dengan demikian, model SVR hasil tuning dipilih sebagai model final karena memberikan nilai RMSE paling rendah dan \(R^2\) paling tinggi dibandingkan model baseline. Hasil ini menunjukkan bahwa optimasi parameter dapat meningkatkan kemampuan model dalam memprediksi nilai HDI, meskipun peningkatannya relatif kecil.
metrik <- function(y, p) {
stopifnot(length(y)==length(p), all(is.finite(y)), all(is.finite(p)))
sst <- sum((y-mean(y))^2)
c(MAE=mean(abs(y-p)), RMSE=sqrt(mean((y-p)^2)),
R2=if (sst>0) 1-sum((y-p)^2)/sst else NA_real_)
}
fit_nn <- function(d, target, prediktor, size=3, decay=.01, seed=2026) {
x <- as.matrix(d[, prediktor, drop=FALSE])
y <- d[[target]]
mu <- colMeans(x)
sx <- apply(x, 2, sd)
sx[!is.finite(sx) | sx==0] <- 1
my <- mean(y); sy <- sd(y)
if (!is.finite(sy) || sy==0) stop("Respons latih harus bervariasi.")
xs <- sweep(sweep(x, 2, mu, "-"), 2, sx, "/")
set.seed(seed)
model <- nnet::nnet(x=xs, y=(y-my)/sy, size=size, decay=decay,
linout=TRUE, maxit=2000, trace=FALSE, MaxNWts=10000)
list(model=model, prediktor=prediktor, mu=mu, sx=sx, my=my, sy=sy)
}
pred_nn <- function(obj, baru) {
x <- as.matrix(baru[, obj$prediktor, drop=FALSE])
xs <- sweep(sweep(x, 2, obj$mu, "-"), 2, obj$sx, "/")
as.numeric(predict(obj$model, xs))*obj$sy + obj$my
}Seperti pada modul SVR, kita membagi data menjadi 80% data latih dan
20% data uji dengan seed = 123. Pembagian ini menghasilkan
kelompok negara yang sama jika isi, urutan, dan penyaringan datanya juga
sama. Agar hasil kedua model bisa dibandingkan secara langsung, gunakan
kembali indeks data latih dan data uji dari modul SVR. Pilih model akhir
melalui cross-validation pada data latih, lalu gunakan data uji
untuk mengevaluasi model terpilih.
# Pembagian data testing & data training (80:20)
set.seed(123)
idx <- sample(seq_len(nrow(hdi)), floor(.8*nrow(hdi))) #(.8*nrow(hdi) untuk hitung banyak baris yg diambil untuk data latih) tl'dr idx berisi nomor baris yang terpilih menjadi data latih.
latih <- hdi[idx, , drop=FALSE] # yg jadi data latih (training)
uji <- hdi[-idx, , drop=FALSE] # yg jadi data uji (testing)
# Pembagian data testing jadi 5 fold cross validation
# 80% dibagi 5
set.seed(123)
fold <- sample(rep(1:5, length.out=nrow(latih)))
cat("Latih:", nrow(latih), "| Uji:", nrow(uji), "\n")## Latih: 122 | Uji: 31
Kita membandingkan model dengan 2 dan 6 prediktor menggunakan pembagian fold yang sama. Pada setiap fold, parameter standardisasi prediktor dan respons dihitung dari bagian training, lalu digunakan untuk mentransformasi bagian validasi. Setiap konfigurasi dilatih tiga kali dengan bobot awal yang berbeda, kemudian ketiga prediksinya dirata-ratakan. Cara yang sama digunakan untuk model akhir. Nilai seed ditetapkan sejak awal agar hasilnya dapat direproduksi.
kelompok <- list(dua=c("gdp", "health"), enam=aman)
grid <- expand.grid(kelompok=c("dua", "enam"), size=c(2, 4, 6), # jumlah neuron pd hiddenlayer
decay=c(.001, .01, .1), #decay mengendalikan besar bobot
stringsAsFactors=FALSE)
grid$CV_RMSE <- NA_real_
grid$Belum_konvergen <- 0L
# Pengujian konfigurasi
for (g in seq_len(nrow(grid))) {
pred_oof <- rep(NA_real_, nrow(latih)) #prediksi yang disimpan adalah prediksi terhadap data yang sedang menjadi bagian validasi, bukan data yang digunakan untuk training.
# 5 fold cross validation
for (k in 1:5) {
a <- latih[fold!=k, , drop=FALSE] #training
b <- latih[fold==k, , drop=FALSE] #validasi
fits <- lapply(1:3, function(s)
fit_nn(a, "hdi", kelompok[[grid$kelompok[g]]],
size=grid$size[g], decay=grid$decay[g], seed=1000*k+s))
grid$Belum_konvergen[g] <- grid$Belum_konvergen[g] +
sum(vapply(fits, function(z) z$model$convergence!=0, logical(1)))
pp <- vapply(fits, function(z) pred_nn(z, b), numeric(nrow(b)))
pred_oof[fold==k] <- rowMeans(pp)
}
grid$CV_RMSE[g] <- sqrt(mean((latih$hdi-pred_oof)^2))
}grid <- grid[order(grid$CV_RMSE), ]
knitr::kable(grid, digits=4, row.names=FALSE,
caption="RMSE out-of-fold gabungan; seluruh prediksi dari fold validasi")| kelompok | size | decay | CV_RMSE | Belum_konvergen |
|---|---|---|---|---|
| dua | 2 | 0.010 | 0.0393 | 0 |
| dua | 2 | 0.001 | 0.0394 | 0 |
| dua | 2 | 0.100 | 0.0398 | 0 |
| dua | 4 | 0.010 | 0.0398 | 0 |
| dua | 6 | 0.010 | 0.0398 | 0 |
| dua | 4 | 0.100 | 0.0400 | 0 |
| dua | 6 | 0.100 | 0.0403 | 0 |
| enam | 6 | 0.100 | 0.0407 | 0 |
| enam | 4 | 0.100 | 0.0407 | 0 |
| dua | 6 | 0.001 | 0.0411 | 0 |
| enam | 2 | 0.010 | 0.0413 | 0 |
| enam | 2 | 0.100 | 0.0421 | 0 |
| enam | 2 | 0.001 | 0.0426 | 0 |
| dua | 4 | 0.001 | 0.0430 | 0 |
| enam | 4 | 0.010 | 0.0456 | 0 |
| enam | 6 | 0.010 | 0.0528 | 0 |
| enam | 6 | 0.001 | 0.0531 | 0 |
| enam | 4 | 0.001 | 0.0537 | 0 |
if (any(grid$Belum_konvergen>0))
warning("Ada fit CV belum konvergen. Periksa tabel sebelum menerima hasil tuning.")
best <- grid[1, , drop=FALSE]
knitr::kable(best, digits=4, caption="Konfigurasi terpilih melalui CV")| kelompok | size | decay | CV_RMSE | Belum_konvergen | |
|---|---|---|---|---|---|
| 7 | dua | 2 | 0.01 | 0.0393 | 0 |
Pada tahap cross-validation (CV), kita melatih 270 jaringan. Setiap satu dari 18 konfigurasi dicoba pada lima fold, dengan tiga set bobot awal pada tiap fold.
Konfigurasi dengan RMSE CV terendah menentukan kelompok prediktor, jumlah neuron, dan besarnya penalti.
if (best$Belum_konvergen>0)
stop("Konfigurasi terpilih belum konvergen. Naikkan maxit dalam fit_nn lalu ulangi CV.")
fit_final <- lapply(1:3, function(s)
fit_nn(latih, "hdi", kelompok[[best$kelompok]],
size=best$size, decay=best$decay, seed=9000+s))
if (any(vapply(fit_final, function(z) z$model$convergence!=0, logical(1))))
stop("Fit final belum konvergen. Periksa optimisasi sebelum evaluasi uji.")DNN menggunakan enam prediktor dengan pembagian data latih
(training), data uji (testing), dan fold yang sama seperti pada
percobaan NN. Kita membandingkan dua arsitektur, yaitu
6–8–4–1 dengan 97 parameter dan 6–8–4–2–1
dengan 105 parameter (8, 4 & 2yaitu hidden layer 1, 2, & 3).
fit_dnn <- function(d, target, prediktor, hidden=c(8L,4L),
lambda=.01, epochs=500L, lr=.01, seed=2026) {
stopifnot(length(hidden)>=1, all(hidden>=1), epochs>=1, lr>0, lambda>=0)
x <- as.matrix(d[, prediktor, drop=FALSE]); y <- d[[target]]
mu <- colMeans(x); sx <- apply(x, 2, sd)
sx[!is.finite(sx) | sx==0] <- 1
my <- mean(y); sy <- sd(y)
if (!is.finite(sy) || sy==0) stop("Respons latih harus bervariasi.")
x <- sweep(sweep(x, 2, mu, "-"), 2, sx, "/")
y <- matrix((y-my)/sy, ncol=1)
dims <- c(ncol(x), as.integer(hidden), 1L)
L <- length(dims)-1L; n <- nrow(x)
set.seed(seed)
# Inisialisasi Xavier untuk aktivasi tanh.
W <- lapply(seq_len(L), function(l) {
batas <- sqrt(6/(dims[l]+dims[l+1]))
matrix(runif(dims[l]*dims[l+1], -batas, batas), dims[l], dims[l+1])
})
b <- lapply(seq_len(L), function(l) matrix(0, 1, dims[l+1]))
mW <- vW <- lapply(W, function(z) z*0)
mb <- vb <- lapply(b, function(z) z*0)
history <- data.frame(epoch=seq_len(epochs), MSE=NA_real_, Loss=NA_real_)
beta1 <- .9; beta2 <- .999; eps <- 1e-8
for (tt in seq_len(epochs)) {
A <- vector("list", L+1L); A[[1]] <- x
for (l in seq_len(L)) {
z <- sweep(A[[l]] %*% W[[l]], 2, as.numeric(b[[l]]), "+")
A[[l+1L]] <- if (l<L) tanh(z) else z
}
err <- A[[L+1L]]-y
history$MSE[tt] <- mean(err^2)
history$Loss[tt] <- mean(err^2)+lambda*sum(vapply(W, function(z) sum(z^2), numeric(1)))
if (!is.finite(history$Loss[tt])) stop("Loss tidak finite; periksa input atau turunkan lr.")
delta <- 2*err/n
gW <- gb <- vector("list", L)
for (l in rev(seq_len(L))) {
gW[[l]] <- crossprod(A[[l]], delta)+2*lambda*W[[l]]
gb[[l]] <- matrix(colSums(delta), nrow=1)
if (l>1L) delta <- (delta %*% t(W[[l]]))*(1-A[[l]]^2)
}
# Semua gradien dihitung sebelum bobot diperbarui.
for (l in seq_len(L)) {
mW[[l]] <- beta1*mW[[l]]+(1-beta1)*gW[[l]]
vW[[l]] <- beta2*vW[[l]]+(1-beta2)*gW[[l]]^2
mb[[l]] <- beta1*mb[[l]]+(1-beta1)*gb[[l]]
vb[[l]] <- beta2*vb[[l]]+(1-beta2)*gb[[l]]^2
W[[l]] <- W[[l]]-lr*(mW[[l]]/(1-beta1^tt))/(sqrt(vW[[l]]/(1-beta2^tt))+eps)
b[[l]] <- b[[l]]-lr*(mb[[l]]/(1-beta1^tt))/(sqrt(vb[[l]]/(1-beta2^tt))+eps)
}
}
list(W=W, b=b, prediktor=prediktor, mu=mu, sx=sx, my=my, sy=sy,
hidden=hidden, lambda=lambda, epochs=epochs, lr=lr, history=history,
n_parameter=sum(vapply(W, length, integer(1)))+
sum(vapply(b, length, integer(1))))
}
pred_dnn <- function(obj, baru) {
a <- as.matrix(baru[, obj$prediktor, drop=FALSE])
a <- sweep(sweep(a, 2, obj$mu, "-"), 2, obj$sx, "/")
L <- length(obj$W)
for (l in seq_len(L)) {
a <- sweep(a %*% obj$W[[l]], 2, as.numeric(obj$b[[l]]), "+")
if (l<L) a <- tanh(a)
}
as.numeric(a)*obj$sy+obj$my
}arsitektur <- list(dua_hidden=c(8L,4L), tiga_hidden=c(8L,4L,2L))
grid_dnn <- expand.grid(arsitektur=names(arsitektur), lambda=c(.001,.01),
epochs=c(300L,800L), stringsAsFactors=FALSE)
grid_dnn$CV_RMSE <- NA_real_
for (g in seq_len(nrow(grid_dnn))) {
oof <- rep(NA_real_, nrow(latih))
for (k in 1:5) {
a <- latih[fold!=k, , drop=FALSE]; b <- latih[fold==k, , drop=FALSE]
fits <- lapply(1:3, function(ss)
fit_dnn(a, "hdi", aman, hidden=arsitektur[[grid_dnn$arsitektur[g]]],
lambda=grid_dnn$lambda[g], epochs=grid_dnn$epochs[g],
lr=.01, seed=1000*k+ss))
oof[fold==k] <- rowMeans(vapply(fits, function(z) pred_dnn(z,b), numeric(nrow(b))))
}
grid_dnn$CV_RMSE[g] <- sqrt(mean((latih$hdi-oof)^2))
}
grid_dnn <- grid_dnn[order(grid_dnn$CV_RMSE), ]
best_dnn <- grid_dnn[1, , drop=FALSE]
knitr::kable(grid_dnn, digits=4, row.names=FALSE,
caption="DNN: pemilihan konfigurasi hanya melalui training CV")| arsitektur | lambda | epochs | CV_RMSE |
|---|---|---|---|
| dua_hidden | 0.010 | 300 | 0.0423 |
| dua_hidden | 0.010 | 800 | 0.0426 |
| tiga_hidden | 0.010 | 300 | 0.0437 |
| tiga_hidden | 0.010 | 800 | 0.0440 |
| dua_hidden | 0.001 | 300 | 0.0442 |
| tiga_hidden | 0.001 | 300 | 0.0491 |
| dua_hidden | 0.001 | 800 | 0.0505 |
| tiga_hidden | 0.001 | 800 | 0.0548 |
keluarga_cv <- data.frame(Model=c("Shallow NN", "Deep NN"),
CV_RMSE=c(best$CV_RMSE, best_dnn$CV_RMSE))
knitr::kable(keluarga_cv, digits=4)| Model | CV_RMSE |
|---|---|
| Shallow NN | 0.0393 |
| Deep NN | 0.0423 |
## Keluarga terpilih berdasarkan CV: Shallow NN
p_nn <- rowMeans(vapply(fit_final, function(z) pred_nn(z, uji), numeric(nrow(uji))))
fit_deep <- lapply(1:3, function(ss)
fit_dnn(latih, "hdi", aman, hidden=arsitektur[[best_dnn$arsitektur]],
lambda=best_dnn$lambda, epochs=best_dnn$epochs, lr=.01, seed=9000+ss))
p_deep <- rowMeans(vapply(fit_deep, function(z) pred_dnn(z, uji), numeric(nrow(uji))))plot_hdi <- data.frame(Aktual=uji$hdi, Prediksi=p_nn, Residual=uji$hdi-p_nn)
ggplot(plot_hdi, aes(Aktual, Prediksi)) +
geom_point(color="#176b87", size=2.5) +
geom_abline(slope=1, intercept=0, linetype=2) + coord_equal() +
labs(title="HDI aktual vs prediksi NN pada test set",
subtitle="Garis putus-putus menunjukkan prediksi sempurna") + theme_minimal()ggplot(plot_hdi, aes(Prediksi, Residual)) +
geom_point(color="#b85c38", size=2.5) + geom_hline(yintercept=0, linetype=2) +
labs(title="Residual pada test set", y="Aktual − prediksi") + theme_minimal()## Prediksi di luar [0,1]: 1
Pada grafik pertama, semakin dekat titik ke garis diagonal, semakin dekat prediksi HDI dengan nilai aktualnya. Titik di atas garis menunjukkan bahwa model memprediksi HDI terlalu tinggi.
Pada grafik residual, nilai positif berarti HDI aktual lebih tinggi daripada prediksi. Jika titik membentuk pola melengkung, model mungkin belum menangkap pola hubungan dalam data. Jika sebarannya makin lebar, besar kesalahan prediksi mungkin berbeda pada tiap kisaran HDI. Titik yang menyebar acak di sekitar nol menunjukkan bahwa grafik ini tidak memperlihatkan pola kesalahan yang jelas.
banding_plot <- rbind(
data.frame(Aktual=uji$hdi, Prediksi=p_nn, Model="Shallow NN"),
data.frame(Aktual=uji$hdi, Prediksi=p_deep, Model="Deep NN"))
ggplot(banding_plot, aes(Aktual, Prediksi)) + geom_point(color="#176b87") +
geom_abline(slope=1, intercept=0, linetype=2) + facet_wrap(~Model) +
coord_equal() + labs(title="NN dan DNN pada test set HDI yang sama") + theme_minimal()ggplot(fit_deep[[1]]$history, aes(epoch, Loss)) + geom_line(color="#7c3aed") +
labs(title="Loss latih anggota pertama ensemble DNN") + theme_minimal()cat("Parameter per DNN:", fit_deep[[1]]$n_parameter,
"| Prediksi DNN di luar [0,1]:", sum(p_deep<0 | p_deep>1), "\n")## Parameter per DNN: 97 | Prediksi DNN di luar [0,1]: 0
Berdasarkan hasil pengujian, Shallow NN memperoleh performa lebih baik dibandingkan Deep NN berdasarkan nilai Cross Validation RMSE, yaitu sebesar 0,0393, sedangkan Deep NN sebesar 0,0423. Konfigurasi terbaik Shallow NN menggunakan 2 neuron dengan decay 0,01, sedangkan Deep NN menggunakan arsitektur 6–8–4–1 dengan lambda 0,01 dan 300 epoch. Hasil ini menunjukkan bahwa jaringan yang lebih sederhana mampu memberikan kesalahan prediksi lebih rendah dibandingkan jaringan yang lebih kompleks pada percobaan ini. Dengan demikian, Shallow NN menjadi model regresi terbaik berdasarkan nilai Cross Validation.
# Menggunakan pembagian data yang sama dengan SVM
latih_cls <- train_raw
uji_cls <- test_raw
# Menggunakan daftar prediktor yang sama dengan SVM
prediktor_cls <- predictors
# Memastikan urutan kategori sesuai dengan fungsi NN klasifikasi
latih_cls$hdi_class <- factor(
latih_cls$hdi_class,
levels = c("Rendah", "Tinggi")
)
uji_cls$hdi_class <- factor(
uji_cls$hdi_class,
levels = c("Rendah", "Tinggi")
)
# Memeriksa data
str(latih_cls)## 'data.frame': 122 obs. of 8 variables:
## $ hdi : num 0.645 0.544 0.691 0.698 0.588 0.628 0.582 0.622 0.515 0.649 ...
## $ GDP : num 0.642 0.677 0.493 0.813 0.549 0.611 0.569 0.446 0.393 0.673 ...
## $ SocialSupport: num 1.236 0.886 1.098 1.321 0.91 ...
## $ HealthyLife : num 0.828 0.535 0.718 0.604 0.331 0.486 0.232 0.677 0.397 0.508 ...
## $ Freedom : num 0.507 0.313 0.389 0.457 0.381 0.381 0.352 0.439 0.349 0.372 ...
## $ Generosity : num 0.246 0.22 0.23 0.37 0.187 0.245 0.154 0.285 0.175 0.105 ...
## $ Corruption : num 0.078 0.098 0.144 0.167 0.037 0.04 0.09 0.089 0.082 0.093 ...
## $ hdi_class : Factor w/ 2 levels "Rendah","Tinggi": 1 1 1 1 1 1 1 1 1 1 ...
##
## Rendah Tinggi
## 43 79
##
## Rendah Tinggi
## 11 20
Pada regresi, fungsi fit_nn() menggunakan output linear karena target yang diprediksi berupa angka kontinu. Untuk klasifikasi, targetnya berupa faktor dengan dua kategori, yaitu Rendah dan Tinggi.
Package nnet dapat menangani respons kategorik. Model menghasilkan prediksi kelas berdasarkan probabilitas kelas yang dipelajari selama pelatihan.
Kita membuat fungsi fit_nn_cls() dan pred_nn_cls() agar proses pelatihan dan prediksi klasifikasi terpisah dari fungsi regresi sebelumnya.
fit_nn_cls <- function(d, prediktor, size=3, decay=.01, seed=2026) {
x <- as.matrix(d[, prediktor, drop=FALSE])
mu <- colMeans(x)
sx <- apply(x, 2, sd)
sx[!is.finite(sx) | sx==0] <- 1
xs <- sweep(sweep(x, 2, mu, "-"), 2, sx, "/")
data_model <- as.data.frame(xs)
data_model$hdi_class <- factor(d$hdi_class,
levels=c("Rendah", "Tinggi"))
set.seed(seed)
model <- nnet::nnet(
hdi_class ~ ., data=data_model,
size=size, decay=decay,
maxit=2000, trace=FALSE, MaxNWts=10000
)
list(model=model, prediktor=prediktor, mu=mu, sx=sx)
}
pred_nn_cls <- function(obj, baru) {
x <- as.matrix(baru[, obj$prediktor, drop=FALSE])
xs <- sweep(sweep(x, 2, obj$mu, "-"), 2, obj$sx, "/")
data_pred <- as.data.frame(xs)
factor(
predict(obj$model, newdata=data_pred, type="class"),
levels=c("Rendah", "Tinggi")
)
}Kinerja model klasifikasi dinilai menggunakan confusion matrix, accuracy, precision, recall, dan F1-score. Kategori Tinggi digunakan sebagai kelas positif.
evaluasi_cls <- function(aktual, prediksi) {
cm <- table(
Aktual=factor(aktual, levels=c("Rendah", "Tinggi")),
Prediksi=factor(prediksi, levels=c("Rendah", "Tinggi"))
)
TN <- cm["Rendah", "Rendah"]
FP <- cm["Rendah", "Tinggi"]
FN <- cm["Tinggi", "Rendah"]
TP <- cm["Tinggi", "Tinggi"]
accuracy <- (TP+TN)/sum(cm)
precision <- if (TP+FP == 0) 0 else TP/(TP+FP)
recall <- if (TP+FN == 0) 0 else TP/(TP+FN)
f1 <- if (precision+recall == 0) 0 else
2*precision*recall/(precision+recall)
list(
confusion_matrix=cm,
metrik=data.frame(
Accuracy=accuracy,
Precision=precision,
Recall=recall,
F1_Score=f1
)
)
}Seperti pada regresi, kita membandingkan 5-fold dan 10-fold CV. Setiap fold digunakan bergantian sebagai data validasi, sedangkan fold lainnya menjadi data training.
buat_fold_cls <- function(y, k) {
if (any(table(y) < k))
stop("Jumlah observasi pada salah satu kelas kurang dari jumlah fold.")
fold <- integer(length(y))
for (kelas in levels(y)) {
idx <- which(y == kelas)
fold[idx] <- sample(rep(1:k, length.out=length(idx)))
}
fold
}
set.seed(123)
fold5_cls <- buat_fold_cls(latih_cls$hdi_class, 5)
set.seed(123)
fold10_cls <- buat_fold_cls(latih_cls$hdi_class, 10)
table(Fold=fold5_cls, Kategori=latih_cls$hdi_class)## Kategori
## Fold Rendah Tinggi
## 1 9 16
## 2 9 16
## 3 9 16
## 4 8 16
## 5 8 15
## Kategori
## Fold Rendah Tinggi
## 1 5 8
## 2 5 8
## 3 5 8
## 4 4 8
## 5 4 8
## 6 4 8
## 7 4 8
## 8 4 8
## 9 4 8
## 10 4 7
Fungsi berikut menjalankan proses pelatihan dan validasi untuk setiap fold. Hasil evaluasi dari seluruh fold kemudian dirata-ratakan untuk memperoleh nilai kinerja CV
cv_nn_cls <- function(d, prediktor, fold, k, size, decay) {
hasil_fold <- data.frame()
for (i in 1:k) {
a <- d[fold!=i, , drop=FALSE]
b <- d[fold==i, , drop=FALSE]
model <- fit_nn_cls(
a, prediktor,
size=size, decay=decay,
seed=2026+i
)
prediksi <- pred_nn_cls(model, b)
evaluasi <- evaluasi_cls(b$hdi_class, prediksi)
hasil_fold <- rbind(
hasil_fold,
data.frame(Fold=i, evaluasi$metrik)
)
}
rata_rata <- data.frame(
Accuracy=mean(hasil_fold$Accuracy),
Precision=mean(hasil_fold$Precision),
Recall=mean(hasil_fold$Recall),
F1_Score=mean(hasil_fold$F1_Score)
)
list(hasil_fold=hasil_fold, rata_rata=rata_rata)
}Jumlah neuron pada hidden layer yang diuji adalah 2, 4, dan 6 neuron. Selain itu, digunakan tiga nilai decay, yaitu 0,001; 0,01; dan 0,1.
Dengan demikian, terdapat sembilan kombinasi hyperparameter yang akan dibandingkan menggunakan 5-fold dan 10-fold CV.
grid_cls <- expand.grid(
size=c(2, 4, 6),
decay=c(.001, .01, .1)
)
uji_grid_cls <- function(d, prediktor, fold, k, grid) {
hasil <- data.frame()
for (g in 1:nrow(grid)) {
cv <- cv_nn_cls(
d=d,
prediktor=prediktor,
fold=fold,
k=k,
size=grid$size[g],
decay=grid$decay[g]
)
hasil <- rbind(
hasil,
data.frame(
Neuron=grid$size[g],
Decay=grid$decay[g],
cv$rata_rata
)
)
}
hasil[order(-hasil$F1_Score, -hasil$Accuracy), ]
}
# 5-fold cross-validation
hasil_cv5_cls <- uji_grid_cls(
latih_cls, prediktor_cls,
fold5_cls, 5, grid_cls
)
knitr::kable(
hasil_cv5_cls, digits=4, row.names=FALSE,
caption="Hasil Tuning Neural Network dengan 5-Fold CV"
)| Neuron | Decay | Accuracy | Precision | Recall | F1_Score |
|---|---|---|---|---|---|
| 2 | 0.100 | 0.9513 | 0.9528 | 0.9750 | 0.9632 |
| 4 | 0.100 | 0.9513 | 0.9528 | 0.9750 | 0.9632 |
| 6 | 0.100 | 0.9513 | 0.9528 | 0.9750 | 0.9632 |
| 4 | 0.010 | 0.9506 | 0.9653 | 0.9617 | 0.9624 |
| 4 | 0.001 | 0.9426 | 0.9528 | 0.9617 | 0.9563 |
| 2 | 0.010 | 0.9426 | 0.9528 | 0.9617 | 0.9563 |
| 6 | 0.010 | 0.9426 | 0.9528 | 0.9617 | 0.9563 |
| 6 | 0.001 | 0.9339 | 0.9528 | 0.9483 | 0.9489 |
| 2 | 0.001 | 0.9353 | 0.9653 | 0.9375 | 0.9486 |
# 10-fold cross-validation
hasil_cv10_cls <- uji_grid_cls(
latih_cls, prediktor_cls,
fold10_cls, 10, grid_cls
)
knitr::kable(
hasil_cv10_cls, digits=4, row.names=FALSE,
caption="Hasil Tuning Neural Network dengan 10-Fold CV"
)| Neuron | Decay | Accuracy | Precision | Recall | F1_Score |
|---|---|---|---|---|---|
| 4 | 0.001 | 0.9519 | 0.9542 | 0.9750 | 0.9632 |
| 6 | 0.001 | 0.9519 | 0.9542 | 0.9750 | 0.9632 |
| 4 | 0.100 | 0.9513 | 0.9542 | 0.9750 | 0.9632 |
| 6 | 0.100 | 0.9513 | 0.9542 | 0.9750 | 0.9632 |
| 4 | 0.010 | 0.9436 | 0.9542 | 0.9625 | 0.9565 |
| 6 | 0.010 | 0.9436 | 0.9542 | 0.9625 | 0.9565 |
| 2 | 0.100 | 0.9429 | 0.9542 | 0.9625 | 0.9565 |
| 2 | 0.001 | 0.9429 | 0.9653 | 0.9500 | 0.9557 |
| 2 | 0.010 | 0.9429 | 0.9653 | 0.9500 | 0.9557 |
Konfigurasi dengan F1-score tertinggi menjadi konfigurasi terbaik pada masing-masing CV. Jika terdapat nilai F1-score yang sama, accuracy digunakan sebagai pertimbangan berikutnya.
best_cls_5 <- hasil_cv5_cls[1, , drop=FALSE]
best_cls_10 <- hasil_cv10_cls[1, , drop=FALSE]
perbandingan_best_cls <- rbind(
data.frame(Metode="5-Fold CV", best_cls_5),
data.frame(Metode="10-Fold CV", best_cls_10)
)
knitr::kable(
perbandingan_best_cls,
digits=4,
row.names=FALSE,
caption="Konfigurasi Terbaik Neural Network"
)| Metode | Neuron | Decay | Accuracy | Precision | Recall | F1_Score |
|---|---|---|---|---|---|---|
| 5-Fold CV | 2 | 0.100 | 0.9513 | 0.9528 | 0.975 | 0.9632 |
| 10-Fold CV | 4 | 0.001 | 0.9519 | 0.9542 | 0.975 | 0.9632 |
Setelah konfigurasi terbaik diperoleh, model dilatih kembali menggunakan seluruh data training. Selanjutnya, kedua model diuji menggunakan data testing yang sama.
# Model akhir berdasarkan 5-fold CV
model_cls_5 <- fit_nn_cls(
latih_cls, prediktor_cls,
size=best_cls_5$Neuron,
decay=best_cls_5$Decay,
seed=9001
)
# Model akhir berdasarkan 10-fold CV
model_cls_10 <- fit_nn_cls(
latih_cls, prediktor_cls,
size=best_cls_10$Neuron,
decay=best_cls_10$Decay,
seed=9001
)
# Prediksi data testing
prediksi_cls_5 <- pred_nn_cls(model_cls_5, uji_cls)
prediksi_cls_10 <- pred_nn_cls(model_cls_10, uji_cls)
# Evaluasi model
evaluasi_cls_5 <- evaluasi_cls(
uji_cls$hdi_class, prediksi_cls_5
)
evaluasi_cls_10 <- evaluasi_cls(
uji_cls$hdi_class, prediksi_cls_10
)
# Confusion matrix
knitr::kable(
evaluasi_cls_5$confusion_matrix,
caption="Confusion Matrix NN dengan 5-Fold CV"
)| Rendah | Tinggi | |
|---|---|---|
| Rendah | 9 | 2 |
| Tinggi | 2 | 18 |
| Rendah | Tinggi | |
|---|---|---|
| Rendah | 8 | 3 |
| Tinggi | 2 | 18 |
# Perbandingan metrik data testing
hasil_test_cls <- rbind(
data.frame(
Metode="5-Fold CV",
Neuron=best_cls_5$Neuron,
Decay=best_cls_5$Decay,
evaluasi_cls_5$metrik
),
data.frame(
Metode="10-Fold CV",
Neuron=best_cls_10$Neuron,
Decay=best_cls_10$Decay,
evaluasi_cls_10$metrik
)
)
knitr::kable(
hasil_test_cls,
digits=4,
row.names=FALSE,
caption="Evaluasi NN Klasifikasi pada Data Testing"
)| Metode | Neuron | Decay | Accuracy | Precision | Recall | F1_Score |
|---|---|---|---|---|---|---|
| 5-Fold CV | 2 | 0.100 | 0.8710 | 0.9000 | 0.9 | 0.900 |
| 10-Fold CV | 4 | 0.001 | 0.8387 | 0.8571 | 0.9 | 0.878 |
Tabel ini membandingkan hasil validasi dan hasil pengujian pada data testing. Perlu diingat bahwa nilai CV merupakan rata-rata hasil validasi, sedangkan nilai testing berasal dari data yang tidak digunakan dalam proses tuning.
hasil_perbandingan_cls <- rbind(
data.frame(
Metode="5-Fold CV",
hasil_cv5_cls[1, c("Accuracy", "Precision", "Recall", "F1_Score")]
),
data.frame(
Metode="10-Fold CV",
hasil_cv10_cls[1, c("Accuracy", "Precision", "Recall", "F1_Score")]
),
data.frame(
Metode="Testing 5-Fold",
evaluasi_cls_5$metrik
),
data.frame(
Metode="Testing 10-Fold",
evaluasi_cls_10$metrik
)
)
knitr::kable(
hasil_perbandingan_cls,
digits=4,
row.names=FALSE,
caption="Perbandingan Hasil 5-Fold dan 10-Fold CV"
)| Metode | Accuracy | Precision | Recall | F1_Score |
|---|---|---|---|---|
| 5-Fold CV | 0.9513 | 0.9528 | 0.975 | 0.9632 |
| 10-Fold CV | 0.9519 | 0.9542 | 0.975 | 0.9632 |
| Testing 5-Fold | 0.8710 | 0.9000 | 0.900 | 0.9000 |
| Testing 10-Fold | 0.8387 | 0.8571 | 0.900 | 0.8780 |
dir.create("output", showWarnings=FALSE)
write.csv(
hasil_cv5_cls,
"output/nn_klasifikasi_hdi_cv5.csv",
row.names=FALSE
)
write.csv(
hasil_cv10_cls,
"output/nn_klasifikasi_hdi_cv10.csv",
row.names=FALSE
)
write.csv(
hasil_test_cls,
"output/nn_klasifikasi_hdi_testing.csv",
row.names=FALSE
)
write.csv(
data.frame(
Aktual=uji_cls$hdi_class,
Prediksi_5Fold=prediksi_cls_5,
Prediksi_10Fold=prediksi_cls_10
),
"output/nn_klasifikasi_hdi_prediksi.csv",
row.names=FALSE
)
saveRDS(
list(
model_5fold=model_cls_5,
model_10fold=model_cls_10,
best_5fold=best_cls_5,
best_10fold=best_cls_10,
prediktor=prediktor_cls
),
"output/nn_klasifikasi_hdi_model.rds"
)
cat("Hasil klasifikasi disimpan di folder output.\n")## Hasil klasifikasi disimpan di folder output.
## [1] "data_preprocessed.csv" "dnn_hdi_cv.csv"
## [3] "dnn_hdi_model.rds" "dnn_hdi_prediksi.csv"
## [5] "happiness_2019.csv" "happiness_clean.csv"
## [7] "hdi_wikipedia.csv" "nn_hdi_cv.csv"
## [9] "nn_hdi_metrik.csv" "nn_hdi_model.rds"
## [11] "nn_hdi_prediksi.csv" "nn_klasifikasi_hdi_cv10.csv"
## [13] "nn_klasifikasi_hdi_cv5.csv" "nn_klasifikasi_hdi_model.rds"
## [15] "nn_klasifikasi_hdi_prediksi.csv" "nn_klasifikasi_hdi_testing.csv"
Berdasarkan hasil pengujian, Shallow NN memperoleh performa lebih baik dibandingkan Deep NN berdasarkan nilai Cross Validation RMSE, yaitu sebesar 0,0393, sedangkan Deep NN sebesar 0,0423. Konfigurasi terbaik Shallow NN menggunakan 2 neuron dengan decay 0,01, sedangkan Deep NN menggunakan arsitektur 6–8–4–1 dengan lambda 0,01 dan 300 epoch. Hasil ini menunjukkan bahwa jaringan yang lebih sederhana mampu memberikan kesalahan prediksi lebih rendah dibandingkan jaringan yang lebih kompleks pada percobaan ini. Dengan demikian, Shallow NN menjadi model regresi terbaik berdasarkan nilai Cross Validation.
Berdasarkan hasil percobaan yang telah dilakukan, terdapat empat model yang digunakan, yaitu Support Vector Machine (SVM) untuk klasifikasi, Support Vector Regression (SVR) untuk regresi, Neural Network untuk klasifikasi, dan Neural Network untuk regresi. Keempat model tersebut dibandingkan berdasarkan hasil evaluasi masing-masing untuk mengetahui metode yang memberikan performa terbaik.
Pada permasalahan klasifikasi, SVM memperoleh nilai accuracy sebesar 90.32% dan F1-score sebesar 92.68%. Sementara itu, Neural Network dengan 5-Fold Cross Validation memperoleh accuracy sebesar 87.10% dan F1-score sebesar 90%, sedangkan Neural Network dengan 10-Fold memperoleh accuracy sebesar 83.87% dan F1-score sebesar 87.80%.
Hasil tersebut menunjukkan bahwa SVM memiliki performa klasifikasi terbaik dibandingkan Neural Network berdasarkan hasil pengujian. SVM juga memiliki nilai recall sebesar 95%, yang menunjukkan kemampuan model dalam mengenali kelas positif dengan baik. Dengan demikian, SVM menjadi metode yang lebih unggul untuk permasalahan klasifikasi pada percobaan ini.
hasil_klasifikasi <- data.frame(
Metode = c(
"SVM",
"NN Klasifikasi (5-Fold)",
"NN Klasifikasi (10-Fold)"
),
Accuracy = c(0.9032, 0.8710, 0.8387),
Precision = c(0.9048, 0.9000, 0.8571),
Recall = c(0.9500, 0.9000, 0.9000),
F1_Score = c(0.9268, 0.9000, 0.8780)
)
knitr::kable(
hasil_klasifikasi,
caption = "Perbandingan Performa Metode Klasifikasi",
digits = 4
)| Metode | Accuracy | Precision | Recall | F1_Score |
|---|---|---|---|---|
| SVM | 0.9032 | 0.9048 | 0.95 | 0.9268 |
| NN Klasifikasi (5-Fold) | 0.8710 | 0.9000 | 0.90 | 0.9000 |
| NN Klasifikasi (10-Fold) | 0.8387 | 0.8571 | 0.90 | 0.8780 |
Pada permasalahan regresi, metode SVR Linear hasil tuning memperoleh nilai RMSE sebesar 0.0366 dan R-squared sebesar 0.9241. Hasil tersebut menunjukkan bahwa model mampu menjelaskan sekitar 92.41% variasi data. Meskipun nilai MAE SVR Linear baseline sedikit lebih rendah, yaitu 0.0286, SVR Linear hasil tuning tetap memberikan hasil lebih baik berdasarkan RMSE dan R-squared.
Sementara itu, pada metode Neural Network regresi, model Shallow memperoleh nilai Cross Validation RMSE sebesar 0.0393, lebih rendah dibandingkan model Deep yang memperoleh nilai 0.0423. Hal ini menunjukkan bahwa Shallow Neural Network memberikan performa validasi yang lebih baik dibandingkan Deep Neural Network.
Namun, perbandingan langsung antara SVR dan Neural Network regresi belum dapat dilakukan secara menyeluruh karena hasil evaluasi yang tersedia menggunakan skema pengujian yang berbeda.
hasil_regresi <- data.frame(
Metode = c(
"SVR Linear Baseline",
"SVR Radial Baseline",
"SVR Linear Tuning",
"NN Regresi Shallow",
"NN Regresi Deep"
),
MAE = c(0.0286, 0.0312, 0.0287, NA, NA),
RMSE = c(0.0372, 0.0384, 0.0366, 0.0393, 0.0423),
R_Squared = c(0.9213, 0.9163, 0.9241, NA, NA)
)
knitr::kable(
hasil_regresi,
caption = "Perbandingan Performa Metode Regresi",
digits = 4
)| Metode | MAE | RMSE | R_Squared |
|---|---|---|---|
| SVR Linear Baseline | 0.0286 | 0.0372 | 0.9213 |
| SVR Radial Baseline | 0.0312 | 0.0384 | 0.9163 |
| SVR Linear Tuning | 0.0287 | 0.0366 | 0.9241 |
| NN Regresi Shallow | NA | 0.0393 | NA |
| NN Regresi Deep | NA | 0.0423 | NA |
Berdasarkan keseluruhan hasil percobaan, dapat disimpulkan bahwa metode terbaik bergantung pada jenis permasalahan yang diselesaikan. Untuk permasalahan klasifikasi, SVM menjadi metode terbaik karena menghasilkan accuracy dan F1-score tertinggi dibandingkan Neural Network pada data testing.
Untuk permasalahan regresi, SVR Linear hasil tuning memberikan performa terbaik di antara model SVR yang diuji, dengan nilai RMSE sebesar 0.0366 dan R-squared sebesar 0.9241. Adapun pada Neural Network regresi, model Shallow lebih unggul dibandingkan model Deep berdasarkan nilai Cross Validation RMSE.
Dengan demikian, SVM direkomendasikan untuk permasalahan klasifikasi, sedangkan SVR Linear hasil tuning menjadi pilihan terbaik di antara model SVR untuk regresi. Sementara itu, Shallow Neural Network merupakan konfigurasi Neural Network regresi yang memberikan hasil validasi terbaik. Secara keseluruhan, pemilihan metode perlu disesuaikan dengan jenis permasalahan serta hasil evaluasi model yang diperoleh.