Identitas Penulis

Universitas Negeri Surabaya

Fakultas Matematika dan Ilmu Pengetahuan Alam

S1 Sains Data

Anggota Kelompok:

  1. Naufal Faiz Nugraha (23031554020)
  2. Bagus Febriansyah Pratama (23031554144)
  3. Otniel Glory Joseputra Pribadi (23031554151)

Latar Belakang

Indeks kebahagiaan global merupakan salah satu indikator penting yang digunakan untuk menilai kesejahteraan dan kualitas hidup masyarakat suatu negara. World Happiness Report secara rutin mempublikasikan skor kebahagiaan berdasarkan berbagai faktor penentu seperti Produk Domestik Bruto per kapita (GDP per capita), dukungan sosial (social support), harapan hidup sehat (healthy life expectancy), kebebasan dalam membuat keputusan hidup (freedom to make life choices), kemurahan hati (generosity), serta persepsi terhadap korupsi (perceptions of corruption). Skor kebahagiaan ini bersifat ordinal, mencerminkan tingkat atau peringkat kebahagiaan suatu negara dari perspektif masyarakatnya [1].

Dalam penelitian dan perumusan kebijakan publik, pengembangan model klasifikasi yang akurat terhadap tingkat kebahagiaan menjadi sangat relevan. Model tersebut memungkinkan pemangku kebijakan untuk memahami variabel-variabel sosial-ekonomi yang paling berpengaruh terhadap kesejahteraan masyarakat, serta mengarahkan intervensi secara lebih tepat sasaran.

Sejalan dengan itu, terdapat beberapa pertanyaan kunci yang perlu dijawab dalam kajian ini. Pertama, bagaimana cara mengklasifikasikan tingkat kebahagiaan negara secara otomatis berdasarkan indikator sosial-ekonomi menggunakan metode Linear Discriminant Analysis (LDA) dan Ordinal Logistic Regression (OLR)? Kedua, apakah metode regresi logistik ordinal lebih efektif dibandingkan analisis diskriminan dalam mengklasifikasikan skor kebahagiaan ke dalam kategori rendah, sedang, dan tinggi? Ketiga, sejauh mana pengaruh faktor-faktor seperti GDP per capita, dukungan sosial, harapan hidup sehat, dan persepsi terhadap korupsi terhadap akurasi klasifikasi skor kebahagiaan global?.

Untuk menjawab pertanyaan-pertanyaan tersebut, proyek ini bertujuan untuk mengembangkan model klasifikasi terhadap tingkat kebahagiaan negara berdasarkan data indikator sosial-ekonomi menggunakan dua pendekatan statistik, yaitu analisis diskriminan dan regresi logistik ordinal. Selain itu, proyek ini bertujuan untuk menganalisis kontribusi masing-masing variabel independen dalam memengaruhi klasifikasi skor kebahagiaan ke dalam tiga kategori: rendah, sedang, dan tinggi. Terakhir, proyek ini juga membandingkan performa kedua metode tersebut dengan menggunakan metrik evaluasi seperti akurasi, 95% confidence interval (CI), No Information Rate (NIR), p-value, dan Kappa Score.

Beberapa pendekatan statistik telah digunakan untuk menganalisis skor kebahagiaan secara global, antara lain visualisasi data [2], klasifikasi status negara [3], hingga identifikasi faktor-faktor penyebab utama kebahagiaan [4]. Selain itu, studi terkini menunjukkan bahwa status imigran serta faktor sosial lainnya juga memiliki kontribusi signifikan terhadap tingkat kebahagiaan masyarakat [5].

Dua pendekatan statistik yang populer dalam analisis klasifikasi data ordinal adalah Ordinal Logistic Regression (OLR) dan Linear Discriminant Analysis (LDA). OLR banyak digunakan karena kemampuannya dalam memodelkan probabilitas kumulatif dari variabel target dengan skala ordinal, sedangkan LDA efektif dalam membedakan antar kelompok berdasarkan kombinasi linier dari variabel prediktor dengan asumsi distribusi normal antar kelas dan homogenitas varians [6][7][8][9][10].


1. Data Loading and Understanding

Data Collecting

Data diambil dari World Happiness Report [11] tahun 2024

Load Dataset

data <- read.csv("E:\\Project_Anmul\\whr_2024.csv")
knitr::kable(head(data, 5))
Country.name Score GDPpc Socsup HLE FtMLC Gens PoC
Finland 7.741 1.844 1.572 0.695 0.859 0.142 0.546
Denmark 7.583 1.908 1.520 0.699 0.823 0.204 0.548
Iceland 7.525 1.881 1.617 0.718 0.819 0.258 0.182
Sweden 7.344 1.878 1.501 0.724 0.838 0.221 0.524
Israel 7.341 1.803 1.513 0.740 0.641 0.153 0.193

Data Understanding

str(data)
## 'data.frame':    143 obs. of  8 variables:
##  $ Country.name: chr  "Finland" "Denmark" "Iceland" "Sweden" ...
##  $ Score       : num  7.74 7.58 7.53 7.34 7.34 ...
##  $ GDPpc       : num  1.84 1.91 1.88 1.88 1.8 ...
##  $ Socsup      : num  1.57 1.52 1.62 1.5 1.51 ...
##  $ HLE         : num  0.695 0.699 0.718 0.724 0.74 0.706 0.704 0.708 0.747 0.692 ...
##  $ FtMLC       : num  0.859 0.823 0.819 0.838 0.641 0.725 0.835 0.801 0.759 0.756 ...
##  $ Gens        : num  0.142 0.204 0.258 0.221 0.153 0.247 0.224 0.146 0.173 0.225 ...
##  $ PoC         : num  0.546 0.548 0.182 0.524 0.193 0.372 0.484 0.432 0.498 0.323 ...

Keterangan variabel:

  • GDPpc | GDP per capita: Indikator ekonomi yang menunjukkan pendapatan rata-rata per orang di suatu negara atau wilayah.
  • Socsup | Social support: Bantuan atau dukungan sosial yang diberikan oleh orang lain kepada individu lain, yang bisa berupa dukungan emosional, instrumental, informasi, atau penghargaan.
  • HLE | Healthy life expectancy: Rata-rata jumlah tahun yang diharapkan seseorang untuk hidup dalam kesehatan penuh.
  • FtMLC | Freedom to make life choices: Hak asasi manusia yang memungkinkan seseorang untuk memutuskan bagaimana hidup mereka, termasuk bagaimana membelanjakan uang, membuat keputusan perawatan kesehatan, memilih pekerjaan, dan membangun hubungan.
  • Gens | Generosity: Sifat atau tindakan memberikan sesuatu kepada orang lain tanpa mengharapkan balasan atau keuntungan pribadi.
  • PoC | Perceptions of corruption: Persepsi atau penilaian masyarakat terhadap tingkat korupsi di suatu negara atau wilayah, yang sering diukur melalui survei seperti Indeks Persepsi Korupsi (IPK).

