1 PENDAHULUAN

1.1 Latar Belakang & Urgensi Masalah

Keberhasilan akademik siswa di tingkat sekolah menengah merupakan indikator penting dalam mengevaluasi efektivitas proses pembelajaran dan penentu masa depan pendidikan siswa ke jenjang perguruan tinggi. Namun, tingkat kelulusan dan capaian nilai siswa dipengaruhi oleh interaksi kompleks dari berbagai faktor internal maupun eksternal, seperti alokasi waktu belajar mandiri, riwayat ketuntasan belajar di kelas sebelumnya, tingkat disiplin kehadiran, motivasi melanjutkan studi, serta ketersediaan program bimbingan belajar tambahan dari pihak sekolah.

Seringkali institusi pendidikan menghadapi tantangan dalam mendeteksi siswa yang berisiko tidak lulus sejak dini. Evaluasi berbasis nilai ujian akhir saja (summative assessment) bersifat reaktif karena intervensi perbaikan baru dapat dilakukan setelah kegagalan terjadi. Oleh karena itu, diperlukan suatu pendekatan statistik prediktif yang objektif dan berbasis bukti (evidence-based) untuk memodelkan probabilitas kelulusan siswa berdasarkan indikator-indikator perilaku belajar dan demografis akademis sebelum nilai akhir ditetapkan.

1.2 Judul dan Tujuan Penelitian

Penelitian ini berjudul: “Analisis Faktor-Faktor yang Memengaruhi Kelulusan Siswa Menggunakan Metode Regresi Logistik Biner”

Tujuan spesifik dari analisis ini adalah:

  1. Memodelkan hubungan probabilistik antara status kelulusan siswa (\(Y\)) dengan lima variabel prediktor: waktu belajar mingguan (studytime), jumlah kegagalan kelas sebelumnya (failures), jumlah ketidakhadiran (absences), dukungan belajar tambahan sekolah (schoolsup), dan keinginan melanjutkan pendidikan tinggi (higher).

  2. Melakukan pengujian signifikansi model secara simultan (Omnibus Likelihood Ratio Test) dan parsial (Wald Test).

  3. Melakukan evaluasi diagnostik model secara menyeluruh (uji multikolinearitas VIF, uji kelayakan model Hosmer-Lemeshow, serta pemeriksaan konvergensi dan separasi).

  4. Menginterpretasikan koefisien regresi logit dan nilai Odds Ratio (\(OR = e^{\beta}\)) secara substantif dengan memperhitungkan kategori referensi yang tepat.

  5. Mengevaluasi performa klasifikasi model pada data testing (Confusion Matrix, Akurasi, Presisi, Sensitivitas, Spesifisitas, F1-Score, Kurva ROC, dan AUC).

1.3 Landasan Teori Regresi Logistik Biner

Regresi logistik biner (binary logistic regression) merupakan metode analisis statistika yang digunakan ketika variabel dependen (\(Y\)) berskala dikotomi/biner (\(Y \in \{0, 1\}\)).

Probabilitas keberhasilan atau kelulusan siswa dinotasikan dengan: \[\pi(\mathbf{x}) = P(Y=1 \mid \mathbf{X} = \mathbf{x}) = \frac{e^{\beta_0 + \sum_{j=1}^k \beta_j X_j}}{1 + e^{\beta_0 + \sum_{j=1}^k \beta_j X_j}} = \frac{1}{1 + e^{-(\beta_0 + \sum_{j=1}^k \beta_j X_j)}}\]

Transformasi logit menghubungkan probabilitas kelulusan dengan kombinasi linier dari variabel penjelas: \[\text{logit}(\pi(\mathbf{x})) = \ln\left(\frac{\pi(\mathbf{x})}{1 - \pi(\mathbf{x})}\right) = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \dots + \beta_k X_k\]

Nilai \(\frac{\pi(\mathbf{x})}{1 - \pi(\mathbf{x})}\) disebut sebagai Odds (rasio kemungkinan lulus terhadap tidak lulus). Parameter \(\beta_j\) merepresentasikan perubahan pada nilai log-odds untuk setiap kenaikan satu satuan prediktor \(X_j\) (dengan asumsi variabel lain konstan). Besaran efek marjinal dinyatakan dalam Odds Ratio (OR): \[\text{OR}_j = \exp(\beta_j) = e^{\beta_j}\]

Estimasi parameter dilakukan dengan memaksimumkan fungsi kemungkinan log (Maximum Likelihood Estimation / MLE) secara numerik melalui algoritma Iteratively Reweighted Least Squares (IRLS).


2 DESKRIPSI DATASET

2.1 Pemuatan Data dan Pemeriksaan Awal

Dataset yang digunakan berasal dari file student-por.csv (Student Performance Dataset - Portuguese language course, Cortez & Silva, 2008), yang mencakup data performa akademik siswa di dua sekolah menengah di Portugal.

# 1. Memuat Library
required_packages <- c("tidyverse", "ggplot2", "dplyr", "car", 
                       "ResourceSelection", "pROC", "caret", "broom", "knitr")

for (pkg in required_packages) {
  if (requireNamespace(pkg, quietly = TRUE)) {
    suppressPackageStartupMessages(library(pkg, character.only = TRUE))
  }
}

# 2. Membaca Data
data_raw <- read.csv("student-por.csv", sep = ";", stringsAsFactors = FALSE)

# 3. Dimensi Data
cat("Dimensi Dataset:\n")
## Dimensi Dataset:
cat("- Jumlah Baris (Observasi):", nrow(data_raw), "\n")
## - Jumlah Baris (Observasi): 649
cat("- Jumlah Kolom (Variabel) :", ncol(data_raw), "\n")
## - Jumlah Kolom (Variabel) : 33
# 4. Lima Baris Pertama
head(data_raw[, c("school", "sex", "age", "studytime", "failures", "schoolsup", "higher", "absences", "G1", "G2", "G3")], 5)

