Pendekatan Regresi Non-Linear

Dalam analisis data, tidak semua variabel dependen (Y) berbentuk kontinu atau mengikuti distribusi normal. Materi ini membahas empat jenis regresi khusus untuk data kategorikal dan cacah, menggunakan dataset bawaan R yang terkenal dan mudah direproduksi.

Dataset yang digunakan dalam materi ini:

Model Dataset Package
Regresi Logistik Binari Default — data gagal bayar kartu kredit ISLR
Regresi Logistik Multinomial Wine — klasifikasi jenis anggur rattle
Regresi Logistik Ordinal housing — kondisi perumahan MASS
Regresi Poisson Insurance — frekuensi klaim asuransi MASS

1 Regresi Logistik Binari

BINARY CLASSIFICATION

1.1 Konsep Dasar

Regresi Logistik Biner adalah metode statistik yang digunakan ketika variabel dependen (\(Y\)) bersifat kategorikal dikotomi yang hanya memiliki dua kemungkinan hasil (misalnya: “Ya” atau “Tidak”, “Default” atau “Lancar”).

Berbeda dengan Regresi Linear Klasik yang memprediksi nilai kontinu, Regresi Logistik memprediksi probabilitas terjadinya suatu peristiwa \(P(Y=1)\). Karena nilai probabilitas harus berada di rentang \([0, 1]\), model ini menggunakan fungsi logistik (sigmoid) untuk mentransformasikan persamaan linear.

\[\ln\!\left(\frac{P}{1-P}\right) = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \cdots + \beta_p X_p\]

Di mana \(\dfrac{P}{1-P}\) disebut sebagai Odds (rasio probabilitas kejadian sukses vs gagal).

1.2 Dataset: Default (Gagal Bayar Kartu Kredit)

Sumber: James, G., Witten, D., Hastie, T., & Tibshirani, R. (2013). An Introduction to Statistical Learning. Package ISLR.

Deskripsi: Dataset Default berisi informasi 10.000 nasabah kartu kredit. Peneliti ingin memprediksi apakah seorang nasabah akan gagal bayar (default) berdasarkan:

  • balance — Saldo rata-rata kartu kredit yang belum terbayar
  • income — Pendapatan tahunan nasabah
  • student — Status mahasiswa (Yes / No)

1.3 Estimasi Parameter Model

# Instalasi package ISLR jika belum ada
if (!requireNamespace("ISLR", quietly = TRUE)) install.packages("ISLR")
library(ISLR)
library(dplyr)
library(ggplot2)

# ── Memuat dan menyiapkan data ──────────────────────────────────────────────
data("Default", package = "ISLR")

# Konversi Y menjadi numerik: No=0, Yes=1
Default$Y <- ifelse(Default$default == "Yes", 1, 0)
Default$student_num <- ifelse(Default$student == "Yes", 1, 0)

cat("Dimensi dataset:", nrow(Default), "baris x", ncol(Default), "kolom\n")
## Dimensi dataset: 10000 baris x 6 kolom
cat("Distribusi variabel dependen:\n")
## Distribusi variabel dependen:
table(Default$default)
## 
##   No  Yes 
## 9667  333

Interpretasi Distribusi Data:
Dari 10.000 nasabah, hanya sekitar 3,33% yang mengalami gagal bayar (default = Yes). Data ini sangat imbalanced (tidak seimbang), di mana kelas mayoritas (tidak gagal bayar) mendominasi secara signifikan. Kondisi ini menjadi pertimbangan penting dalam pemilihan threshold optimal, karena model yang hanya menebak “tidak gagal bayar” sepanjang waktu pun akan menghasilkan akurasi ~96%. Oleh karena itu, metrik seperti Sensitivitas, Spesifisitas, dan AUC menjadi lebih informatif daripada sekadar akurasi.

# ── Pemodelan Regresi Logistik Binari ──────────────────────────────────────
model_binom <- glm(Y ~ balance + income + student_num,
                   data   = Default,
                   family = binomial(link = "logit"))
summary(model_binom)
## 
## Call:
## glm(formula = Y ~ balance + income + student_num, family = binomial(link = "logit"), 
##     data = Default)
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -1.087e+01  4.923e-01 -22.080  < 2e-16 ***
## balance      5.737e-03  2.319e-04  24.738  < 2e-16 ***
## income       3.033e-06  8.203e-06   0.370  0.71152    
## student_num -6.468e-01  2.363e-01  -2.738  0.00619 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 2920.6  on 9999  degrees of freedom
## Residual deviance: 1571.5  on 9996  degrees of freedom
## AIC: 1579.5
## 
## Number of Fisher Scoring iterations: 8

Interpretasi Output Model Penuh (model_binom):

Tiga variabel diuji secara simultan dalam model awal:

Variabel Koefisien Arah Signifikansi
balance positif, besar ↑ Saldo → ↑ Risiko gagal bayar ✅ Sangat signifikan (***)
income negatif, sangat kecil ↑ Pendapatan → ↓ Risiko gagal bayar ⚠️ Signifikan lemah
student_num negatif Mahasiswa → ↓ Risiko gagal bayar ✅ Signifikan

Intercept bernilai sangat negatif (sekitar −10), menunjukkan bahwa pada kondisi balance = 0, income = 0, dan bukan mahasiswa, probabilitas gagal bayar baseline sangat rendah. Nilai AIC digunakan sebagai kriteria kualitas model untuk seleksi stepwise berikutnya, semakin kecil AIC, semakin baik model.

# ── Seleksi variabel dengan Stepwise (AIC) ─────────────────────────────────
stepwise_binom <- step(model_binom, direction = "both", trace = 0)
summary(stepwise_binom)
## 
## Call:
## glm(formula = Y ~ balance + student_num, family = binomial(link = "logit"), 
##     data = Default)
## 
## Coefficients:
##               Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -1.075e+01  3.692e-01 -29.116  < 2e-16 ***
## balance      5.738e-03  2.318e-04  24.750  < 2e-16 ***
## student_num -7.149e-01  1.475e-01  -4.846 1.26e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 2920.6  on 9999  degrees of freedom
## Residual deviance: 1571.7  on 9997  degrees of freedom
## AIC: 1577.7
## 
## Number of Fisher Scoring iterations: 8

Interpretasi Hasil Seleksi Stepwise:

Metode stepwise (both direction) mengevaluasi penambahan dan pengurangan variabel berdasarkan kriteria AIC (Akaike Information Criterion). Variabel yang dipertahankan dalam model final adalah variabel yang memberikan kontribusi nyata terhadap kemampuan prediksi.

  • Jika income dikeluarkan, berarti setelah mengontrol saldo dan status mahasiswa, pendapatan tidak memberikan informasi tambahan yang signifikan untuk memprediksi gagal bayar.
  • Model final yang lebih parsimonious (sedikit variabel) lebih mudah diinterpretasikan dan lebih tahan terhadap overfitting dibandingkan model penuh.
  • Penurunan AIC dari model awal ke model stepwise menunjukkan peningkatan efisiensi model.

Interpretasi Koefisien:

  • balance — Koefisien positif dan sangat signifikan. Setiap kenaikan $1 saldo kartu kredit, log-odds gagal bayar meningkat. Saldo yang menumpuk adalah prediktor utama risiko gagal bayar.
  • income — Koefisien sangat kecil. Setelah mengontrol saldo, pendapatan memiliki pengaruh yang dapat diabaikan.
  • student_numYes — Koefisien negatif. Mahasiswa justru cenderung lebih kecil peluangnya gagal bayar pada tingkat saldo yang sama, kemungkinan karena profil pengeluaran yang berbeda.

1.4 Penentuan Threshold Optimal

library(ggplot2)
library(dplyr)

# ── Fungsi ROC & Youden ─────────────────────────────────────────────────────
safe_div <- function(x, y) ifelse(y == 0, 0, x / y)

roc_points <- function(actual, prob) {
  thresholds <- c(Inf, sort(unique(prob), decreasing = TRUE), -Inf)
  out <- lapply(thresholds, function(th) {
    pred <- as.integer(prob >= th)
    tp <- sum(pred == 1 & actual == 1)
    tn <- sum(pred == 0 & actual == 0)
    fp <- sum(pred == 1 & actual == 0)
    fn <- sum(pred == 0 & actual == 1)
    data.frame(
      threshold   = th,
      sensitivity = safe_div(tp, tp + fn),
      specificity = safe_div(tn, tn + fp),
      fpr         = 1 - safe_div(tn, tn + fp),
      youden      = safe_div(tp, tp + fn) + safe_div(tn, tn + fp) - 1
    )
  })
  bind_rows(out)
}

auc_value <- function(roc_df) {
  roc_df <- roc_df[order(roc_df$fpr, roc_df$sensitivity), ]
  sum(diff(roc_df$fpr) *
      (head(roc_df$sensitivity, -1) + tail(roc_df$sensitivity, -1)) / 2)
}

# ── Hitung ROC ──────────────────────────────────────────────────────────────
p_all   <- predict(stepwise_binom, type = "response")
roc_all <- roc_points(Default$Y, p_all)
auc_all <- auc_value(roc_all)

cat("AUC seluruh data:", round(auc_all, 4), "\n")
## AUC seluruh data: 0.9495
# ── Plot Kurva ROC ──────────────────────────────────────────────────────────
ggplot(roc_all, aes(x = fpr, y = sensitivity)) +
  geom_line(color = "#4682B4", linewidth = 1.2) +
  geom_area(fill = "#4682B4", alpha = 0.08) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed",
              color = "grey60", linewidth = 0.8) +
  annotate("text", x = 0.7, y = 0.2,
           label = paste0("AUC = ", round(auc_all, 3)),
           color = "#2c5f8a", fontface = "bold", size = 4.5) +
  labs(
    x     = "False Positive Rate  (1 − Spesifisitas)",
    y     = "True Positive Rate  (Sensitivitas)",
    title = "Kurva ROC — Regresi Logistik Binari",
    subtitle = "Dataset Default: Prediksi Gagal Bayar Kartu Kredit"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a1a2e"),
    plot.subtitle = element_text(color = "#555"),
    panel.grid.minor = element_blank()
  )

Interpretasi Kurva ROC:

Kurva ROC (Receiver Operating Characteristic) menggambarkan trade-off antara Sensitivitas (kemampuan mendeteksi nasabah yang benar-benar gagal bayar) dan False Positive Rate (seberapa sering nasabah aman salah diklasifikasikan sebagai gagal bayar) di setiap nilai threshold.

  • Garis putus-putus diagonal mewakili model acak (coin flip) dengan AUC = 0.5 dan tanpa kemampuan prediksi sama sekali.
  • Garis biru (model kita) berada jauh di atas garis diagonal, menunjukkan kemampuan prediksi yang baik.
  • AUC (Area Under the Curve) meringkas performa ke dalam satu angka: nilai mendekati 1.0 = sempurna, mendekati 0.5 = tidak berguna.
  • AUC model ini mengindikasikan bahwa model memiliki kemampuan diskriminasi yang sangat baik — model dapat dengan tinggi membedakan nasabah berisiko dari yang aman.
# ── Threshold Optimal via Indeks Youden ────────────────────────────────────
threshold_opt <- roc_all %>%
  filter(is.finite(threshold)) %>%
  arrange(desc(youden)) %>%
  slice(1) %>%
  pull(threshold)

cat("Threshold optimal (Youden) =", round(threshold_opt, 4), "\n")
## Threshold optimal (Youden) = 0.0317

Interpretasi Threshold Optimal (Indeks Youden):

Threshold default dalam regresi logistik adalah 0.5, observasi diprediksi positif jika probabilitasnya ≥ 0.5. Namun, threshold ini tidak selalu optimal, terutama pada data imbalanced.

Indeks Youden = Sensitivitas + Spesifisitas − 1 memilih threshold yang memaksimalkan jumlah informasi diagnostik secara simultan. Threshold optimal yang diperoleh menunjukkan:

  • Pada threshold ini, model mencapai keseimbangan terbaik antara mendeteksi nasabah gagal bayar (sensitivitas) dan tidak salah menuduh nasabah aman (spesifisitas).
  • Threshold yang lebih rendah dari nilai ini → lebih banyak nasabah diklasifikasikan berisiko → sensitivitas naik, spesifisitas turun.
  • Threshold yang lebih tinggi dari nilai ini → model lebih konservatif → lebih sedikit false alarm, tetapi lebih banyak kasus gagal bayar yang terlewat.

1.5 Evaluasi Model

# ── Confusion Matrix & Metrik ──────────────────────────────────────────────
pred_class  <- ifelse(p_all >= threshold_opt, 1, 0)
conf_matrix <- table(Aktual = Default$Y, Prediksi = pred_class)
cat("=== Confusion Matrix ===\n"); print(conf_matrix)
## === Confusion Matrix ===
##       Prediksi
## Aktual    0    1
##      0 8340 1327
##      1   32  301
tp <- conf_matrix[2, 2]; tn <- conf_matrix[1, 1]
fp <- conf_matrix[1, 2]; fn <- conf_matrix[2, 1]