Statistik Deskriptif Data Mentah

summary_rounded <- sapply(data, function(x) {
  if (is.numeric(x)) {
    round(summary(x), 4)
  } else {
    summary(x)
  }
})

print(summary_rounded)
## $Country.name
##    Length     Class      Mode 
##       143 character character 
## 
## $Score
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.721   4.726   5.785   5.528   6.416   7.741 
## 
## $GDPpc
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   0.000   1.078   1.431   1.379   1.742   2.141       3 
## 
## $Socsup
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.0000  0.9218  1.2375  1.1343  1.3832  1.6170       3 
## 
## $HLE
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.0000  0.3980  0.5495  0.5209  0.6485  0.8570       3 
## 
## $FtMLC
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.0000  0.5275  0.6410  0.6206  0.7360  0.8630       3 
## 
## $Gens
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.0000  0.0910  0.1365  0.1463  0.1925  0.4010       3 
## 
## $PoC
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.0000  0.0688  0.1205  0.1541  0.1937  0.5750       3

Cek Dimensi Data

cat("Dimensi data:", dim(data)[1], "baris x", dim(data)[2], "kolom\n")
## Dimensi data: 143 baris x 8 kolom

Cek Missing Values

print("Nilai yang hilang: ")
## [1] "Nilai yang hilang: "
colSums(is.na(data))
## Country.name        Score        GDPpc       Socsup          HLE        FtMLC 
##            0            0            3            3            3            3 
##         Gens          PoC 
##            3            3
cat("Total data yang hilang: ", sum(is.na(data)), "\n")
## Total data yang hilang:  18

Cek Duplikasi

cat("Jumlah duplikasi:", sum(duplicated(data)), "\n")
## Jumlah duplikasi: 0

Cek Nilai Skewness Data

features <- c("Score", "GDPpc", "Socsup", "HLE", "FtMLC", "Gens", "PoC")

numeric_with_na <- data %>%
  dplyr::select(where(is.numeric)) %>%
  dplyr::select(where(~ any(is.na(.))))

skew_df <- data.frame(
  Feature = names(numeric_with_na),
  Skewness = sapply(numeric_with_na, skewness, na.rm = TRUE)
)
print(skew_df)
##        Feature   Skewness
## GDPpc    GDPpc -0.5016776
## Socsup  Socsup -0.9816194
## HLE        HLE -0.5401925
## FtMLC    FtMLC -1.0078842
## Gens      Gens  0.6559284
## PoC        PoC  1.5085388

Distribusi Kelas

h <- hist(data$Score,
          main = "Distribusi Skor Kebahagiaan",
          xlab = "Skor",
          col = "skyblue",
          border = "white")

text(x = h$mids,
     y = h$counts,
     labels = h$counts,
     pos = 3,
     cex = 0.8,
     col = "black")

boxplot(data$Score, main="Boxplot Skor Kebahagiaan", col="lightblue", horizontal=TRUE)

top_10 <- data %>% arrange(desc(Score)) %>% slice_head(n = 10)
cat("10 Negara dengan Skor Kebahagiaan Tertinggi:\n")
## 10 Negara dengan Skor Kebahagiaan Tertinggi:
print(top_10[, c("Country.name", "Score")])
##    Country.name Score
## 1       Finland 7.741
## 2       Denmark 7.583
## 3       Iceland 7.525
## 4        Sweden 7.344
## 5        Israel 7.341
## 6   Netherlands 7.319
## 7        Norway 7.302
## 8    Luxembourg 7.122
## 9   Switzerland 7.060
## 10    Australia 7.057
bottom_10 <- data %>% arrange(Score) %>% slice_head(n = 10)
cat("10 Negara dengan Skor Kebahagiaan Terendah:\n")
## 10 Negara dengan Skor Kebahagiaan Terendah:
print(bottom_10[, c("Country.name", "Score")])
##        Country.name Score
## 1       Afghanistan 1.721
## 2           Lebanon 2.707
## 3           Lesotho 3.186
## 4      Sierra Leone 3.245
## 5  Congo (Kinshasa) 3.295
## 6          Zimbabwe 3.341
## 7          Botswana 3.383
## 8            Malawi 3.421
## 9            Zambia 3.502
## 10         Eswatini 3.502

2. Exploratory Data Analysis

Skewness

plot_list <- lapply(names(numeric_with_na), function(col) {
  ggplot(data, aes_string(x = col)) +
    geom_histogram(aes(y = ..density..), bins = 30, fill = "skyblue", color = "white", alpha = 0.7) +
    geom_density(color = "red", size = 1) +
    labs(title = paste("Distribusi dan Density:", col), x = col, y = "Density") +
    theme_minimal()
})
do.call("grid.arrange", c(plot_list, ncol = 2))

10 Negara dengan Skor Kebahagiaan Tertinggi

ggplot(top_10, aes(x = reorder(Country.name, Score), y = Score)) +
  geom_bar(stat = "identity", fill = "darkgreen") +
  geom_text(aes(label = round(Score, 2)), hjust = -0.1, size = 3) +
  labs(title = "10 Negara dengan Skor Kebahagiaan Tertinggi", x = "Negara", y = "Skor Kebahagiaan") +
  coord_flip() +
  theme_minimal()

10 Negara dengan Skor Kebahagiaan Terendah

ggplot(bottom_10, aes(x = reorder(Country.name, -Score), y = Score)) +
  geom_bar(stat = "identity", fill = "darkred") +
  geom_text(aes(label = round(Score, 2)), hjust = -0.1, size = 3) +
  labs(title = "10 Negara dengan Skor Kebahagiaan Terendah", x = "Negara", y = "Skor Kebahagiaan") +
  coord_flip() +
  theme_minimal()

Kontribusi Faktor pada 5 Negara Teratas

top_5 <- data %>% arrange(desc(Score)) %>% slice_head(n = 5)
top_5_long <- top_5 %>%
  dplyr::select(Country.name, GDPpc, Socsup, HLE, FtMLC, Gens, PoC) %>%
  pivot_longer(cols = -Country.name, names_to = "Factor", values_to = "Value")