2.2 Struktur Data dan Pemeriksaan Nilai Hilang / Duplikasi

# Pemeriksaan Missing Values
missing_vals <- colSums(is.na(data_raw))
cat("Total Missing Value pada Seluruh Kolom:", sum(missing_vals), "\n")
## Total Missing Value pada Seluruh Kolom: 0
# Pemeriksaan Duplikasi
cat("Total Baris Duplikasi:", sum(duplicated(data_raw)), "\n")
## Total Baris Duplikasi: 0
# Ringkasan Statistik Deskriptif Variabel Utama
summary(data_raw[, c("studytime", "failures", "absences", "schoolsup", "higher", "G3")])
##    studytime        failures         absences       schoolsup        
##  Min.   :1.000   Min.   :0.0000   Min.   : 0.000   Length:649        
##  1st Qu.:1.000   1st Qu.:0.0000   1st Qu.: 0.000   Class :character  
##  Median :2.000   Median :0.0000   Median : 2.000   Mode  :character  
##  Mean   :1.931   Mean   :0.2219   Mean   : 3.659                     
##  3rd Qu.:2.000   3rd Qu.:0.0000   3rd Qu.: 6.000                     
##  Max.   :4.000   Max.   :3.0000   Max.   :32.000                     
##     higher                G3       
##  Length:649         Min.   : 0.00  
##  Class :character   1st Qu.:10.00  
##  Mode  :character   Median :12.00  
##                     Mean   :11.91  
##                     3rd Qu.:14.00  
##                     Max.   :19.00

Hasil inspeksi membuktikan bahwa dataset bersih, memiliki 649 baris dan 33 kolom, tanpa missing value (\(NA = 0\)) dan tanpa baris duplikasi.


3 PEMBENTUKAN VARIABEL PENELITIAN

Sesuai dengan protokol penelitian yang telah ditetapkan:

3.1 Variabel Dependen (Y)

Variabel respons dibentuk dari nilai ujian akhir periode ketiga (G3): \[Y = \begin{cases} 1, & \text{jika } G3 \ge 10 \quad (\text{Status: Lulus}) \\ 0, & \text{jika } G3 < 10 \quad (\text{Status: Tidak Lulus}) \end{cases}\]

3.2 Variabel Independen (X)

Model melibatkan 5 variabel independen:

  1. studytime (\(X_1\)): Waktu belajar mingguan (skala 1: <2 jam, 2: 2–5 jam, 3: 5–10 jam, 4: >10 jam; numerik/ordinal).

  2. failures (\(X_2\)): Jumlah kegagalan kelas sebelumnya (\(n\) jika \(1 \le n < 3\), else 4; numerik diskrit).

  3. absences (\(X_3\)): Jumlah hari ketidakhadiran di sekolah (numerik kontinu/cacah).

  4. schoolsup (\(X_4\)): Bantuan dukungan belajar tambahan dari sekolah (kategorik biner: "no", "yes").

  5. higher (\(X_5\)): Keinginan melanjutkan ke jenjang perguruan tinggi (kategorik biner: "no", "yes").

Batasan Ketat Metodologis: * Variabel G3 tidak dimasukkan sebagai prediktor karena merupakan dasar pembentukan \(Y\). * Variabel nilai periode pertama (G1) dan kedua (G2) tidak dimasukkan sebagai prediktor guna mencegah data leakage, karena tujuan model adalah memprediksi kelulusan murni berdasarkan faktor perilaku dan motivasi belajar, bukan nilai ujian perantara. * Variabel schoolsup dan higher diperlakukan secara tepat sebagai variabel kategorik (factor) dengan kategori referensi (baseline) "no".

# Pembentukan Variabel Respons Y
data_raw$Y <- ifelse(data_raw$G3 >= 10, 1, 0)
data_raw$status_kelulusan <- factor(
  ifelse(data_raw$Y == 1, "Lulus", "Tidak Lulus"),
  levels = c("Tidak Lulus", "Lulus")
)

# Menyiapkan Data Model
data_model <- data_raw[, c("studytime", "failures", "absences", "schoolsup", "higher", "Y")]
data_model$schoolsup <- factor(data_model$schoolsup, levels = c("no", "yes"))
data_model$higher    <- factor(data_model$higher, levels = c("no", "yes"))

# Distribusi Frekuensi Y
tab_y <- table(data_raw$status_kelulusan)
prop_y <- prop.table(tab_y) * 100

data.frame(
  Status_Kelulusan = names(tab_y),
  Kode_Biner = c(0, 1),
  Frekuensi = as.numeric(tab_y),
  Persentase = paste0(round(as.numeric(prop_y), 2), " %")
)

Distribusi variabel dependen menunjukkan bahwa sebanyak 549 siswa (84,59%) lulus dan 100 siswa (15,41%) tidak lulus. Terjadi ketidakseimbangan kelas (class imbalance) yang menuntut penggunaan penarikan sampel terstratifikasi (stratified sampling).


4 EKSPLORASI DATA (EDA)

Berikut disajikan visualisasi eksplorasi data untuk memahami karakteristik distribusi variabel dan hubungannya dengan status kelulusan.

par(mfrow = c(2, 2), mar = c(4, 4, 3, 1))

# 1. Distribusi Status Kelulusan (Y)
bp_y <- barplot(
  tab_y,
  col = c("#E74C3C", "#2ECC71"),
  main = "Distribusi Status Kelulusan (Y)",
  xlab = "Status", ylab = "Jumlah Siswa",
  ylim = c(0, 600), border = NA
)
text(x = bp_y, y = as.numeric(tab_y) + 30, 
     labels = paste0(as.numeric(tab_y), "\n(", round(as.numeric(prop_y), 1), "%)"), cex = 0.9)
grid(nx = NA, ny = NULL, col = "gray85")