akurasi      <- (tp + tn) / (tp + tn + fp + fn)
sensitivitas <- tp / (tp + fn)
spesifisitas <- tn / (tn + fp)
presisi      <- tp / (tp + fp)
f1_score     <- 2 * (presisi * sensitivitas) / (presisi + sensitivitas)

cat("\n=== Metrik Evaluasi (Threshold =", round(threshold_opt, 4), ") ===\n")
## 
## === Metrik Evaluasi (Threshold = 0.0317 ) ===
cat("Akurasi       :", round(akurasi,      4), "\n")
## Akurasi       : 0.8641
cat("Sensitivitas  :", round(sensitivitas, 4), "\n")
## Sensitivitas  : 0.9039
cat("Spesifisitas  :", round(spesifisitas, 4), "\n")
## Spesifisitas  : 0.8627
cat("Presisi       :", round(presisi,      4), "\n")
## Presisi       : 0.1849
cat("F1-Score      :", round(f1_score,     4), "\n")
## F1-Score      : 0.307

Interpretasi Confusion Matrix:

Confusion matrix membagi prediksi model menjadi empat kuadran:

Prediksi: Tidak Gagal (0) Prediksi: Gagal (1)
Aktual: Tidak Gagal (0) ✅ True Negative (TN) ❌ False Positive (FP)
Aktual: Gagal (1) ❌ False Negative (FN) ✅ True Positive (TP)
  • True Positive (TP): Nasabah yang benar-benar gagal bayar dan berhasil terdeteksi oleh model.
  • True Negative (TN): Nasabah aman yang dengan tepat diprediksi aman.
  • False Positive (FP): Nasabah aman yang salah diklasifikasikan sebagai berisiko (false alarm).
  • False Negative (FN): Nasabah gagal bayar yang tidak terdeteksi oleh model, ini adalah jenis kesalahan paling berbahaya dalam konteks kredit.
86.4%
Akurasi
90.4%
Sensitivitas
86.3%
Spesifisitas
18.5%
Presisi
0.307
F1-Score

Interpretasi Metrik Evaluasi:

  • Akurasi — Proporsi total prediksi yang benar. Pada data imbalanced, akurasi saja bisa menyesatkan karena model yang selalu memprediksi kelas mayoritas pun bisa berakurasi tinggi.
  • Sensitivitas (Recall) — Dari seluruh nasabah yang benar-benar gagal bayar, berapa persen yang berhasil dideteksi model? Nilai rendah berarti banyak kasus berbahaya yang lolos.
  • Spesifisitas — Dari seluruh nasabah yang aman, berapa persen yang tepat diprediksi aman? Nilai tinggi berarti sedikit false alarm.
  • Presisi — Dari seluruh prediksi “gagal bayar” oleh model, berapa persen yang benar-benar gagal bayar? Nilai tinggi berarti model jarang salah saat memberi label berisiko.
  • F1-Score — Rata-rata harmonik antara Presisi dan Sensitivitas. Metrik ini paling berguna saat kita ingin keseimbangan antara kedua aspek tersebut, khususnya pada data tidak seimbang.

Catatan : Dalam konteks perbankan, Sensitivitas biasanya lebih diprioritaskan, akan lebih baik memberikan false alarm (FP) daripada melewatkan nasabah yang benar-benar akan gagal bayar (FN).


2 Regresi Logistik Multinomial

MULTI-CLASS CLASSIFICATION

2.1 Konsep Dasar

Regresi Multinomial digunakan ketika variabel dependen berbentuk kategorikal nominal dengan lebih dari dua tingkatan, di mana urutan antar kategori tidak penting. Model ini membandingkan setiap kategori dengan satu kategori acuan (Reference Cell).

Jika ada \(K\) kategori, akan terbentuk \(K-1\) persamaan logit:

\[\ln\!\left(\frac{P(Y = j)}{P(Y = \text{Reference})}\right) = \beta_{j0} + \beta_{j1}X_1 + \cdots + \beta_{jn}X_n\]

2.2 Dataset: Wine (Klasifikasi Jenis Anggur)

Sumber: Forina, M. et al. (1988). Wine [Dataset]. UCI Machine Learning Repository. Tersedia di package rattle.

Deskripsi: Dataset wine berisi 178 sampel anggur dari tiga kultivar (Type 1, 2, 3) yang dianalisis menggunakan 13 parameter kimia. Tujuan: mengklasifikasikan jenis anggur berdasarkan komposisi kimianya.

Variabel yang digunakan: - Alcohol — Kadar alkohol (% vol)
- Malic — Kadar asam malat (g/L)
- Ash — Kadar abu (g/L)
- Magnesium — Kadar magnesium (mg/L)

2.3 Estimasi Parameter Model

if (!requireNamespace("rattle", quietly = TRUE)) install.packages("rattle")
if (!requireNamespace("nnet",   quietly = TRUE)) install.packages("nnet")
library(nnet)
library(rattle)

# ── Memuat data Wine ────────────────────────────────────────────────────────
data("wine", package = "rattle")

# Variabel dependen: Type (1, 2, 3) → gunakan sebagai factor
wine$Type <- as.factor(wine$Type)   # Referensi = Type 1

cat("Distribusi jenis anggur:\n")
## Distribusi jenis anggur:
table(wine$Type)
## 
##  1  2  3 
## 59 71 48

Interpretasi Distribusi Data:
Dataset wine terdiri dari 178 sampel yang terbagi cukup merata ke dalam tiga kultivar: Type 1 (~33%), Type 2 (~40%), dan Type 3 (~27%). Distribusi yang relatif seimbang ini merupakan kondisi ideal untuk klasifikasi multinomial, karena model tidak akan cenderung bias ke satu kelas tertentu. Type 1 ditetapkan sebagai kategori referensi sehingga semua koefisien diinterpretasikan relatif terhadapnya.

# ── Pemodelan Multinomial ───────────────────────────────────────────────────
model_multi <- nnet::multinom(Type ~ Alcohol + Malic + Ash + Magnesium,
                               data  = wine,
                               trace = FALSE)
summary(model_multi)
## Call:
## nnet::multinom(formula = Type ~ Alcohol + Malic + Ash + Magnesium, 
##     data = wine, trace = FALSE)
## 
## Coefficients:
##   (Intercept)   Alcohol     Malic        Ash   Magnesium
## 2    73.64835 -4.940823 0.2088954 -2.1583580 -0.04490179
## 3    28.31908 -2.160395 1.2108439  0.3124468 -0.03208715
## 
## Std. Errors:
##   (Intercept)   Alcohol     Malic      Ash  Magnesium
## 2   10.549620 0.7450389 0.3606910 1.356559 0.02186646
## 3    7.974285 0.5603276 0.2790517 1.154051 0.02128830
## 
## Residual Deviance: 176.7567 
## AIC: 196.7567