ggplot(top_5_long, aes(x = Factor, y = Value, fill = Country.name)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Kontribusi Faktor pada 5 Negara Teratas", x = "Faktor", y = "Nilai") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Untuk melihat faktor-faktor yang berpengaruh pada 5 negara teratas

Outlier

numeric_data <- data %>% dplyr::select(where(is.numeric))

# Tambahkan Country jika tersedia
if ("Country.name" %in% colnames(data)) {
  numeric_data <- cbind(Country.name = data$Country.name, numeric_data)
}

# Ubah ke long format untuk ggplot
numeric_long <- pivot_longer(numeric_data, cols = -Country.name, names_to = "Feature", values_to = "Value")

# Plot boxplot per fitur
ggplot(numeric_long, aes(x = Feature, y = Value)) +
  geom_boxplot(fill = "#69b3a2", outlier.colour = "red", outlier.shape = 16) +
  theme_minimal(base_size = 13) +
  labs(title = "Boxplot Setiap Fitur Numerik", x = "Fitur", y = "Nilai") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))


3. Preprocessing

Handling Missing Values

# Imputasi dengan Median
numeric_cols <- sapply(data, is.numeric)
for (col in names(data)[numeric_cols]) {
  data[[col]][is.na(data[[col]])] <- median(data[[col]], na.rm = TRUE)
  cat("Imputasi median untuk:", col, "\n")
}
## Imputasi median untuk: Score 
## Imputasi median untuk: GDPpc 
## Imputasi median untuk: Socsup 
## Imputasi median untuk: HLE 
## Imputasi median untuk: FtMLC 
## Imputasi median untuk: Gens 
## Imputasi median untuk: PoC
# Cek Missing Values kembali
print("Nilai yang hilang: ")
## [1] "Nilai yang hilang: "
colSums(is.na(data))
## Country.name        Score        GDPpc       Socsup          HLE        FtMLC 
##            0            0            0            0            0            0 
##         Gens          PoC 
##            0            0
cat("Total data yang hilang: ", sum(is.na(data)), "\n")
## Total data yang hilang:  0

Handling Outlier

handle_outliers_iqr <- function(x, multiplier = 1.5) {
  if(sum(!is.na(x)) <= 1) {
    return(x)
  }
  
  q1 <- quantile(x, 0.25, na.rm = TRUE)
  q3 <- quantile(x, 0.75, na.rm = TRUE)
  iqr <- q3 - q1
  
  lower_bound <- q1 - (multiplier * iqr)
  upper_bound <- q3 + (multiplier * iqr)
  
  x[!is.na(x) & x < lower_bound] <- lower_bound
  x[!is.na(x) & x > upper_bound] <- upper_bound
  
  return(x)
}

numeric_columns <- sapply(data, is.numeric)

# Handle jika tidak ada kolom numerik
if(sum(numeric_columns) > 0) {
  for (col in names(data)[numeric_columns]) {
    data[[col]] <- handle_outliers_iqr(data[[col]])
  }
  
  numeric_data <- data %>% dplyr::select(where(is.numeric))
  
  if ("Country.name" %in% colnames(data)) {
    numeric_data <- cbind(Country.name = data$Country.name, numeric_data)
    numeric_long <- pivot_longer(numeric_data, cols = -Country.name, names_to = "Feature", values_to = "Value")
  } else {
    numeric_long <- pivot_longer(numeric_data, cols = everything(), names_to = "Feature", values_to = "Value")
  }
  
  # Plot boxplot per fitur
  ggplot(numeric_long, aes(x = Feature, y = Value)) +
    geom_boxplot(fill = "#69b3a2", outlier.colour = "red", outlier.shape = 16) +
    theme_minimal(base_size = 13) +
    labs(title = "Boxplot Setiap Fitur Numerik (Setelah Penanganan IQR)", x = "Fitur", y = "Nilai") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))
} else {
  print("Dataset tidak memiliki kolom numerik untuk divisualisasikan.")
}

Untuk mengidentifikasi dan menghapus nilai outlier dari data, digunakan metode Interquartile Range (IQR). IQR merupakan selisih antara kuartil ketiga (Q3) dan kuartil pertama (Q1), yang merepresentasikan rentang tengah 50% data. Nilai-nilai yang dianggap outlier adalah data yang berada di bawah Q1 - 1.5×IQR atau di atas Q3 + 1.5×IQR.

Correlation Matrix

correlation_matrix <- cor(data[features])
corrplot(correlation_matrix, method = "color", type = "upper", order = "hclust", 
         tl.col = "black", tl.srt = 45, addCoef.col = "black", number.cex = 0.7,
         title = "Korelasi antar Fitur")

Binning dengan Threshold acuan

data$Happiness_Level <- cut(data$Score, breaks = c(0, 5, 6, Inf),
                            labels = c("Low", "Medium", "High"),
                            include.lowest = TRUE)
data$Happiness_Level <- ordered(data$Happiness_Level, levels = c("Low", "Medium", "High"))

Menggunakan Binning untuk mengubah target dari numerik kontinu ke kategorik. Menggunakan acuan dari hasil penelitian sebelumnya [12]. Setelah dilakukan binning, selanjutnya dilakukan perubahan agar menjadi data ordinal.

Distribusi Kategori Kebahagiaan

table_happiness <- table(data$Happiness_Level)
print(table_happiness)
## 
##    Low Medium   High 
##     46     41     56
barplot(table_happiness, main = "Distribusi Kategori Kebahagiaan", 
        col = c("red", "blue", "green"), xlab = "Kategori", ylab = "Jumlah Negara")

Transformasi Log sesuai nilai Skewed

# Daftar fitur dan nilai skewness
fitur_skew <- c("GDPpc", "Socsup", "HLE", "FtMLC", "Gens", "PoC")
skewness_values <- c(-0.50, -0.98, -0.54, -1.01, 0.66, 1.51)
names(skewness_values) <- fitur_skew

# Transformasi berbasis arah skewness
for (fitur in fitur_skew) {
  nilai <- data[[fitur]]
  if (skewness_values[fitur] > 0) {
    # Positively skewed → log10(x)
    data[[paste0("trans_", fitur)]] <- log10(nilai + 1e-8)  # Hindari log(0)
  } else {
    # Negatively skewed → log10(max(x+1) - x)
    data[[paste0("trans_", fitur)]] <- log10(max(nilai + 1) - nilai + 1e-8)
  }
}

# Cek Variabel baru hasil Transformasi
names(data)
##  [1] "Country.name"    "Score"           "GDPpc"           "Socsup"         
##  [5] "HLE"             "FtMLC"           "Gens"            "PoC"            
##  [9] "Happiness_Level" "trans_GDPpc"     "trans_Socsup"    "trans_HLE"      
## [13] "trans_FtMLC"     "trans_Gens"      "trans_PoC"