# 2. Distribusi Waktu Belajar (studytime)
tab_st <- table(data_model$studytime)
barplot(
  tab_st, col = "#3498DB",
  main = "Distribusi Waktu Belajar (studytime)",
  xlab = "Skala Studytime (1: <2j, 2: 2-5j, 3: 5-10j, 4: >10j)",
  ylab = "Frekuensi", border = NA
)
grid(nx = NA, ny = NULL, col = "gray85")

# 3. Distribusi Kegagalan Kelas Sebelumnya (failures)
tab_fl <- table(data_model$failures)
barplot(
  tab_fl, col = "#E67E22",
  main = "Distribusi Kegagalan Sebelumnya (failures)",
  xlab = "Jumlah Kegagalan", ylab = "Frekuensi", border = NA
)
grid(nx = NA, ny = NULL, col = "gray85")

# 4. Distribusi Ketidakhadiran (absences)
hist(
  data_model$absences, breaks = 20, col = "#9B59B6", border = "white",
  main = "Distribusi Ketidakhadiran (absences)",
  xlab = "Hari Tidak Hadir", ylab = "Frekuensi"
)
grid(col = "gray85")

par(mfrow = c(1, 1))
par(mfrow = c(1, 2), mar = c(4, 4, 3, 1))

# 5. Hubungan schoolsup dengan Status Kelulusan
tab_ss <- table(data_model$schoolsup, data_raw$status_kelulusan)
prop_ss <- prop.table(tab_ss, 1) * 100
barplot(
  t(prop_ss), beside = TRUE, col = c("#E74C3C", "#2ECC71"),
  main = "Kelulusan vs Dukungan Sekolah",
  xlab = "Menerima schoolsup", ylab = "Persentase (%)",
  ylim = c(0, 100), border = NA
)
legend("topright", legend = c("Tidak Lulus", "Lulus"), fill = c("#E74C3C", "#2ECC71"), bty = "n")
grid(nx = NA, ny = NULL, col = "gray85")

# 6. Hubungan higher dengan Status Kelulusan
tab_hg <- table(data_model$higher, data_raw$status_kelulusan)
prop_hg <- prop.table(tab_hg, 1) * 100
barplot(
  t(prop_hg), beside = TRUE, col = c("#E74C3C", "#2ECC71"),
  main = "Kelulusan vs Keinginan Kuliah",
  xlab = "Ingin Melanjutkan Kuliah (higher)", ylab = "Persentase (%)",
  ylim = c(0, 100), border = NA
)
legend("topleft", legend = c("Tidak Lulus", "Lulus"), fill = c("#E74C3C", "#2ECC71"), bty = "n")
grid(nx = NA, ny = NULL, col = "gray85")

par(mfrow = c(1, 1))
# 7. Perbandingan Variabel Numerik Berdasarkan Status Kelulusan
par(mfrow = c(1, 3), mar = c(4, 4, 3, 1))
boxplot(studytime ~ status_kelulusan, data = data_raw, col = c("#E74C3C", "#2ECC71"),
        main = "studytime vs Kelulusan", xlab = "Status Kelulusan", ylab = "studytime (Skala 1-4)")
boxplot(failures ~ status_kelulusan, data = data_raw, col = c("#E74C3C", "#2ECC71"),
        main = "failures vs Kelulusan", xlab = "Status Kelulusan", ylab = "Jumlah Failures")
boxplot(absences ~ status_kelulusan, data = data_raw, col = c("#E74C3C", "#2ECC71"),
        main = "absences vs Kelulusan", xlab = "Status Kelulusan", ylab = "Jumlah Absences")

par(mfrow = c(1, 1))

4.0.1 Interpretasi Hasil Eksplorasi Data (EDA)

  1. Status Kelulusan: Sebanyak 84,6% siswa berada pada kategori Lulus (\(G3 \ge 10\)) dan 15,4% Tidak Lulus.

  2. Waktu Belajar (studytime): Mayoritas siswa mengalokasikan waktu belajar pada kategori 2 (2–5 jam per minggu). Siswa yang lulus memperlihatkan median waktu belajar yang cenderung lebih tinggi daripada siswa yang tidak lulus.

  3. Riwayat Kegagalan (failures): Sebagian besar siswa tidak pernah gagal kelas sebelumnya (nilai 0). Namun, pada kelompok siswa yang tidak lulus, proporsi siswa dengan riwayat kegagalan 1 hingga 3 kali tampak jauh lebih dominan.

  4. Ketidakhadiran (absences): Distribusi ketidakhadiran menceng ke kanan (right-skewed), di mana mayoritas siswa memiliki ketidakhadiran 0 hingga 6 hari, dengan nilai maksimum 32 hari.

  5. Keinginan Melanjutkan Pendidikan Tinggi (higher): Dari siswa yang ingin melanjutkan kuliah (higher = yes), lebih dari 88% berhasil lulus. Sebaliknya, pada siswa yang tidak berniat kuliah (higher = no), persentase ketidaklulusan melonjak hingga hampir 48%.

  6. Dukungan Belajar Tambahan (schoolsup): Proporsi kelulusan pada siswa yang menerima bantuan sekolah justru sedikit lebih rendah dibandingkan yang tidak menerima, mengindikasikan bahwa program dukungan sekolah umumnya dialokasikan kepada siswa yang memang sejak awal mengalami kesulitan akademik.


5 PEMODELAN REGRESI LOGISTIK BINER

5.1 Pembagian Data Terstratifikasi (80:20, Seed = 70)

Untuk memastikan validasi model dilakukan secara objektif tanpa bias data leakage, data dibagi menjadi 80% Data Latih (Training) dan 20% Data Uji (Testing) menggunakan stratified sampling berdasarkan variabel \(Y\) dengan seed = 70.

set.seed(70)

idx_y1 <- which(data_model$Y == 1)
idx_y0 <- which(data_model$Y == 0)