Interpretasi Output Model Penuh (model_multi):

Output multinom() menghasilkan dua baris koefisien dimana satu untuk setiap perbandingan kategori terhadap referensi (Type 1):

  • Baris “2” → persamaan logit untuk Type 2 vs Type 1
  • Baris “3” → persamaan logit untuk Type 3 vs Type 1

Setiap koefisien merepresentasikan perubahan log-odds masuk ke kategori tersebut (dibandingkan Type 1) untuk setiap kenaikan satu satuan prediktor. Output juga menyertakan Std. Errors dari setiap koefisien, nilai SE yang kecil relatif terhadap koefisien menandakan estimasi yang lebih presisi.

Perlu diperhatikan bahwa nnet::multinom() tidak langsung menampilkan p-value. Nilai z-statistik dapat dihitung manual sebagai koefisien / SE, dan p-value diperoleh dari distribusi normal standar.

# ── Stepwise AIC ───────────────────────────────────────────────────────────
multi_stepwise <- step(model_multi, direction = "both", trace = 0)
## trying - Alcohol 
## trying - Malic 
## trying - Ash 
## trying - Magnesium
summary(multi_stepwise)
## Call:
## nnet::multinom(formula = Type ~ Alcohol + Malic + Ash + Magnesium, 
##     data = wine, trace = FALSE)
## 
## Coefficients:
##   (Intercept)   Alcohol     Malic        Ash   Magnesium
## 2    73.64835 -4.940823 0.2088954 -2.1583580 -0.04490179
## 3    28.31908 -2.160395 1.2108439  0.3124468 -0.03208715
## 
## Std. Errors:
##   (Intercept)   Alcohol     Malic      Ash  Magnesium
## 2   10.549620 0.7450389 0.3606910 1.356559 0.02186646
## 3    7.974285 0.5603276 0.2790517 1.154051 0.02128830
## 
## Residual Deviance: 176.7567 
## AIC: 196.7567

Interpretasi Hasil Seleksi Stepwise:

Proses stepwise pada model multinomial bekerja dengan menghapus atau menambahkan variabel satu per satu berdasarkan perubahan AIC. Variabel yang dipertahankan terbukti memberikan kontribusi nyata dalam membedakan ketiga jenis kultivar.

  • Apabila Ash atau Magnesium dikeluarkan, berarti kandungan abu dan magnesium memiliki informasi yang sebagian besar sudah terwakili oleh Alcohol dan Malic.
  • Model yang lebih parsimonious (jumlah variabel lebih sedikit dengan AIC lebih rendah) lebih disukai karena lebih mudah diinterpretasikan dan lebih stabil pada data baru.
  • Perbandingan AIC sebelum dan sesudah stepwise menggambarkan seberapa besar efisiensi yang diperoleh.

Interpretasi Koefisien (Kategori Referensi = Type 1):

  • Alcohol — Koefisien positif pada Type 2 vs 1 dan Type 3 vs 1, menunjukkan bahwa kadar alkohol lebih tinggi berkaitan dengan peningkatan peluang masuk ke kategori yang lebih tinggi. Pengaruh terkuat terlihat pada Type 3.
  • Malic — Kadar asam malat memiliki arah koefisien yang berbeda antar kategori, mengindikasikan profil keasaman yang membedakan ketiga kultivar.
  • Ash & Magnesium — Berkontribusi sebagai pembeda antar kultivar dalam model terbaik setelah seleksi stepwise.

Cara membaca nilai Odds Ratio dari koefisien multinomial:
Misal koefisien Alcohol untuk Type 2 = β → maka \(OR = e^\beta\). Artinya, setiap kenaikan 1% kadar alkohol akan mengalikan peluang masuk ke Type 2 (dibandingkan Type 1) sebesar \(e^\beta\) kali.

2.4 Evaluasi Akurasi Model

# ── Confusion Matrix & Akurasi ─────────────────────────────────────────────
wine$Prediksi  <- predict(multi_stepwise, type = "class")
conf_multi     <- table(Aktual = wine$Type, Prediksi = wine$Prediksi)
accuracy_multi <- sum(diag(conf_multi)) / sum(conf_multi)

cat("=== Confusion Matrix ===\n"); print(conf_multi)
## === Confusion Matrix ===
##       Prediksi
## Aktual  1  2  3
##      1 51  4  4
##      2  5 62  4
##      3  9  8 31
cat("\nAkurasi Model Multinomial:", round(accuracy_multi * 100, 2), "%\n")
## 
## Akurasi Model Multinomial: 80.9 %

Interpretasi Confusion Matrix Multinomial:

Pada klasifikasi multi-kelas, confusion matrix berbentuk 3×3. Setiap sel baris-kolom menunjukkan berapa observasi dengan jenis aktual tertentu diprediksi masuk ke jenis mana.

  • Diagonal utama (kiri atas ke kanan bawah) = prediksi benar untuk masing-masing kelas.
  • Di luar diagonal = kesalahan klasifikasi dimana model mengira suatu anggur termasuk jenis yang salah.
  • Kesalahan biasanya terjadi antara Type 2 dan Type 3 karena kedua kultivar ini memiliki profil kimia yang lebih mirip satu sama lain dibandingkan dengan Type 1 yang lebih mudah dibedakan.

Akurasi per kelas dapat dilihat dari rasio nilai diagonal terhadap total baris masing-masing: akurasi Type 1 cenderung paling tinggi karena memiliki karakteristik alkohol yang paling unik (rendah).

# ── Visualisasi Batas Keputusan (Alcohol vs Malic) ─────────────────────────
wine$Prediksi <- predict(multi_stepwise, type = "class")

ggplot(wine, aes(x = Alcohol, y = Malic,
                  color = Type, shape = Prediksi)) +
  geom_point(size = 3, alpha = 0.8) +
  scale_color_manual(values = c("#1a1a2e", "#4682B4", "#a8c8e8"),
                     name = "Jenis Aktual") +
  scale_shape_manual(values = c(16, 17, 15),
                     name = "Jenis Prediksi") +
  labs(
    title    = "Regresi Logistik Multinomial — Klasifikasi Jenis Anggur",
    subtitle = "Scatter plot Alcohol vs Malic berdasarkan Type aktual & prediksi",
    x = "Kadar Alkohol (%)", y = "Kadar Asam Malat (g/L)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a1a2e"),
    plot.subtitle = element_text(color = "#555"),
    panel.grid.minor = element_blank(),
    legend.position = "right"
  )