Menangani normalitas data dengan trasnformasi log untuk dua kondisi yang berbeda, yaitu nilai skew yang positif dan negatif [13].


4. Uji Asumsi

Untuk Model OLR

Uji Multikolinearitas

vif_model <- lm(as.numeric(Happiness_Level) ~ trans_GDPpc + trans_Socsup + trans_HLE +
                  trans_FtMLC + trans_Gens + trans_PoC, data = data)
vif(vif_model)
##  trans_GDPpc trans_Socsup    trans_HLE  trans_FtMLC   trans_Gens    trans_PoC 
##     4.206114     2.676294     3.718712     1.331593     1.024596     1.065375

VIF (Variance Inflation Factor) digunakan untuk mendeteksi adanya korelasi yang tinggi antar variabel bebas (independent) dalam model regresi.

Uji Hipotesis:

  • H0 : Tidak ada multikolinearitas signifikan antar variabel (VIF <= 5 atau 10).
  • H1 : Terdapat multikolinearitas signifikan antar variabel (VIF > 5 atau 10).

Kriteria Keputusan:

  • Jika semua nilai VIF < 5: Tidak ada indikasi multikolinearitas serius.
  • Jika ada nilai VIF > 5 (moderate) atau > 10 (severe): Ada indikasi multikolinearitas.

Untuk Model LDA

Uji Normalitas Multivariat

# Ambil hanya fitur numerik hasil transformasi
fitur <- data[, c("trans_GDPpc", "trans_Socsup", "trans_HLE",
                  "trans_FtMLC", "trans_Gens", "trans_PoC")]

# Jalankan uji normalitas multivariat Mardia
hasil_mvn <- mvn(data = fitur, mvnTest = "mardia", multivariatePlot = "qq")

# Ambil hasilnya dalam bentuk data frame
hasil_mvn_df <- hasil_mvn$multivariateNormality
print(hasil_mvn_df)
##              Test        Statistic p value Result
## 1 Mardia Skewness 3740.42662773086       0     NO
## 2 Mardia Kurtosis 104.929091737487       0     NO
## 3             MVN             <NA>    <NA>     NO

Mardia digunakan untuk menguji apakah data multivariat terdistribusi normal. Uji ini berbasis pada perhitungan kemiringan (skewness) dan keruncingan (kurtosis) data multivariat.

Uji Hipotesis:

  • H0 : Data mengikuti distribusi normal multivariat.
  • H1 : Data tidak mengikuti distribusi normal multivariat.

Kriteria Keputusan:

  • Jika p-value > 0.05, Terima H0, Data normal.
  • Jika p-value <= 0.05, Tolak H0, Data tidak normal multivariat.

Uji Homogenitas

numeric_vars <- c("trans_GDPpc", "trans_Socsup", "trans_HLE",
                    "trans_FtMLC", "trans_Gens", "trans_PoC")
  
complete_data <- data[, c(numeric_vars, "Happiness_Level")]
  
box_test <- biotools::boxM(complete_data[, numeric_vars], complete_data$Happiness_Level)
cat("\nBox's M Test for Homogeneity of Covariance Matrices:\n")
## 
## Box's M Test for Homogeneity of Covariance Matrices:
print(box_test)
## 
##  Box's M-test for Homogeneity of Covariance Matrices
## 
## data:  complete_data[, numeric_vars]
## Chi-Sq (approx.) = 322.49, df = 42, p-value < 2.2e-16

Box’s M adalah uji statistik yang digunakan untuk menguji asumsi homogenitas varians-kovarians dalam analisis MANOVA (Multivariate Analysis of Variance) atau analisis multivariat lainnya.

Uji Hipotesis:

  • H0 : Matriks kovarian antar kelompok adalah sama (homogen).
  • H1 : Setidaknya satu matriks kovarian antar kelompok berbeda (tidak homogen).

Kriteria Keputusan:

  • Jika p-value > 0.05, Terima H0, Homogen.
  • Jika p-value <= 0.05, Tolak H0, Tidak homogen.

Handle Normalitas Multivariat, Homogenitas

cat("\n===== TRANSFORMASI BOX-COX =====\n")
## 
## ===== TRANSFORMASI BOX-COX =====
# Hanya menggunakan data numerik untuk transformasi
prediktor <- c("trans_GDPpc", "trans_Socsup", "trans_HLE", "trans_FtMLC", "trans_Gens", "trans_PoC")
  
for (var in prediktor) {
    # Menambahkan konstanta untuk memastikan semua nilai positif jika ada nilai negatif
    nilai <- data[[var]]
    if (min(nilai, na.rm = TRUE) <= 0) {
      offset <- abs(min(nilai, na.rm = TRUE)) + 1
      nilai <- nilai + offset
      cat(sprintf("Menambahkan offset %f ke variabel %s untuk memastikan semua nilai positif\n", offset, var))
    }
    
    # Mencari parameter lambda optimal untuk transformasi Box-Cox
    bc <- car::powerTransform(nilai)
    lambda <- bc$lambda
    
    # Menerapkan transformasi Box-Cox
    if (abs(lambda) < 0.01) { # Mendekati 0
      data[[paste0("boxcox_", var)]] <- log(nilai)
      cat(sprintf("Variabel %s: lambda ≈ 0, menerapkan transformasi logaritmik\n", var))
    } else {
      data[[paste0("boxcox_", var)]] <- (nilai^lambda - 1) / lambda
      cat(sprintf("Variabel %s: lambda = %.4f\n", var, lambda))
    }
}
## Variabel trans_GDPpc: lambda = 0.7030
## Variabel trans_Socsup: lambda = 0.4741
## Variabel trans_HLE: lambda = 0.6025
## Variabel trans_FtMLC: lambda = 0.5420
## Menambahkan offset 9.000000 ke variabel trans_Gens untuk memastikan semua nilai positif
## Variabel trans_Gens: lambda = 9.0354
## Menambahkan offset 9.000000 ke variabel trans_PoC untuk memastikan semua nilai positif
## Variabel trans_PoC: lambda = 6.3184
# Cek Variabel baru hasil Transformasi
names(data)
##  [1] "Country.name"        "Score"               "GDPpc"              
##  [4] "Socsup"              "HLE"                 "FtMLC"              
##  [7] "Gens"                "PoC"                 "Happiness_Level"    
## [10] "trans_GDPpc"         "trans_Socsup"        "trans_HLE"          
## [13] "trans_FtMLC"         "trans_Gens"          "trans_PoC"          
## [16] "boxcox_trans_GDPpc"  "boxcox_trans_Socsup" "boxcox_trans_HLE"   
## [19] "boxcox_trans_FtMLC"  "boxcox_trans_Gens"   "boxcox_trans_PoC"