train_idx_y1 <- sample(idx_y1, size = round(0.80 * length(idx_y1)))
train_idx_y0 <- sample(idx_y0, size = round(0.80 * length(idx_y0)))

train_indices <- sort(c(train_idx_y1, train_idx_y0))
train_data <- data_model[train_indices, ]
test_data  <- data_model[-train_indices, ]

data.frame(
  Himpunan_Data = c("Total Populasi", "Data Latih (Train 80%)", "Data Uji (Test 20%)"),
  Jumlah_Observasi = c(nrow(data_model), nrow(train_data), nrow(test_data)),
  Jumlah_Lulus = c(sum(data_model$Y), sum(train_data$Y), sum(test_data$Y)),
  Proporsi_Lulus = paste0(round(c(mean(data_model$Y), mean(train_data$Y), mean(test_data$Y)) * 100, 2), " %"),
  Proporsi_Tidak_Lulus = paste0(round(c(1 - mean(data_model$Y), 1 - mean(train_data$Y), 1 - mean(test_data$Y)) * 100, 2), " %")
)

Proporsi kelulusan pada data latih (84,59%) dan data uji (84,62%) terjaga identik dengan populasi aslinya, membuktikan efektivitas stratifikasi.

5.2 Estimasi Model Regresi Logistik

Model diestimasi menggunakan fungsi glm() pada data training dengan fungsi penghubung logit: \[\text{logit}(P(Y=1)) = \beta_0 + \beta_1 \cdot \text{studytime} + \beta_2 \cdot \text{failures} + \beta_3 \cdot \text{absences} + \beta_4 \cdot \text{schoolsup}_{\text{yes}} + \beta_5 \cdot \text{higher}_{\text{yes}}\]

model_null <- glm(Y ~ 1, data = train_data, family = binomial(link = "logit"))
model_full <- glm(Y ~ studytime + failures + absences + schoolsup + higher, 
                  data = train_data, family = binomial(link = "logit"))

summary(model_full)
## 
## Call:
## glm(formula = Y ~ studytime + failures + absences + schoolsup + 
##     higher, family = binomial(link = "logit"), data = train_data)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)   0.31088    0.44972   0.691 0.489403    
## studytime     0.38424    0.19043   2.018 0.043614 *  
## failures     -0.93918    0.18492  -5.079  3.8e-07 ***
## absences     -0.02834    0.02713  -1.045 0.296159    
## schoolsupyes  0.12243    0.50896   0.241 0.809905    
## higheryes     1.33555    0.35551   3.757 0.000172 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 446.16  on 518  degrees of freedom
## Residual deviance: 371.42  on 513  degrees of freedom
## AIC: 383.42
## 
## Number of Fisher Scoring iterations: 5

6 DIAGNOSIS MODEL (MODEL DIAGNOSTICS)

Sebelum koefisien diinterpretasikan, model harus melalui serangkaian pengujian diagnostik untuk memverifikasi pemenuhan asumsi dan kelayakan model secara statistik.

6.1 Uji Multikolinearitas (VIF / GVIF)

Multikolinearitas terjadi jika prediktor memiliki korelasi linear yang kuat antar-sesamanya, yang dapat membiaskan estimasi standard error. Pedoman pengujian menyatakan nilai VIF atau \(\text{GVIF}^{1/(2 \times \text{Df})} < 5\) mengindikasikan bebas multikolinearitas.

if (requireNamespace("car", quietly = TRUE)) {
  vif_table <- car::vif(model_full)
  vif_df <- data.frame(
    Variabel = names(vif_table),
    VIF = round(as.numeric(vif_table), 4),
    Status = ifelse(vif_table < 5, "Bebas Multikolinearitas (VIF < 5)", "Kolinearitas Tinggi")
  )
} else {
  X_mat <- model.matrix(model_full)[, -1]
  vif_vals <- sapply(1:ncol(X_mat), function(j) 1 / (1 - summary(lm(X_mat[, j] ~ X_mat[, -j]))$r.squared))
  vif_df <- data.frame(
    Variabel = colnames(X_mat),
    VIF = round(vif_vals, 4),
    Status = ifelse(vif_vals < 5, "Bebas Multikolinearitas (VIF < 5)", "Kolinearitas Tinggi")
  )
}
vif_df

Interpretasi Multikolinearitas: Seluruh variabel prediktor memiliki nilai VIF \(< 1{,}20\) (jauh di bawah batas toleransi 5). Hal ini menegaskan bahwa tidak ada multikolinearitas antar prediktor, sehingga estimasi koefisien dan kesalahan baku bersifat stabil dan efisien.

6.2 Uji Signifikansi Simultan (Omnibus Likelihood Ratio Test / \(G\)-Test)

Uji signifikansi simultan menguji apakah kelima prediktor secara bersama-sama memengaruhi probabilitas kelulusan siswa dibandingkan model tanpa prediktor (intercept-only).

  • Hipotesis:
    • \(H_0: \beta_1 = \beta_2 = \beta_3 = \beta_4 = \beta_5 = 0\)
    • \(H_1: \text{Minimal ada satu } \beta_j \neq 0 \quad (j = 1, \dots, 5)\)
  • Statistik Uji: \[G = D_{\text{null}} - D_{\text{model}} \sim \chi^2_{(df_{\text{null}} - df_{\text{model}})}\]
lrt_anova <- anova(model_null, model_full, test = "Chisq")
lrt_anova
g_stat <- model_null$deviance - model_full$deviance
df_g   <- model_null$df.residual - model_full$df.residual
p_val_g <- pchisq(g_stat, df = df_g, lower.tail = FALSE)

cat(sprintf("Statistik G (Chi-Square) = %.4f | df = %d | p-value = %e\n", g_stat, df_g, p_val_g))
## Statistik G (Chi-Square) = 74.7419 | df = 5 | p-value = 1.053112e-14