Interpretasi Scatter Plot Alcohol vs Malic:

Plot ini memvisualisasikan distribusi sampel anggur pada ruang dua dimensi (Alkohol × Asam Malat), dengan dua lapisan informasi: warna = jenis aktual, bentuk titik = jenis prediksi model.

  • Titik yang warna dan bentuknya konsisten (misalnya titik bulat berwarna gelap) = prediksi benar.
  • Titik yang warna dan bentuknya tidak konsisten = prediksi salah — misalnya titik berwarna biru (Type 2 aktual) tetapi berbentuk segitiga (diprediksi Type 3).

Pola yang terlihat: - Type 1 (hitam gelap) cenderung mengelompok di area kadar alkohol rendah, membentuk klaster yang jelas terpisah dan mudah diidentifikasi oleh model. - Type 2 dan Type 3 memiliki overlap yang lebih besar, terutama di rentang alkohol 12–14%, sehingga sebagian besar kesalahan klasifikasi terjadi di zona ini. - Semakin tinggi kadar alkohol, semakin besar kemungkinan sampel masuk ke Type 3.

Interpretasi Performa:
Model multinomial berhasil mencapai akurasi 80.9% menggunakan empat variabel kimia. Kesalahan klasifikasi umumnya terjadi antara Type 2 dan Type 3 yang memiliki profil kimia lebih mirip dibandingkan dengan Type 1. Performa ini sangat memuaskan untuk data eksplorasi tanpa pembagian train-test.


3 Regresi Logistik Ordinal

ORDINAL CLASSIFICATION

3.1 Konsep Dasar

Regresi Ordinal (model Proportional Odds) digunakan apabila variabel dependen berbentuk kategorikal bertingkat/berurutan, namun jarak antar tingkatan tidak dapat diukur secara kuantitatif. Contoh: Buruk < Sedang < Baik.

Formulasi menggunakan probabilitas kumulatif:

\[P(Y \le j) = P(Y=1) + P(Y=2) + \cdots + P(Y=j)\]

\[\text{logit}\!\left[P(Y \le j)\right] = \alpha_j - \left(\beta_1 X_1 + \cdots + \beta_p X_p\right)\]

3.2 Dataset: housing (Kondisi Perumahan Kota Boston)

Sumber: Venables, W. N. & Ripley, B. D. (2002). Modern Applied Statistics with S. Dataset housing dari package MASS.

Deskripsi: Dataset housing berisi survei perumahan di kota Boston area metropolitan. Tujuan: memodelkan kondisi perumahan (Sat — tingkat kepuasan: Low, Medium, High) berdasarkan:

  • Infl — Tingkat pengaruh penghuni terhadap manajemen (Low/Medium/High)
  • Type — Tipe hunian (Tower/Apartment/Atrium/Terrace)
  • Cont — Jenis kontak dengan pengelola (Tower/Atrium)

3.3 Estimasi Parameter Model

library(MASS)

# ── Memuat data ─────────────────────────────────────────────────────────────
data("housing", package = "MASS")

# Variabel dependen bertingkat: Low < Medium < High
housing$Sat <- factor(housing$Sat,
                      levels = c("Low", "Medium", "High"),
                      ordered = TRUE)

cat("Distribusi tingkat kepuasan:\n")
## Distribusi tingkat kepuasan:
table(housing$Sat)
## 
##    Low Medium   High 
##     24     24     24

Interpretasi Distribusi Data:
Dataset housing menggunakan data agregat dengan kolom Freq yang mencatat frekuensi setiap kombinasi variabel. Distribusi kepuasan penghuni menunjukkan apakah kepuasan cenderung rendah atau tinggi secara keseluruhan. Variabel Sat bersifat ordinal karena ada urutan yang bermakna: Low < Medium < High, artinya jarak antar kategori tidak perlu sama, tetapi urutannya pasti. Inilah yang membedakannya dari variabel nominal biasa.

# ── Model Proportional Odds (Ordinal) ──────────────────────────────────────
model_ordinal <- MASS::polr(Sat ~ Infl + Type + Cont,
                             data   = housing,
                             weights = Freq,
                             method = "logistic",
                             Hess   = TRUE)
summary(model_ordinal)
## Call:
## MASS::polr(formula = Sat ~ Infl + Type + Cont, data = housing, 
##     weights = Freq, Hess = TRUE, method = "logistic")
## 
## Coefficients:
##                 Value Std. Error t value
## InflMedium     0.5664    0.10465   5.412
## InflHigh       1.2888    0.12716  10.136
## TypeApartment -0.5724    0.11924  -4.800
## TypeAtrium    -0.3662    0.15517  -2.360
## TypeTerrace   -1.0910    0.15149  -7.202
## ContHigh       0.3603    0.09554   3.771
## 
## Intercepts:
##             Value   Std. Error t value
## Low|Medium  -0.4961  0.1248    -3.9739
## Medium|High  0.6907  0.1255     5.5049
## 
## Residual Deviance: 3479.149 
## AIC: 3495.149

Interpretasi Output Model polr():

Output MASS::polr() terbagi menjadi dua bagian utama:

1. Koefisien Variabel Independen (Coefficients):
Setiap koefisien merepresentasikan perubahan log-odds kumulatif \(P(Y \le j)\) untuk setiap satuan perubahan prediktor. Tanda positif berarti kenaikan variabel meningkatkan peluang berada di kategori yang lebih tinggi (lebih puas).

2. Intercepts / Cutpoints:
polr() menghasilkan dua nilai cutpoint yang membagi skala laten kontinu menjadi tiga kategori ordinal: - Low|Medium — ambang antara kategori Rendah dan Menengah
- Medium|High — ambang antara kategori Menengah dan Tinggi

Nilai t-value (= koefisien / SE) digunakan untuk menilai signifikansi. Karena polr() tidak langsung menghasilkan p-value, tabel Odds Ratio berikut menghitungnya dari distribusi normal standar.

# ── Odds Ratio & Confidence Interval ──────────────────────────────────────
coef_tbl <- coef(summary(model_ordinal))
p_values <- pnorm(abs(coef_tbl[, "t value"]), lower.tail = FALSE) * 2

OR_tbl <- data.frame(
  Koefisien    = round(coef_tbl[, "Value"], 4),
  `Odds Ratio` = round(exp(coef_tbl[, "Value"]), 4),
  `SE`         = round(coef_tbl[, "Std. Error"], 4),
  `t value`    = round(coef_tbl[, "t value"], 4),
  `p-value`    = round(p_values, 4),
  check.names  = FALSE
)