Uji Normalitas Multivariat dan Homogenitas kembali

# Ambil hanya fitur numerik hasil transformasi
fitur <- data[, c("boxcox_trans_GDPpc", "boxcox_trans_Socsup", "boxcox_trans_HLE",
                    "boxcox_trans_FtMLC", "boxcox_trans_Gens", "boxcox_trans_PoC")]

# Jalankan uji normalitas multivariat Mardia
hasil_mvn <- mvn(data = fitur, mvnTest = "mardia", multivariatePlot = "qq")

# Ambil hasilnya dalam bentuk data frame
hasil_mvn_df <- hasil_mvn$multivariateNormality
print(hasil_mvn_df)
##              Test        Statistic              p value Result
## 1 Mardia Skewness 168.470360400258 3.41115253380214e-13     NO
## 2 Mardia Kurtosis 5.33494386042621 9.55741226160711e-08     NO
## 3             MVN             <NA>                 <NA>     NO

Uji Hipotesis:

  • H0 : Data mengikuti distribusi normal multivariat.
  • H1 : Data tidak mengikuti distribusi normal multivariat.

Kriteria Keputusan:

  • Jika p-value > 0.05, Terima H0, Data normal.
  • Jika p-value <= 0.05, Tolak H0, Data tidak normal multivariat.
numeric_vars <- c("boxcox_trans_GDPpc", "boxcox_trans_Socsup", "boxcox_trans_HLE",
                    "boxcox_trans_FtMLC", "boxcox_trans_Gens", "boxcox_trans_PoC")
  
complete_data <- data[, c(numeric_vars, "Happiness_Level")]
  
box_test <- biotools::boxM(complete_data[, numeric_vars], complete_data$Happiness_Level)
cat("\nBox's M Test for Homogeneity of Covariance Matrices:\n")
## 
## Box's M Test for Homogeneity of Covariance Matrices:
print(box_test)
## 
##  Box's M-test for Homogeneity of Covariance Matrices
## 
## data:  complete_data[, numeric_vars]
## Chi-Sq (approx.) = 91.004, df = 42, p-value = 1.79e-05

Uji Hipotesis:

  • H0 : Matriks kovarian antar kelompok adalah sama (homogen).
  • H1 : Setidaknya satu matriks kovarian antar kelompok berbeda (tidak homogen).

Kriteria Keputusan:

  • Jika p-value > 0.05, Terima H0, Homogen.
  • Jika p-value <= 0.05, Tolak H0, Tidak homogen.

5. Feature Selection

Uji Korelasi Spearman antara fitur dan Score

# --- Uji Korelasi Spearman ---
fitur_full <- c("boxcox_trans_GDPpc", "boxcox_trans_Socsup", "boxcox_trans_HLE",
                "boxcox_trans_FtMLC", "boxcox_trans_Gens", "boxcox_trans_PoC")

spearman_test_results <- lapply(fitur_full, function(fitur) {
  result <- cor.test(data[[fitur]], data$Score, method = "spearman", exact = FALSE)
  data.frame(
    Feature = fitur,
    Correlation = round(result$estimate, 4),
    p_value = round(result$p.value, 5)
  )
})

spearman_df <- do.call(rbind, spearman_test_results)

# --- Tambahkan label nama fitur lebih singkat jika perlu ---
spearman_df$Short_Feature <- gsub("boxcox_trans_", "", spearman_df$Feature)

# --- Plot hasil korelasi ---
ggplot(spearman_df, aes(x = reorder(Short_Feature, Correlation), y = Correlation)) +
  geom_bar(stat = "identity", fill = "#69b3a2") +
  geom_text(aes(label = paste0("r = ", Correlation, "\n(p = ", p_value, ")")), 
            vjust = -0.2, size = 3) +
  labs(
    title = "Korelasi Spearman antara Fitur dan Skor Kebahagiaan",
    x = "Fitur",
    y = "Koefisien Korelasi Spearman"
  ) +
  theme_minimal() +
  coord_flip()  # Supaya fitur tampil vertikal

Pemilihan Fitur

# Pemilihan Fitur
fitur <- data %>% dplyr::select(boxcox_trans_GDPpc, boxcox_trans_Socsup, boxcox_trans_HLE, boxcox_trans_FtMLC, boxcox_trans_Gens, boxcox_trans_PoC)

# Feature Scale
fitur_scaled <- scale(fitur)

# Cek Duplikasi setelah Feature Scale
duplicated_rows <- which(duplicated(as.data.frame(fitur_scaled)) | duplicated(as.data.frame(fitur_scaled), fromLast = TRUE))
data[duplicated_rows, c("Country.name", "Happiness_Level")]
##           Country.name Happiness_Level
## 62             Bahrain          Medium
## 88          Tajikistan          Medium
## 103 State of Palestine             Low
# Hapus baris duplikat dari fitur dan data asli
fitur_nodup <- fitur_scaled[-duplicated_rows, ]
data_nodup <- data[-duplicated_rows, ]

# Membuat dataframe
df_model <- cbind(as.data.frame(fitur_nodup), 
                 Happiness_Level = data_nodup$Happiness_Level)

# Tampilan data final
dfinal_head <- cbind("Country.name" = data_nodup$Country.name, "Happiness_Level" = data_nodup$Happiness_Level, as.data.frame(round(fitur_nodup, 4)))
knitr::kable(head(dfinal_head, 5))
Country.name Happiness_Level boxcox_trans_GDPpc boxcox_trans_Socsup boxcox_trans_HLE boxcox_trans_FtMLC boxcox_trans_Gens boxcox_trans_PoC
Finland High -1.1615 -2.1247 -1.1035 -2.4790 0.1058 1.6839
Denmark High -1.4230 -1.5707 -1.1394 -1.6222 0.8411 1.6839
Iceland High -1.3090 -3.4347 -1.3166 -1.5595 1.3812 0.5673
Sweden High -1.2967 -1.4140 -1.3751 -1.8898 1.0193 1.6839
Israel High -1.0083 -1.5110 -1.5376 0.0927 0.2481 0.6502
# Mengubah respons ke faktor
df_model$Happiness_Level <- as.factor(df_model$Happiness_Level)

6. Perceptual Mapping

Mapping MDS

dist_matrix <- dist(fitur_nodup)
mds_result <- cmdscale(dist_matrix, k = 2)

# Hitung jarak asli dan jarak hasil MDS
dist_original <- as.matrix(dist_matrix)
dist_mds <- as.matrix(dist(mds_result))