Keputusan Uji Simultan: Nilai statistik \(G = 74{,}7419\) dengan \(df = 5\) menghasilkan \(p\)-value = \(1{,}053 \times 10^{-14} < 0{,}05\). Maka, Tolak \(H_0\). Secara simultan, kelima variabel penjelas memberikan pengaruh yang sangat signifikan terhadap probabilitas kelulusan siswa.

6.3 Uji Signifikansi Parsial (Wald Test)

Uji Wald mengevaluasi signifikansi kontribusi individual masing-masing koefisien terhadap model: * Hipotesis: \(H_0: \beta_j = 0\) vs \(H_1: \beta_j \neq 0\) * Statistik Uji: \(Z = \frac{\hat{\beta}_j}{\text{SE}(\hat{\beta}_j)} \sim N(0, 1)\)

summary_coef <- summary(model_full)$coefficients

data.frame(
  Variabel = rownames(summary_coef),
  Estimasi_Beta = round(summary_coef[, 1], 4),
  Std_Error = round(summary_coef[, 2], 4),
  Wald_Z = round(summary_coef[, 3], 3),
  P_Value = format.pval(summary_coef[, 4], digits = 4),
  Keputusan = ifelse(summary_coef[, 4] < 0.05, "Signifikan (Tolak H0)", "Tidak Signifikan (Gagal Tolak H0)")
)

Keputusan Uji Parsial (\(\alpha = 0{,}05\)): * Variabel yang signifikan: failures (\(p < 0{,}001\)), higher (\(p < 0{,}001\)), dan studytime (\(p = 0{,}0436\)). * Variabel yang tidak signifikan: absences (\(p = 0{,}2962\)) dan schoolsup (\(p = 0{,}8099\)).

6.4 Uji Kelayakan Model (Hosmer-Lemeshow Goodness of Fit Test)

Uji Hosmer-Lemeshow membagi data ke dalam \(g = 10\) kelompok desil berdasarkan probabilitas terprediksi \(\hat{\pi}_i\) untuk menguji apakah frekuensi teramati sesuai dengan ekspektasi model.

  • Hipotesis:
    • \(H_0\): Model cocok dengan data secara memadai (model fits the data adequately).
    • \(H_1\): Model tidak cocok dengan data (lack of fit).
if (requireNamespace("ResourceSelection", quietly = TRUE)) {
  hl_res <- ResourceSelection::hoslem.test(train_data$Y, model_full$fitted.values, g = 10)
  hl_stat <- hl_res$statistic
  hl_df   <- hl_res$parameter
  hl_pval <- hl_res$p.value
} else {
  brks <- unique(quantile(model_full$fitted.values, probs = seq(0, 1, length.out = 11)))
  groups <- cut(model_full$fitted.values, breaks = brks, include.lowest = TRUE)
  obs_1 <- tapply(train_data$Y, groups, sum)
  obs_0 <- tapply(1 - train_data$Y, groups, sum)
  exp_1 <- tapply(model_full$fitted.values, groups, sum)
  exp_0 <- tapply(1 - model_full$fitted.values, groups, sum)
  hl_stat <- sum((obs_1 - exp_1)^2 / exp_1 + (obs_0 - exp_0)^2 / exp_0, na.rm = TRUE)
  hl_df   <- length(brks) - 3
  hl_pval <- pchisq(hl_stat, df = hl_df, lower.tail = FALSE)
}

cat("Statistik Hosmer-Lemeshow Chi-Square (X-squared):", round(hl_stat, 4), "\n")
## Statistik Hosmer-Lemeshow Chi-Square (X-squared): 9.5689
cat("Derajat Bebas (df)                             :", hl_df, "\n")
## Derajat Bebas (df)                             : 8
cat("P-value                                        :", round(hl_pval, 5), "\n")
## P-value                                        : 0.2966

Keputusan & Keterbatasan Uji Hosmer-Lemeshow: Karena \(p\)-value = \(0{,}2966 > 0{,}05\), maka Gagal Tolak \(H_0\). Tidak terdapat bukti yang cukup untuk menyatakan model tidak cocok, sehingga model regresi logistik biner ini memiliki kebaikan suai (goodness of fit) yang memadai.

Keterbatasan Pengujian: Uji Hosmer-Lemeshow sensitif terhadap pemilihan jumlah grup desil (\(g\)) dan adanya nilai probabilitas prediksi yang identik (ties). Oleh karena itu, hasil uji HL harus didukung oleh metrik diskriminasi kurva ROC dan evaluasi matriks klasifikasi.

6.5 Pemeriksaan Konvergensi Model & Separasi

Pada regresi logistik biner, kondisi complete separation atau quasi-complete separation (kondisi di mana suatu prediktor memisahkan kelas 0 dan 1 secara sempurna) dapat menyebabkan estimasi koefisien membengkak menuju tak hingga dan standar error menjadi sangat besar (exploding SE).

cat("Status Konvergensi Algoritma IRLS       :", model_full$converged, "\n")
## Status Konvergensi Algoritma IRLS       : TRUE
cat("Jumlah Iterasi Fisher Scoring Dilakukan :", model_full$iter, "\n")
## Jumlah Iterasi Fisher Scoring Dilakukan : 5
cat("Rentang Probabilitas Prediksi Minimum   :", round(min(model_full$fitted.values), 4), "\n")
## Rentang Probabilitas Prediksi Minimum   : 0.0785
cat("Rentang Probabilitas Prediksi Maksimum   :", round(max(model_full$fitted.values), 4), "\n")
## Rentang Probabilitas Prediksi Maksimum   : 0.9646

Evaluasi Konvergensi: Model berhasil mencapai konvergensi hanya dalam 5 iterasi tanpa mengeluarkan warning numerik. Nilai probabilitas prediksi berada dalam rentang wajar (\(0{,}0785\) hingga \(0{,}9646\)) dan seluruh standar error memiliki besaran yang wajar (\(\text{SE} \le 0{,}51\)). Dengan demikian, tidak terjadi masalah separasi data.