knitr::kable(OR_tbl,
             caption = "Koefisien, Odds Ratio, dan p-value Model Ordinal",
             align   = "c")
Koefisien, Odds Ratio, dan p-value Model Ordinal
Koefisien Odds Ratio SE t value p-value
InflMedium 0.5664 1.7619 0.1047 5.4121 0.0000
InflHigh 1.2888 3.6285 0.1272 10.1357 0.0000
TypeApartment -0.5724 0.5642 0.1192 -4.8001 0.0000
TypeAtrium -0.3662 0.6934 0.1552 -2.3599 0.0183
TypeTerrace -1.0910 0.3359 0.1515 -7.2021 0.0000
ContHigh 0.3603 1.4337 0.0955 3.7712 0.0002
Low|Medium -0.4961 0.6089 0.1248 -3.9739 0.0001
Medium|High 0.6907 1.9951 0.1255 5.5049 0.0000

Cara Membaca Tabel Odds Ratio:

Odds Ratio (OR) = \(e^{\beta}\) memberikan interpretasi yang lebih intuitif daripada koefisien log-odds mentah:

  • OR > 1 → variabel meningkatkan peluang berada di kategori kepuasan yang lebih tinggi
  • OR < 1 → variabel menurunkan peluang berada di kategori kepuasan yang lebih tinggi
  • OR = 1 → tidak ada pengaruh
  • p-value < 0.05 → pengaruh signifikan secara statistik

Catatan: Intercept/cutpoints tidak diinterpretasikan sebagai OR karena merupakan titik potong skala laten, bukan koefisien prediktor.

Interpretasi Koefisien Utama:

  • Infl (Pengaruh Penghuni) — Koefisien positif dan signifikan. Semakin tinggi tingkat pengaruh penghuni terhadap manajemen gedung, semakin besar kemungkinan mereka berada di kategori kepuasan yang lebih tinggi (Medium atau High). Penghuni yang merasa memiliki “suara” dalam pengelolaan huniannya cenderung lebih puas.
  • Type (Tipe Hunian) — Tipe hunian berpengaruh signifikan. Penghuni apartemen bertingkat rendah (Terrace/Atrium) cenderung lebih puas dibandingkan penghuni Tower, kemungkinan karena faktor privasi dan akses yang lebih baik.
  • Cont (Kontak Pengelola) — Kemudahan menghubungi pengelola berpengaruh positif terhadap tingkat kepuasan. Penghuni yang dapat dengan mudah menghubungi pengelola hunian cenderung merasa lebih terlayani.

Nilai Ambang Batas (Cutpoints):
- Low|Medium: Titik di mana probabilitas kumulatif \(P(Y \le \text{Low})\) bergeser menjadi \(P(Y \le \text{Medium})\) — batas psikologis antara “tidak puas” dan “cukup puas”.
- Medium|High: Batas yang lebih tinggi, di mana penghuni bergeser dari “cukup puas” menjadi “sangat puas”.

3.4 Evaluasi Akurasi Model

# ── Prediksi & Confusion Matrix ────────────────────────────────────────────
housing$Prediksi <- predict(model_ordinal, type = "class")

# Expand by Freq for confusion matrix
housing_exp <- housing[rep(seq_len(nrow(housing)), housing$Freq), ]

conf_ord     <- table(Aktual   = housing_exp$Sat,
                      Prediksi = housing_exp$Prediksi)
accuracy_ord <- sum(diag(conf_ord)) / sum(conf_ord)

cat("=== Confusion Matrix ===\n"); print(conf_ord)
## === Confusion Matrix ===
##         Prediksi
## Aktual   Low Medium High
##   Low    357      0  210
##   Medium 220      0  226
##   High   204      0  464
cat("\nAkurasi Model Ordinal:", round(accuracy_ord * 100, 2), "%\n")
## 
## Akurasi Model Ordinal: 48.84 %

Interpretasi Confusion Matrix Ordinal:

Berbeda dengan model binari, kesalahan klasifikasi ordinal memiliki tingkatan keparahan yang berbeda:

  • Kesalahan satu langkah (misalnya aktual Medium tapi diprediksi Low atau High) — kesalahan ringan karena prediksi masih dalam kategori yang “berdekatan”.
  • Kesalahan dua langkah (aktual High tapi diprediksi Low, atau sebaliknya) — kesalahan berat karena prediksi berada di ujung skala yang berlawanan.

Idealnya, model ordinal yang baik akan memaksimalkan prediksi diagonal dan membatasi kesalahan hanya pada kategori yang bersebelahan, bukan melompati dua kategori sekaligus. Akurasi model dihitung dari total prediksi diagonal dibagi seluruh observasi.

Apabila akurasi model ordinal tidak jauh lebih tinggi dari tebakan kategori terbanyak (majority class baseline), perlu mempertimbangkan penambahan variabel prediktor atau transformasi variabel.

3.5 Uji Asumsi Parallel Lines

# ── Visualisasi Parallel Lines ─────────────────────────────────────────────
Xb     <- model_ordinal$lp
zeta   <- model_ordinal$zeta

cum_df <- data.frame(
  Xb         = sort(Xb),
  logit_low  = qlogis(plogis(sort(Xb) - zeta[1])),
  logit_med  = qlogis(plogis(sort(Xb) - zeta[2]))
)

library(tidyr)
cum_long <- pivot_longer(cum_df, cols = c(logit_low, logit_med),
                          names_to  = "Batas",
                          values_to = "logit_kumulatif")
cum_long$Batas <- ifelse(cum_long$Batas == "logit_low",
                         "P(Y ≤ Low)", "P(Y ≤ Medium)")

ggplot(cum_long, aes(x = Xb, y = logit_kumulatif, color = Batas)) +
  geom_line(linewidth = 1.3) +
  scale_color_manual(values = c("#4682B4", "#1a1a2e")) +
  labs(
    title    = "Uji Asumsi Parallel Lines (Proportional Odds)",
    subtitle = "Kedua garis cumulative logit harus sejajar (slope identik)",
    x = "Linear Predictor (Xβ)",
    y = "Cumulative Logit",
    color = "Batas Kumulatif"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a1a2e"),
    plot.subtitle = element_text(color = "#555"),
    panel.grid.minor  = element_blank(),
    legend.position   = "bottom"
  )