# Hitung skor stress
stress_numerator <- sum((dist_original - dist_mds)^2)
stress_denominator <- sum(dist_original^2)
stress <- sqrt(stress_numerator / stress_denominator)

# Buat data frame MDS
mds_df <- as.data.frame(mds_result)
colnames(mds_df) <- c("Dim1", "Dim2")
mds_df$Country <- data_nodup$Country.name
mds_df$Happiness_Level <- data_nodup$Happiness_Level

ggplot(mds_df, aes(x = Dim1, y = Dim2, color = Happiness_Level, label = Country)) +
  geom_point(size = 3) +
  geom_text(check_overlap = TRUE, size = 2) +
  theme_minimal() +
  labs(
    title = "MDS Visualization of World Happiness Report",
    subtitle = paste0("Kruskal's Stress-1 = ", round(stress, 4)),
    x = "Dimension 1",
    y = "Dimension 2",
    color = "Happiness Level"
  )

Peta Multidimensi (MDS) menunjukkan hubungan antarnegara berdasarkan tingkat kebahagiaan. Negara-negara seperti Finlandia, Denmark, dan Swiss (kuning) berkumpul di kuadran positif, menunjukkan kebahagiaan tinggi. Negara-negara seperti Afghanistan dan Sierra Leone (ungu) berada di kuadran negatif, menandakan kebahagiaan rendah. Negara-negara “Medium” (hijau) tersebar di antaranya.

Mapping Biplot

pca_model <- prcomp(fitur_nodup, center = TRUE, scale. = TRUE)

# Ubah ukuran plot dan sesuaikan parameter visual
biplot <- ggbiplot(pca_model, 
                  labels = data_nodup$Country.name, 
                  groups = data_nodup$Happiness_Level, 
                  ellipse = TRUE, 
                  circle = TRUE,
                  var.scale = 1,  # Skala untuk variabel
                  varname.size = 4,  # Ukuran teks untuk variabel
                  varname.adjust = 1.5,  # Jarak teks variabel dari panah
                  labels.size = 2.5,  # Ukuran teks label negara
                  ellipse.prob = 0.68) +  # Tingkat kepercayaan ellipse
  theme_minimal(base_size = 12) +  # Ukuran font dasar
  theme(legend.position = "right",
        plot.margin = margin(1, 1, 1, 1, "cm")) +  # Margin plot
  xlim(c(-4, 4)) +  # Batas sumbu x
  ylim(c(-3, 3))   # Batas sumbu y

options(repr.plot.width = 20, repr.plot.height = 20)

# Tampilkan plot
print(biplot)

Analisis Komponen Utama (PCA) menunjukkan kontribusi variabel terhadap variasi data. Variabel seperti GDP per capita (49.5%) dan SocSup memiliki pengaruh kuat pada pemisahan tingkat kebahagiaan. Negara-negara dengan kebahagiaan tinggi (kuning) berkorelasi positif dengan variabel ini, sementara negara dengan kebahagiaan rendah (ungu) menunjukkan korelasi negatif atau lemah.

Statistik Deskriptif Final

summary_rounded <- sapply(df_model, function(x) {
  if (is.numeric(x)) {
    round(summary(x), 4)
  } else {
    summary(x)
  }
})

print(summary_rounded)
## $boxcox_trans_GDPpc
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -3.0143 -0.7955  0.0670 -0.0014  0.7922  2.1338 
## 
## $boxcox_trans_Socsup
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -3.4347 -0.6855 -0.0693  0.0015  0.8213  1.9400 
## 
## $boxcox_trans_HLE
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -3.6874 -0.7155 -0.0230  0.0005  0.8176  2.2690 
## 
## $boxcox_trans_FtMLC
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -2.8284 -0.6212  0.0927 -0.0020  0.7351  1.9266 
## 
## $boxcox_trans_Gens
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -3.7942 -0.6542  0.0322 -0.0007  0.7156  2.0870 
## 
## $boxcox_trans_PoC
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -3.6507 -0.6243  0.0218 -0.0005  0.6557  1.6839 
## 
## $Happiness_Level
##    Low Medium   High 
##     45     39     56

7. Modelling

Model Ordinal Logistic Regression

model_olr <- polr(Happiness_Level ~ ., data = df_model, Hess = TRUE)
summary(model_olr)
## Call:
## polr(formula = Happiness_Level ~ ., data = df_model, Hess = TRUE)
## 
## Coefficients:
##                       Value Std. Error t value
## boxcox_trans_GDPpc  -1.1537     0.5258 -2.1944
## boxcox_trans_Socsup -1.9517     0.4336 -4.5014
## boxcox_trans_HLE    -0.3778     0.3937 -0.9596
## boxcox_trans_FtMLC  -1.1865     0.2958 -4.0108
## boxcox_trans_Gens   -0.1405     0.2300 -0.6108
## boxcox_trans_PoC     0.6442     0.2640  2.4397
## 
## Intercepts:
##             Value   Std. Error t value
## Low|Medium  -2.4875  0.4331    -5.7434
## Medium|High  1.2442  0.3462     3.5936
## 
## Residual Deviance: 132.1816 
## AIC: 148.1816

Uji Serentak

model_null <- update(model_olr, . ~ 1)

# Uji Likelihood Ratio Test
lrtest(model_olr, model_null)
## Likelihood ratio test
## 
## Model 1: Happiness_Level ~ boxcox_trans_GDPpc + boxcox_trans_Socsup + 
##     boxcox_trans_HLE + boxcox_trans_FtMLC + boxcox_trans_Gens + 
##     boxcox_trans_PoC
## Model 2: Happiness_Level ~ 1
##   #Df   LogLik Df  Chisq Pr(>Chisq)    
## 1   8  -66.091                         
## 2   2 -152.232 -6 172.28  < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Hipotesis:

  • H0 : Semua koefisien prediktor sama dengan nol (model tanpa prediktor sama baiknya dengan model penuh).
  • H1 : Setidaknya satu koefisien prediktor ≠ 0 (model penuh lebih baik dari model null).

Kriteria Keputusan:

  • Jika p-value < 0.05, Tolak H0, artinya model dengan prediktor secara keseluruhan signifikan.
  • Jika p-value >= 0.05, Gagal tolak H0, artinya model dengan prediktor tidak signifikan secara keseluruhan.

Uji Parsial