7 INTERPRETASI KOEFISIEN DAN ODDS RATIO

Tabel berikut menyajikan ringkasan lengkap parameter model: estimasi koefisien (\(\hat{\beta}\)), kesalahan baku (Standard Error), statistik uji Wald (\(Z\)), nilai \(p\), Odds Ratio (\(OR = e^{\hat{\beta}}\)), dan Interval Kepercayaan 95% untuk Odds Ratio: \[\text{CI}_{95\%}(OR) = \left[ \exp(\hat{\beta} - 1{,}96 \times \text{SE}), \; \exp(\hat{\beta} + 1{,}96 \times \text{SE}) \right]\]

coef_est <- coef(model_full)
se_est   <- summary_coef[, 2]
wald_z   <- summary_coef[, 3]
p_vals   <- summary_coef[, 4]

or_val  <- exp(coef_est)
ci_calc <- exp(confint.default(model_full))

table_interpretasi <- data.frame(
  Variabel = names(coef_est),
  Koefisien_Beta = round(coef_est, 4),
  Std_Error = round(se_est, 4),
  Wald_Z = round(wald_z, 3),
  Odds_Ratio = round(or_val, 4),
  P_Value = format.pval(p_vals, digits = 4),
  CI_95_Lower = round(ci_calc[, 1], 4),
  CI_95_Upper = round(ci_calc[, 2], 4),
  Signifikansi = ifelse(p_vals < 0.001, "***", 
                        ifelse(p_vals < 0.01, "**", 
                               ifelse(p_vals < 0.05, "*", "ns")))
)
table_interpretasi
# Forest Plot Odds Ratio
plot_df <- table_interpretasi[table_interpretasi$Variabel != "(Intercept)", ]
par(mar = c(5, 8, 4, 2))
plot(
  plot_df$Odds_Ratio, 1:nrow(plot_df), pch = 19, col = "#2980B9", cex = 1.3,
  xlim = c(0, 8.5), ylim = c(0.5, nrow(plot_df) + 0.5), yaxt = "n",
  xlab = "Odds Ratio (OR) dan 95% Confidence Interval", ylab = "",
  main = "Forest Plot Odds Ratio Prediktor Kelulusan Siswa"
)
axis(2, at = 1:nrow(plot_df), labels = plot_df$Variabel, las = 2)
abline(v = 1, col = "#E74C3C", lty = 2, lwd = 1.5)
for (i in 1:nrow(plot_df)) {
  lines(c(plot_df$CI_95_Lower[i], plot_df$CI_95_Upper[i]), c(i, i), col = "#2980B9", lwd = 2)
}
grid(nx = NULL, ny = NA)

par(mar = c(5, 4, 4, 2))

7.1 Interpretasi Substantif Setiap Variabel

7.1.1 1. Waktu Belajar Mingguan (studytime)

  • Parameter: \(\hat{\beta}_1 = +0{,}3842\), \(\text{SE} = 0{,}1904\), Wald \(Z = +2{,}018\), \(p = 0{,}0436\), \(\text{OR} = 1{,}4685\) (95% CI: \([1{,}0111 ; 2{,}1329]\)).
  • Arah Hubungan: Positif dan signifikan pada taraf \(\alpha = 0{,}05\).
  • Interpretasi Statistik: Untuk setiap kenaikan satu tingkat kategori waktu belajar mingguan siswa (misalnya dari kategori 1 [<2 jam] ke kategori 2 [2–5 jam]), odds kelulusan siswa meningkat sekitar 46,85% (\(\text{OR} = 1{,}4685\)), dengan asumsi variabel lain konstan. Interval kepercayaan 95% berada sepenuhnya di atas nilai 1 (\([1{,}0111 ; 2{,}1329]\)), menegaskan bahwa alokasi waktu belajar mandiri yang lebih intensif secara konsisten diasosiasikan dengan peningkatan kecenderungan kelulusan.

7.1.2 2. Jumlah Kegagalan Kelas Sebelumnya (failures)

  • Parameter: \(\hat{\beta}_2 = -0{,}9392\), \(\text{SE} = 0{,}1849\), Wald \(Z = -5{,}079\), \(p = 3{,}80 \times 10^{-7}\), \(\text{OR} = 0{,}3909\) (95% CI: \([0{,}2721 ; 0{,}5617]\)).
  • Arah Hubungan: Negatif dan sangat signifikan pada taraf \(\alpha = 0{,}001\).
  • Interpretasi Statistik: Setiap penambahan satu kali riwayat kegagalan kelas di masa lalu diasosiasikan dengan penurunan odds kelulusan siswa sebesar 60,91% (\(1 - 0{,}3909 = 0{,}6091\)), dengan asumsi variabel lain konstan. Variabel ini merupakan faktor penghambat kelulusan terbesar, mencerminkan adanya akumulasi defisit pemahaman konsep belajar yang belum terselesaikan dari jenjang sebelumnya.

7.1.3 3. Jumlah Ketidakhadiran (absences)

  • Parameter: \(\hat{\beta}_3 = -0{,}0283\), \(\text{SE} = 0{,}0271\), Wald \(Z = -1{,}045\), \(p = 0{,}2962\), \(\text{OR} = 0{,}9721\) (95% CI: \([0{,}9217 ; 1{,}0251]\)).
  • Arah Hubungan: Negatif, tetapi tidak signifikan secara statistik pada taraf \(\alpha = 0{,}05\) (\(p > 0{,}05\)).
  • Interpretasi Statistik: Setiap penambahan satu hari ketidakhadiran diasosiasikan dengan penurunan odds kelulusan sebesar 2,79% (\(1 - 0{,}9721\)), namun karena nilai \(p = 0{,}2962\) dan interval kepercayaan 95% mencakup angka 1 (\([0{,}9217 ; 1{,}0251]\)), tidak terdapat bukti statistik yang cukup untuk menyatakan bahwa variasi absensi memiliki pengaruh langsung terhadap kelulusan dalam model ini.