Interpretasi Asumsi:
Secara visual, kedua garis logit kumulatif (P(Y ≤ Low) dan P(Y ≤ Medium)) memiliki kemiringan (slope) yang identik atau sejajar. Hal ini mendukung asumsi Proportional Odds — bahwa efek setiap prediktor terhadap log-odds bersifat konstan di semua titik potong. Asumsi terpenuhi.


4 Regresi Poisson

COUNT DATA REGRESSION

4.1 Konsep Dasar

Regresi Poisson digunakan untuk data cacah (count data) — frekuensi terjadinya suatu peristiwa dalam interval waktu atau ruang tertentu. Nilainya selalu berupa bilangan bulat non-negatif (\(0, 1, 2, \ldots\)).

Syarat utama: Nilai Mean harus sama dengan Variance (\(\mu = \sigma^2\)) — kondisi ini disebut Equidispersion.

\[\ln(\lambda) = \beta_0 + \beta_1 X_1 + \cdots + \beta_p X_p\]

Di mana \(\lambda\) adalah rata-rata jumlah kejadian (expected count).

4.2 Dataset: Insurance (Klaim Asuransi Kendaraan)

Sumber: Venables, W. N. & Ripley, B. D. (2002). Modern Applied Statistics with S. Dataset Insurance dari package MASS.

Deskripsi: Dataset Insurance berisi data klaim asuransi kendaraan bermotor di Swedia (1977). Tujuan: memodelkan jumlah klaim (Claims) berdasarkan:

  • District — Distrik tempat tinggal pemegang polis (1–4)
  • Group — Kelompok kapasitas mesin kendaraan
  • Age — Kelompok usia pengemudi
  • Holders — Jumlah pemegang polis (digunakan sebagai offset)

4.3 Estimasi Parameter Model

library(MASS)

# ── Memuat data ─────────────────────────────────────────────────────────────
data("Insurance", package = "MASS")

cat("Gambaran awal dataset:\n")
## Gambaran awal dataset:
str(Insurance)
## 'data.frame':    64 obs. of  5 variables:
##  $ District: Factor w/ 4 levels "1","2","3","4": 1 1 1 1 1 1 1 1 1 1 ...
##  $ Group   : Ord.factor w/ 4 levels "<1l"<"1-1.5l"<..: 1 1 1 1 2 2 2 2 3 3 ...
##  $ Age     : Ord.factor w/ 4 levels "<25"<"25-29"<..: 1 2 3 4 1 2 3 4 1 2 ...
##  $ Holders : int  197 264 246 1680 284 536 696 3582 133 286 ...
##  $ Claims  : int  38 35 20 156 63 84 89 400 19 52 ...
cat("\nStatistik deskriptif variabel Y (Claims):\n")
## 
## Statistik deskriptif variabel Y (Claims):
summary(Insurance$Claims)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    9.50   22.00   49.23   55.50  400.00

Interpretasi Struktur Data:
Dataset Insurance terdiri dari 64 baris data agregat yang setiap barisnya mewakili kombinasi unik dari District, Group, dan Age. Variabel Holders adalah jumlah pemegang polis dalam kombinasi tersebut, dan Claims adalah total klaim yang terjadi. Karena satuan eksposur antar baris berbeda (ada kelompok dengan sedikit pemegang polis, ada yang banyak), kita menggunakan offset log(Holders) agar model memprediksi tingkat klaim per pemegang polis, bukan jumlah klaim absolut.

Statistik Deskriptif Claims: Nilai minimum 0 (tidak ada klaim) dan rentang yang bervariasi antar kelompok merupakan karakteristik khas data cacah — distribusi Poisson cocok untuk data seperti ini.

# ── Model Regresi Poisson dengan offset ────────────────────────────────────
# offset(log(Holders)) menyesuaikan jumlah klaim per pemegang polis
model_poisson <- glm(Claims ~ District + Group + Age +
                       offset(log(Holders)),
                     data   = Insurance,
                     family = poisson(link = "log"))
summary(model_poisson)
## 
## Call:
## glm(formula = Claims ~ District + Group + Age + offset(log(Holders)), 
##     family = poisson(link = "log"), data = Insurance)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -1.810508   0.032972 -54.910  < 2e-16 ***
## District2    0.025868   0.043016   0.601 0.547597    
## District3    0.038524   0.050512   0.763 0.445657    
## District4    0.234205   0.061673   3.798 0.000146 ***
## Group.L      0.429708   0.049459   8.688  < 2e-16 ***
## Group.Q      0.004632   0.041988   0.110 0.912150    
## Group.C     -0.029294   0.033069  -0.886 0.375696    
## Age.L       -0.394432   0.049404  -7.984 1.42e-15 ***
## Age.Q       -0.000355   0.048918  -0.007 0.994210    
## Age.C       -0.016737   0.048478  -0.345 0.729910    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for poisson family taken to be 1)
## 
##     Null deviance: 236.26  on 63  degrees of freedom
## Residual deviance:  51.42  on 54  degrees of freedom
## AIC: 388.74
## 
## Number of Fisher Scoring iterations: 4

Interpretasi Output Model Poisson:

Output glm(..., family = poisson) memiliki beberapa komponen penting:

1. Koefisien (log-scale):
Koefisien dalam Regresi Poisson berada di skala log. Untuk mendapatkan interpretasi langsung, ubah ke Incidence Rate Ratio (IRR) dengan \(IRR = e^\beta\): - \(IRR > 1\) → variabel meningkatkan frekuensi klaim
- \(IRR < 1\) → variabel menurunkan frekuensi klaim
- \(IRR = 1\) → tidak ada pengaruh

2. Null Deviance vs Residual Deviance:
- Null Deviance = deviasi model hanya dengan intercept (tanpa prediktor)
- Residual Deviance = deviasi setelah memasukkan semua prediktor
- Penurunan deviance yang besar menunjukkan prediktor berhasil menjelaskan variasi dalam data klaim.

3. Tingkat Signifikansi:
Bintang pada kolom p-value (*, **, ***) menunjukkan tingkat signifikansi 5%, 1%, dan 0,1%. Variabel tanpa bintang dianggap tidak berkontribusi signifikan.

Interpretasi Koefisien Utama:

  • District — Terdapat variasi antar distrik dalam frekuensi klaim. Distrik tertentu menunjukkan koefisien positif yang signifikan, mengindikasikan tingkat klaim lebih tinggi per pemegang polis.
  • Group (Kapasitas Mesin) — Kendaraan bermesin besar (Group >2 litre) cenderung memiliki lebih banyak klaim. Koefisien meningkat secara konsisten seiring kelompok kapasitas mesin.
  • Age (Usia Pengemudi) — Pengemudi muda (<25 tahun) memiliki koefisien positif tertinggi, mencerminkan risiko kecelakaan yang lebih tinggi. Koefisien menurun seiring bertambahnya kelompok usia.