ctable <- round(coef(summary(model_olr)), 4)
p_vals <- pnorm(abs(ctable[, "t value"]), lower.tail = FALSE) * 2
ctable <- cbind(ctable, "p value" = round(p_vals, 4))
print(ctable)
##                       Value Std. Error t value p value
## boxcox_trans_GDPpc  -1.1537     0.5258 -2.1944  0.0282
## boxcox_trans_Socsup -1.9517     0.4336 -4.5014  0.0000
## boxcox_trans_HLE    -0.3778     0.3937 -0.9596  0.3373
## boxcox_trans_FtMLC  -1.1865     0.2958 -4.0108  0.0001
## boxcox_trans_Gens   -0.1405     0.2300 -0.6108  0.5413
## boxcox_trans_PoC     0.6442     0.2640  2.4397  0.0147
## Low|Medium          -2.4875     0.4331 -5.7434  0.0000
## Medium|High          1.2442     0.3462  3.5936  0.0003

Hipotesis:

  • H0 : Koefisien regresi untuk variabel tersebut = 0.
  • H1 : Koefisien regresi ≠ 0.

Kriteria Keputusan:

  • Jika p-value < 0.05, Tolak H0, prediktor signifikan.
  • Jika p-value >= 0.05, Gagal tolak H0, prediktor tidak signifikan..

Hasil Prediksi beserta Statistik Reportnya

pred_olr <- predict(model_olr, df_model)
confusionMatrix(pred_olr, df_model$Happiness_Level)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Low Medium High
##     Low     37      8    0
##     Medium   8     24    7
##     High     0      7   49
## 
## Overall Statistics
##                                           
##                Accuracy : 0.7857          
##                  95% CI : (0.7084, 0.8505)
##     No Information Rate : 0.4             
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.6749          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Low Class: Medium Class: High
## Sensitivity              0.8222        0.6154      0.8750
## Specificity              0.9158        0.8515      0.9167
## Pos Pred Value           0.8222        0.6154      0.8750
## Neg Pred Value           0.9158        0.8515      0.9167
## Prevalence               0.3214        0.2786      0.4000
## Detection Rate           0.2643        0.1714      0.3500
## Detection Prevalence     0.3214        0.2786      0.4000
## Balanced Accuracy        0.8690        0.7334      0.8958

Diperoleh informasi sebagai berikut:

  • Accuracy : 0.7857 | Nilai ini menunjukkan akurasi prediksi model

  • 95% CI : (0.7084, 0.8505) | Rentang nilai tergolong sempit sekitar 15%, menandakan model yang Bagus dan Stabil

  • No Information Rate : 0.4 | Akurasi baseline suatu model, atau akurasi pada saat asal menebak

  • P-Value : < 0.05 | Tolak Hipotesis Nol (H0), dengan kata lain model berkinerja jauh lebih baik daripada sekadar menebak kelas terbanyak.

  • Kappa Score : 0.6749 | Mediocrie atau sedang, kesepakatan substansial, bukan hanya karena kebetulan

Model Linear Discriminant Analysis

model_lda <- lda(Happiness_Level ~ ., data = df_model)
pred_lda <- predict(model_lda)$class
confusionMatrix(pred_lda, df_model$Happiness_Level)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Low Medium High
##     Low     39      8    0
##     Medium   6     25    7
##     High     0      6   49
## 
## Overall Statistics
##                                           
##                Accuracy : 0.8071          
##                  95% CI : (0.7319, 0.8689)
##     No Information Rate : 0.4             
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.7075          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: Low Class: Medium Class: High
## Sensitivity              0.8667        0.6410      0.8750
## Specificity              0.9158        0.8713      0.9286
## Pos Pred Value           0.8298        0.6579      0.8909
## Neg Pred Value           0.9355        0.8627      0.9176
## Prevalence               0.3214        0.2786      0.4000
## Detection Rate           0.2786        0.1786      0.3500
## Detection Prevalence     0.3357        0.2714      0.3929
## Balanced Accuracy        0.8912        0.7562      0.9018

Diperoleh informasi sebagai berikut:

  • Accuracy : 0.8071 | Nilai ini menunjukkan akurasi prediksi model

  • 95% CI : (0.7319, 0.8689) | Rentang nilai tergolong sempit sekitar 13%, menandakan model yang Bagus dan Stabil

  • No Information Rate : 0.4 | Akurasi baseline suatu model, atau akurasi pada saat asal menebak

  • P-Value : < 0.05 | Tolak Hipotesis Nol (H0), dengan kata lain model berkinerja jauh lebih baik daripada sekadar menebak kelas terbanyak.

  • Kappa Score : 0.7075 | Middling atau menengah, kesepakatan substansial, bukan hanya karena kebetulan

Visualisasi Confussion Matrix kedua Model

cm_olr <- as.data.frame(table(Predicted = pred_olr, Actual = df_model$Happiness_Level))
ggplot(cm_olr, aes(Actual, Predicted, fill = Freq)) +
  geom_tile() +
  geom_text(aes(label = Freq), color = "white", size = 5) +
  labs(title = "Confusion Matrix - Ordinal Logistic Regression", x = "Actual", y = "Predicted") +
  scale_fill_gradient(low = "skyblue", high = "darkblue")

cm_lda <- as.data.frame(table(Predicted = pred_lda, Actual = df_model$Happiness_Level))
ggplot(cm_lda, aes(Actual, Predicted, fill = Freq)) +
  geom_tile() +
  geom_text(aes(label = Freq), color = "white", size = 5) +
  labs(title = "Confusion Matrix - Linear Discriminant Analysis", x = "Actual", y = "Predicted") +
  scale_fill_gradient(low = "lightgreen", high = "darkgreen")


8. Visualisasi Setelah Modelling

Penyebaran Distribusi Kelas

ggplot(data, aes(x = Happiness_Level, y = Score, fill = Happiness_Level)) +
  geom_boxplot() +
  theme_minimal()

Dapat dilihat pada Boxplot, rentang Score dari setiap kelas:

  • Low : < 5
  • Medium : >= 5 y < 6
  • High : > 6

Menunjukkan skor rata-rata untuk setiap tingkat kebahagiaan. “High” memiliki skor tertinggi (sekitar 7), diikuti “Medium” (sekitar 6), dan “Low” (sekitar 4), dengan sedikit tumpang tindih, menunjukkan perbedaan yang jelas antara kategori.

Violin Plot

faktor_long <- df_model %>%
  dplyr::select(Happiness_Level, boxcox_trans_GDPpc, boxcox_trans_Socsup, boxcox_trans_HLE, boxcox_trans_Gens, boxcox_trans_FtMLC, boxcox_trans_PoC) %>%
  pivot_longer(-Happiness_Level, names_to = "Faktor", values_to = "Nilai")