7.1.4 4. Dukungan Belajar Tambahan Sekolah (schoolsup)

  • Parameter: \(\hat{\beta}_4 = +0{,}1224\), \(\text{SE} = 0{,}5090\), Wald \(Z = +0{,}241\), \(p = 0{,}8099\), \(\text{OR} = 1{,}1302\) (95% CI: \([0{,}4168 ; 3{,}0648]\)).
  • Kategori Referensi: "no" (siswa yang tidak menerima dukungan belajar tambahan).
  • Arah Hubungan: Positif, tetapi tidak signifikan secara statistik (\(p > 0{,}05\)).
  • Interpretasi Statistik: Siswa yang menerima dukungan belajar tambahan dari sekolah memiliki odds kelulusan 1,1302 kali (13,02% lebih tinggi) dibandingkan siswa yang tidak menerima bantuan, dengan asumsi variabel lain konstan. Namun, karena \(p = 0{,}8099\), perbedaan ini tidak signifikan secara statistik. Hal ini dapat dimaklumi karena program bantuan sekolah umumnya ditujukan secara selektif kepada siswa yang sedang mengalami penurunan nilai, sehingga efek intervensinya belum langsung melampaui kelompok siswa reguler.

7.1.5 5. Keinginan Melanjutkan Pendidikan Tinggi (higher)

  • Parameter: \(\hat{\beta}_5 = +1{,}3356\), \(\text{SE} = 0{,}3555\), Wald \(Z = +3{,}757\), \(p = 0{,}00017\), \(\text{OR} = 3{,}8021\) (95% CI: \([1{,}8941 ; 7{,}6320]\)).
  • Kategori Referensi: "no" (siswa yang tidak berniat melanjutkan ke perguruan tinggi).
  • Arah Hubungan: Positif dan sangat signifikan pada taraf \(\alpha = 0{,}001\).
  • Interpretasi Statistik: Siswa yang memiliki motivasi untuk melanjutkan pendidikan ke perguruan tinggi (higher = yes) memiliki odds kelulusan 3,8021 kali lebih tinggi (atau 280,21% lebih tinggi) dibandingkan siswa yang tidak berniat melanjutkan kuliah, dengan asumsi variabel lain konstan. Variabel ini menjadi prediktor pendorong kelulusan terkuat dalam model.

8 EVALUASI MODEL PADA DATA TESTING

Performa generalisasi model dievaluasi secara independen pada Data Uji (Testing Set) (\(N = 130\) observasi) yang belum pernah dilihat saat pelatihan.

# Prediksi probabilitas pada data uji
prob_test <- predict(model_full, newdata = test_data, type = "response")
actual_test <- test_data$Y

# Klasifikasi dengan Threshold Awal 0.50
pred_class_50 <- ifelse(prob_test >= 0.50, 1, 0)
cm_test <- table(Aktual = actual_test, Prediksi = pred_class_50)
rownames(cm_test) <- c("Aktual: 0 (Tidak Lulus)", "Aktual: 1 (Lulus)")
colnames(cm_test) <- c("Prediksi: 0 (Tidak Lulus)", "Prediksi: 1 (Lulus)")
cm_test
##                          Prediksi
## Aktual                    Prediksi: 0 (Tidak Lulus) Prediksi: 1 (Lulus)
##   Aktual: 0 (Tidak Lulus)                         4                  16
##   Aktual: 1 (Lulus)                               2                 108

8.1 Ekstraksi Metrik Kinerja Klasifikasi (Kelas Positif: \(Y = 1\) / Lulus)

tp <- sum(actual_test == 1 & pred_class_50 == 1)
tn <- sum(actual_test == 0 & pred_class_50 == 0)
fp <- sum(actual_test == 0 & pred_class_50 == 1)
fn <- sum(actual_test == 1 & pred_class_50 == 0)

acc_val  <- (tp + tn) / length(actual_test)
prec_val <- tp / (tp + fp)
rec_val  <- tp / (tp + fn) # Sensitivity / Recall
spec_val <- tn / (tn + fp)
f1_val   <- 2 * prec_val * rec_val / (prec_val + rec_val)

data.frame(
  Metrik_Kinerja = c("Accuracy", "Precision", "Recall / Sensitivity", "Specificity", "F1-Score"),
  Nilai_Desimal = round(c(acc_val, prec_val, rec_val, spec_val, f1_val), 4),
  Persentase = paste0(round(c(acc_val, prec_val, rec_val, spec_val) * 100, 2), " %", c("", "", "", "", " (skala 0-1)"))
)

8.2 Analisis Kurva ROC dan AUC

th_grid <- seq(0, 1, by = 0.005)
tpr_seq <- numeric(length(th_grid))
fpr_seq <- numeric(length(th_grid))

for (k in seq_along(th_grid)) {
  p_cl <- ifelse(prob_test >= th_grid[k], 1, 0)
  tpr_seq[k] <- sum(p_cl == 1 & actual_test == 1) / sum(actual_test == 1)
  fpr_seq[k] <- sum(p_cl == 1 & actual_test == 0) / sum(actual_test == 0)
}

ord_roc <- order(fpr_seq)
fpr_s <- fpr_seq[ord_roc]
tpr_s <- tpr_seq[ord_roc]
auc_val <- sum(diff(fpr_s) * (tpr_s[-1] + tpr_s[-length(tpr_s)]) / 2)