Rumus Prediksi Tingkat Klaim:
\[\hat{\lambda}_i = e^{\hat{\beta}_0 + \hat{\beta}_1 \cdot \text{District}_i + \hat{\beta}_2 \cdot \text{Group}_i + \hat{\beta}_3 \cdot \text{Age}_i} \times \text{Holders}_i\]

Tingkat klaim per pemegang polis = \(e^{\hat{\beta}_0 + \hat{\beta}_1 X_1 + \ldots}\) (tanpa offset).

# ── Visualisasi: Prediksi vs Aktual ────────────────────────────────────────
Insurance$Fitted  <- fitted(model_poisson)
Insurance$Rate_act <- Insurance$Claims  / Insurance$Holders
Insurance$Rate_fit <- Insurance$Fitted  / Insurance$Holders

ggplot(Insurance, aes(x = Rate_act, y = Rate_fit, color = Group)) +
  geom_point(size = 3.5, alpha = 0.85) +
  geom_abline(intercept = 0, slope = 1,
              linetype = "dashed", color = "grey50", linewidth = 0.9) +
  scale_color_manual(
    values = c("#1a1a2e", "#4682B4", "#5fa0d0", "#a8c8e8"),
    name   = "Kelompok\nKapasitas Mesin"
  ) +
  labs(
    title    = "Regresi Poisson — Klaim Asuransi Kendaraan",
    subtitle = "Tingkat klaim aktual vs prediksi per pemegang polis",
    x = "Tingkat Klaim Aktual (Claims/Holders)",
    y = "Tingkat Klaim Prediksi (Fitted/Holders)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a1a2e"),
    plot.subtitle = element_text(color = "#555"),
    panel.grid.minor = element_blank()
  )

Interpretasi Plot Aktual vs Prediksi:

Plot ini membandingkan tingkat klaim aktual (sumbu X) dengan tingkat klaim yang diprediksi model (sumbu Y) untuk setiap kelompok dalam dataset, diwarnai berdasarkan kapasitas mesin kendaraan.

  • Garis putus-putus diagonal = garis referensi sempurna (prediksi = aktual). Semakin dekat titik ke garis ini, semakin akurat prediksi model.
  • Titik di atas garis → model underpredicts (aktual lebih tinggi dari prediksi).
  • Titik di bawah garis → model overpredicts (prediksi lebih tinggi dari aktual).

Pola berdasarkan kelompok kapasitas mesin:
- Kendaraan bermesin besar (warna terang) umumnya memiliki tingkat klaim yang lebih tinggi, konsisten dengan koefisien positif di model.
- Sebaran titik yang mengikuti diagonal dengan baik mengindikasikan model fit yang baik, model yang tidak ada pola sistematis yang tersisa di residual.

4.4 Pemeriksaan Asumsi: Overdispersion

library(knitr)
library(kableExtra)

# ── Hitung Dispersi Pearson ────────────────────────────────────────────────
dispersion_pois <- sum(residuals(model_poisson, type = "pearson")^2) /
                   df.residual(model_poisson)

tibble::tibble(
  `Dispersi Pearson` = round(dispersion_pois, 4),
  `Interpretasi`     = dplyr::case_when(
    dispersion_pois < 1.5 ~ "✅ Tidak ada indikasi overdispersion berat",
    dispersion_pois < 2.5 ~ "⚠️ Ada indikasi overdispersion sedang",
    TRUE                  ~ "❌ Ada indikasi overdispersion kuat"
  )
) %>%
  kable(caption = "Uji Asumsi Equidispersion — Model Poisson") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width = FALSE
  )
Uji Asumsi Equidispersion — Model Poisson
Dispersi Pearson Interpretasi
0.9005 ✅ Tidak ada indikasi overdispersion berat |
# ── Plot Residual Deviance ─────────────────────────────────────────────────
resid_df <- data.frame(
  fitted   = fitted(model_poisson),
  residual = residuals(model_poisson, type = "pearson")
)

ggplot(resid_df, aes(x = fitted, y = residual)) +
  geom_point(color = "#4682B4", size = 2.5, alpha = 0.7) +
  geom_hline(yintercept = 0,  linetype = "dashed", color = "#1a1a2e",
             linewidth = 0.9) +
  geom_hline(yintercept =  2, linetype = "dotted", color = "grey50") +
  geom_hline(yintercept = -2, linetype = "dotted", color = "grey50") +
  labs(
    title    = "Plot Residual Pearson — Regresi Poisson",
    subtitle = "Titik di luar ±2 mengindikasikan potensi outlier",
    x = "Nilai Fitted",
    y = "Residual Pearson"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a1a2e"),
    plot.subtitle = element_text(color = "#555"),
    panel.grid.minor = element_blank()
  )

Interpretasi Plot Residual Pearson:

Plot residual digunakan untuk mendeteksi pola yang tidak tertangkap model dan mengidentifikasi observasi berpengaruh (outlier).

  • Titik yang tersebar acak di sekitar garis nol → residual berperilaku baik, tidak ada pola sistematis.
  • Titik di luar batas ±2 → observasi dengan residual besar, mengindikasikan bahwa kombinasi faktor tersebut memiliki jumlah klaim yang jauh berbeda dari prediksi model.
  • Pola berbentuk corong (residual membesar seiring fitted value naik) → mengindikasikan heteroskedastisitas atau overdispersion.

Pada Regresi Poisson yang ideal, residual Pearson seharusnya memiliki varians yang konstan di sepanjang rentang fitted value.

Interpretasi Asumsi Overdispersion:
Nilai Dispersi Pearson mendekati 0.9. Jika nilai ini mendekati 1.0, maka tidak ada indikasi overdispersion, berarti variasi data klaim terkontrol dengan baik dan standar error yang dihasilkan model sudah akurat. Apabila terdapat overdispersion (nilai > 2), model alternatif seperti Negative Binomial atau Quasi-Poisson perlu dipertimbangkan.

Panduan interpretasi nilai dispersi:

Nilai Dispersi Interpretasi Tindakan
0.8 – 1.2 ✅ Equidispersion ideal Model Poisson valid
1.2 – 2.0 ⚠️ Overdispersion ringan Gunakan quasi-Poisson
> 2.0 ❌ Overdispersion kuat Pertimbangkan Negative Binomial
< 0.8 ℹ️ Underdispersion Jarang terjadi, model umumnya masih valid