ggplot(faktor_long, aes(x = Happiness_Level, y = Nilai, fill = Happiness_Level)) +
  geom_violin(trim = FALSE) +
  facet_wrap(~ Faktor, scales = "free", ncol = 3) +
  theme_minimal()

Visualisasi Violin menunjukkan beberapa informasi statistik yang dijadikan dalam satu plot, Violin Plot berisi nilai Max, Min, IQR, Density, Median.

Plot menunjukkan distribusi variabel seperti FtMLC, GDP per capita, Generosity, HLE, PoC, dan SocSup berdasarkan tingkat kebahagiaan (Low, Medium, High). Tingkat kebahagiaan “High” cenderung memiliki distribusi yang lebih terpusat dan simetris dengan nilai yang lebih tinggi untuk semua variabel, terutama pada GDP per capita, Generosity, dan SocSup. “Low” kebahagiaan menunjukkan distribusi yang lebih lebar dan miring ke nilai negatif, menunjukkan variabilitas lebih tinggi dan nilai yang lebih rendah secara konsisten.


Kesimpulan dan Saran

Kesimpulan

Proyek ini membahas penerapan dua metode klasifikasi multivariat Ordinal Logistic Regression (OLR) dan Linear Discriminant Analysis (LDA) untuk mengklasifikasikan tingkat kebahagiaan negara berdasarkan indikator sosial-ekonomi dari World Happiness Report 2024. Target klasifikasi berupa variabel ordinal dengan tiga tingkat kebahagiaan: Low, Medium, dan High.

Hasil menunjukkan bahwa: Model OLR dan LDA sama-sama menghasilkan akurasi yang besar, 78.57% untuk model OLR dan 80.71% untuk model LDA. dengan Kappa Score > 0.65, yang menandakan adanya kesepakatan klasifikasi yang substansial. Fitur paling signifikan dalam memengaruhi klasifikasi skor kebahagiaan adalah Social support, Freedom to make life choices, dan Perceptions of corruption.

Secara keseluruhan, proyek ini menegaskan pentingnya faktor sosial dan tata kelola pemerintahan dalam memengaruhi persepsi kebahagiaan masyarakat. Penggunaan pendekatan statistik yang tepat dapat mendukung pengambilan keputusan berbasis data dalam lingkup kebijakan publik.

Saran

Berdasarkan hasil penelitian, terdapat beberapa saran yang dapat diajukan untuk pengembangan lebih lanjut:

1. Penggunaan Dataset Multitahun

  • Menggabungkan data dari beberapa tahun dapat meningkatkan robust-nya model dan memungkinkan analisis tren kebahagiaan dari waktu ke waktu.

2. Ekspansi Fitur Non-Numerik

  • Menambahkan fitur kategorikal seperti wilayah geografis, stabilitas politik, atau indeks pendidikan dapat memperkaya kualitas model klasifikasi.

3. Validasi Model dengan Data Eksternal

  • Perlu dilakukan validasi silang dengan data dari tahun atau sumber berbeda untuk menguji generalisasi model.

4. Integrasi ke Sistem Pengambilan Keputusan

  • Model ini dapat diintegrasikan ke dalam dashboard interaktif atau sistem rekomendasi kebijakan berbasis data untuk mendukung lembaga internasional dan pemerintah nasional dalam merancang intervensi sosial.

Proyek ini diharapkan dapat menjadi dasar pengembangan lanjutan dalam bidang ilmu data sosial dan kebijakan berbasis bukti (evidence-based policy making).


Referensi

[1] E. Sivari and S. Sürücü, “Prediction of heart attack risk using linear discriminant analysis methods,” Journal of Computer & Electrical and Electronics Engineering Sciences, vol. 1, no. 1, pp. 5–9, Apr. 2023, doi: 10.51271/jceees-0002.

[2] F. Marshall, R. Bond, and S. Zhang, “Measuring and Visualising Global Happiness,” BCS Learning & Development, 2018. doi: 10.14236/ewic/hci2018.210.

[3] S. F. Al Maula et al., “Classification Of Country Status In 2022 Based On Social Indicators With Ordinal Logistic Regression,” Jurnal Matematika, Statistika dan Komputasi, vol. 20, no. 3, pp. 538–551, May 2024, doi: 10.20956/j.v20i3.32356.

[4] P. Oberoi, S. Chopra, and Y. Seth, “A Comparative Analysis Of The Factors Affecting Happiness Index”, [Online]. Available: www.ijstr.org

[5] S. Chen, M. Yang, and Y. Lin, “Predicting happiness levels of European immigrants and natives: An application of Artificial Neural Network and Ordinal Logistic Regression,” Front Psychol, vol. 13, Oct. 2022, doi: 10.3389/fpsyg.2022.1012796.

[6] A. Jannani, N. Sael, and F. Benabbou, “Machine learning for the analysis of quality of life using the World Happiness Index and Human Development Indicators,” Mathematical Modeling and Computing, vol. 10, no. 2, pp. 534–546, 2023, doi: 10.23939/mmc2023.02.534.

[7] P. Boedeker and N. T. Kearns, “Linear Discriminant Analysis for Prediction of Group Membership: A User-Friendly Primer,” Adv Methods Pract Psychol Sci, vol. 2, no. 3, pp. 250–263, Sep. 2019, doi: 10.1177/2515245919849378.

[8] D. A. Omondiagbe, S. Veeramani, and A. S. Sidhu, “Machine Learning Classification Techniques for Breast Cancer Diagnosis,” in IOP Conference Series: Materials Science and Engineering, Institute of Physics Publishing, 2019. doi: 10.1088/1757-899X/495/1/012033.

[9] M. Kobus and R. Kurek, “Multidimensional polarization for ordinal data,” J Econ Inequal, vol. 17, no. 3, pp. 301–317, Sep. 2019, doi: 10.1007/s10888-018-9402-1.

[10] F. Lu, F. Ferraro, and E. Raff, “Continuously Generalized Ordinal Regression for Linear and Deep Models,” in Proceedings of the 2022 SIAM International Conference on Data Mining, SDM 2022, Society for Industrial and Applied Mathematics Publications, 2022, pp. 28–36. doi: 10.1137/1.9781611977172.4.

[11] World Happiness Report. 2024. https://worldhappiness.report/ed/2024/#appendices-and-data

[12] Quantifying Happiness: Exploring Factors Affecting Happiness. 2023. https://ucladatares.medium.com/quantifying-happiness-exploring-factors-affecting-happiness-e9376d32c847

[13] Transform Data to Normal Distribution in R 2018. https://www.datanovia.com/en/lessons/transform-data-to-normal-distribution-in-r/