plot(
  fpr_s, tpr_s, type = "l", col = "#2980B9", lwd = 3,
  main = paste0("Kurva ROC pada Data Testing (AUC = ", round(auc_val, 4), ")"),
  xlab = "False Positive Rate (1 - Spesifisitas)",
  ylab = "True Positive Rate (Sensitivitas)",
  xlim = c(0, 1), ylim = c(0, 1)
)
abline(a = 0, b = 1, col = "gray50", lty = 2, lwd = 1.5)
points(1 - spec_val, rec_val, col = "#E74C3C", pch = 19, cex = 1.5)
text(1 - spec_val + 0.16, rec_val - 0.05, 
     labels = paste0("Threshold 0.50\nSens: ", round(rec_val, 2), "\nSpec: ", round(spec_val, 2)),
     col = "#E74C3C", cex = 0.85)
grid()

8.2.1 Makna Hasil Evaluasi Model

  1. Accuracy (86,15%): Model berhasil memprediksi status kelulusan dengan tepat pada 112 dari 130 siswa di data testing.

  2. Sensitivity / Recall (98,18%): Model mampu mendeteksi 108 dari 110 siswa yang lulus secara tepat (hanya 2 siswa lulus yang salah diklasifikasikan sebagai tidak lulus).

  3. Precision (87,10%): Dari 124 siswa yang diprediksi lulus oleh model, sebanyak 108 siswa faktualnya benar-benar lulus.

  4. Specificity (20,00%): Pada threshold standar 0,50, spesifisitas relatif rendah karena sifat ketidakseimbangan kelas populasi (84,6% lulus), di mana model cenderung agresif memprediksi lulus.

  5. F1-Score (0,9231): Menunjukkan keharmonisan performa presisi dan recall yang sangat tinggi untuk kelas mayoritas.

  6. Area Under ROC (AUC = 0,8032): Berdasarkan standar klasifikasi Hosmer & Lemeshow (\(0{,}80 \le \text{AUC} < 0{,}90\)), nilai AUC sebesar 0,8032 mengindikasikan kemampuan diskriminasi model yang sangat baik (excellent discrimination) dalam membedakan siswa yang akan lulus dan tidak lulus.


9 KESIMPULAN

Berdasarkan keseluruhan tahapan pengujian dan estimasi empiris, dapat ditarik beberapa kesimpulan penting:

  1. Hasil Pengujian Simultan (Omnibus LRT / \(G\)-test): Model regresi logistik biner yang dibangun terbukti signifikan secara simultan (\(G = 74{,}7419, \; df = 5, \; p\text{-value} = 1{,}053 \times 10^{-14} < 0{,}05\)), membuktikan bahwa kombinasi kelima variabel penjelas secara bersama-sama memberikan kontribusi nyata terhadap kelulusan siswa.

  2. Hasil Pengujian Parsial (Wald Test):

    • Terdapat tiga prediktor yang signifikan secara statistik pada taraf nyata \(\alpha = 0{,}05\):
      • higher (\(p = 0{,}00017\)): Keinginan melanjutkan ke perguruan tinggi berhubungan positif sangat kuat dengan kelulusan.
      • failures (\(p = 3{,}80 \times 10^{-7}\)): Riwayat kegagalan kelas sebelumnya berhubungan negatif sangat kuat dengan kelulusan.
      • studytime (\(p = 0{,}0436\)): Waktu belajar mingguan berhubungan positif dengan kelulusan.
    • Dua prediktor terbukti tidak signifikan secara statistik: absences (\(p = 0{,}2962\)) dan schoolsup (\(p = 0{,}8099\)).
  3. Hasil Diagnosis Multikolinearitas: Seluruh prediktor memiliki nilai VIF \(< 1{,}20\), membuktikan bahwa model terbebas dari masalah multikolinearitas.

  4. Hasil Uji Kelayakan Model (Goodness of Fit): Uji Hosmer-Lemeshow menghasilkan statistik \(\chi^2 = 9{,}5689\) (\(df = 8, \; p\text{-value} = 0{,}2966 > 0{,}05\)) yang mengindikasikan bahwa model memiliki kecocokan (goodness of fit) yang memadai terhadap data.

  5. Hasil Evaluasi Klasifikasi pada Data Testing: Model menghasilkan performa generalisasi yang solid pada data testing independen: Akurasi 86,15%, Recall 98,18%, F1-Score 0,9231, dan nilai AUC = 0,8032 (excellent discrimination).

  6. Variabel yang Paling Kuat Hubungannya dengan Kelulusan:

    • Pendorong Kelulusan Terkuat: Variabel motivasi pendidikan tinggi (higher = yes) dengan Odds Ratio = 3,8021 (odds kelulusan meningkat 280,21%). Siswa yang memiliki orientasi masa depan akademik yang jelas memiliki dorongan internal yang kuat untuk menyelesaikan studinya.
    • Penghambat Kelulusan Terbesar: Variabel riwayat kegagalan kelas (failures) dengan Odds Ratio = 0,3909 (odds kelulusan merosot 60,91% untuk setiap kegagalan masa lalu). Riwayat kegagalan merupakan sinyal bahaya utama (red flag) yang membutuhkan intervensi pedagogis dini.
  7. Keterbatasan Penelitian:

    • Penelitian menggunakan data cross-sectional dari satu mata pelajaran (bahasa Portugis) di dua sekolah tertentu, sehingga generalisasi ke mata pelajaran eksakta (seperti Matematika) atau konteks sekolah lain perlu diuji lebih lanjut.
    • Terdapat ketidakseimbangan kelas (84,6% lulus vs 15,4% tidak lulus), yang menyebabkan spesifisitas pada threshold 0,50 bernilai rendah (20,0%). Pada skenario deteksi siswa berisiko, penyesuaian threshold klasifikasi dapat dipertimbangkan sesuai prioritas kebijakan sekolah.
    • Analisis mengidentifikasi hubungan asosiatif probabilistik dan tidak boleh diinterpretasikan sebagai hubungan sebab-akibat mutlak (causality).