1 Persiapan Data

1.1 Load Library

# ── Manipulasi Data ───────────────────────────────────────────────
library(foreign)           # read.dbf
library(dplyr)
library(readxl)            # read_excel
library(tidyr)

# ── Visualisasi ───────────────────────────────────────────────────
library(highcharter)       # interactive charts
library(htmltools)         # tagList, HTML

# ── Pemodelan ─────────────────────────────────────────────────────
library(ResourceSelection) # Hosmer-Lemeshow
library(lmtest)            # lrtest
library(logistf)           # Firth logistic regression
library(smotefamily)       # SMOTE oversampling
library(pROC)              # ROC-AUC
library(survey)            # estimasi tertimbang & confidence interval

# ── Output Tabel ──────────────────────────────────────────────────
library(knitr)
library(kableExtra)

1.2 Load Data Utama (SUSENAS 2023)

Data utama yang digunakan adalah data individu SUSENAS 2023 dalam format .dbf.

data_susenas <- read.dbf("D:/Altytan Semester 7/Skripsi Rampunggg/Data Pengolahan/46654/Susenas KOR maret 2023/bv2_2026_02_22_08_59_08_ssn202303kor_ind_1.dbf")

1.3 Filter Populasi Studi

Populasi studi adalah anak penyandang disabilitas usia 13–15 tahun yang berdomisili di Kawasan Timur Indonesia

Variabel kunci yang dibentuk pada tahap ini:

  • JUMLAH_JENIS_DISABILITAS: jumlah jenis disabilitas yang dialami anak (dari R1002–R1009).
  • status (Variabel Y): partisipasi sekolah — 1 = sedang bersekolah, 0 = tidak bersekolah.
allowed_vals <- c(1, 2, 3, 5, 6, 7)

dataku_filtered <- data_susenas %>%
  mutate(
    across(R1002:R1009, ~ as.numeric(.x)),

    JUMLAH_JENIS_DISABILITAS = rowSums(
      across(R1002:R1009, ~ .x %in% allowed_vals),
      na.rm = TRUE
    ),

    prov = as.numeric(R101),
    kabu = as.numeric(R101) * 100 + as.numeric(R102),

    # Y: Partisipasi Sekolah (1 = Bersekolah, 0 = Tidak Bersekolah)
    status = ifelse(
      R407 >= 13 & R407 <= 15 & JUMLAH_JENIS_DISABILITAS > 0,
      ifelse(R610 == 2, 1, 0),
      NA_real_
    )
  ) %>%
  filter(
    R407 >= 13 & R407 <= 15,
    JUMLAH_JENIS_DISABILITAS > 0,
    as.numeric(R101) %in% c(52:53, 71:76, 81:82, 91:97)
  )

cat("Jumlah observasi setelah filter:", nrow(dataku_filtered), "\n")
Jumlah observasi setelah filter: 236 

1.4 Variabel Kepala Rumah Tangga (X4, X5, X6)

Variabel karakteristik kepala rumah tangga (KRT) diekstrak dari baris dengan R403 == 1 (penanda KRT dalam data).

Variabel Deskripsi Kategori
X4 Jenis kelamin KRT 0 = Perempuan*; 1 = Laki-laki
X5 Pendidikan KRT 0 = ≤ SMP/Sederajat*; 1 = Minimal SMA/Sederajat
X6 Pekerjaan KRT 0 = Tidak bekerja*; 1 = Pertanian; 2 = Nonpertanian
id_rt <- c("URUT")

data_krt <- data_susenas %>%
  filter(as.numeric(R403) == 1) %>%
  mutate(
    R405 = as.numeric(R405),
    R614 = as.numeric(R614),
    R705 = as.numeric(R705),
    R706 = as.numeric(R706),

    # X4: Jenis Kelamin KRT
    X4 = case_when(
      R405 == 1 ~ 1L,
      R405 == 2 ~ 0L,
      TRUE      ~ NA_integer_
    ),

    # X5: Tingkat Pendidikan KRT
    X5 = case_when(
      R614 >= 11 & R614 <= 24   ~ 1L,
      R614 %in% c(0:10, 25)     ~ 0L,
      TRUE                      ~ NA_integer_
    ),

    # X6: Pekerjaan KRT
    # 0 = Tidak bekerja; 1 = Pertanian; 2 = Nonpertanian
    X6 = case_when(
      R706 >= 1 & R706 <= 6     ~ 1L,
      R706 >= 7 & R706 <= 26    ~ 2L,
      R705 == 5                 ~ 0L,
      TRUE                      ~ NA_integer_
    )
  ) %>%
  select(all_of(id_rt), X4, X5, X6)

1.5 Variabel Kemiskinan Rumah Tangga (X9)

Data pengeluaran per kapita (KAPITA) dari data KP Blok 4.3 digabung dengan Garis Kemiskinan (GK) provinsi/daerah untuk membentuk variabel status kemiskinan.

files_43 <- c(
  "D:/Altytan Semester 7/Skripsi Rampunggg/Data Pengolahan/46654/Susenas KP Maret 2023/bv2_2026_02_22_08_55_02_ssn202303kp_blok43_51_94.dbf",
  "D:/Altytan Semester 7/Skripsi Rampunggg/Data Pengolahan/46654/Susenas KP Maret 2023/bv2_2026_02_22_08_49_01_ssn202303kp_blok43_11_31.dbf",
  "D:/Altytan Semester 7/Skripsi Rampunggg/Data Pengolahan/46654/Susenas KP Maret 2023/bv2_2026_02_22_08_52_06_ssn202303kp_blok43_32_36.dbf"
)

data_kp_43 <- bind_rows(lapply(files_43, read.dbf, as.is = TRUE)) %>%
  mutate(
    R101 = as.numeric(R101),
    R102 = as.numeric(R102),
    URUT = as.numeric(URUT)
  )

GK <- read_excel(
  "D:/Altytan Semester 7/Skripsi Rampunggg/Data Pengolahan/Garis Kemiskinan (Rupiah_Kapita_Bulan) Menurut Provinsi dan Daerah , 2023.xlsx",
  sheet = "Sheet2"
) %>%
  mutate(R101 = as.numeric(R101))

data_kp_x9 <- data_kp_43 %>%
  left_join(GK, by = c("R101" = "R101", "R105" = "R105")) %>%
  mutate(
    # X9: Status Kemiskinan RT (0 = Miskin/ref; 1 = Tidak Miskin)
    X9 = if_else(KAPITA < GK, 0L, 1L, missing = NA_integer_)
  ) %>%
  select(all_of(id_rt), X9)

1.6 Penggabungan & Pembuatan Variabel Final

Semua variabel level individu dibentuk dan digabung menjadi satu dataset analisis (dataku_final).

Variabel Deskripsi Kategori
Y Partisipasi sekolah anak 1 = Bersekolah; 0 = Tidak
X1 Jenis kelamin anak 0 = Perempuan*; 1 = Laki-laki
X2 Jenis disabilitas 0 = Ganda (≥2)*; 1 = Tunggal
X3 Tingkat kesulitan disabilitas 0 = Sangat kesulitan*; 1 = Kesulitan; 2 = Sedikit
X4 Jenis kelamin KRT 0 = Perempuan*; 1 = Laki-laki
X5 Pendidikan KRT 0 = ≤ SMP/Sederajat*; 1 = Minimal SMA/Sederajat
X6 Pekerjaan KRT 0 = Tidak bekerja*; 1 = Pertanian; 2 = Nonpertanian
X7 Daerah tempat tinggal 0 = Perdesaan*; 1 = Perkotaan
X8 Kepemilikan KIP/PIP 0 = Tidak memiliki*; 1 = Memiliki
X9 Status kemiskinan RT 0 = Miskin*; 1 = Tidak miskin
dataku_final <- dataku_filtered %>%
  mutate(
    across(R1002:R1009, ~ as.numeric(.x)),
    R105 = as.numeric(R105),
    R405 = as.numeric(R405),
    R615 = as.numeric(R615),
    R616 = as.numeric(R616),

    # Y: Partisipasi Sekolah
    Y  = as.integer(status),

    # X1: Jenis Kelamin Anak
    X1 = case_when(
      R405 == 1 ~ 1L,
      R405 == 2 ~ 0L,
      TRUE      ~ NA_integer_
    ),

    # X2: Jenis Disabilitas (0 = Ganda/ref; 1 = Tunggal)
    X2 = case_when(
      JUMLAH_JENIS_DISABILITAS > 1  ~ 0L,
      JUMLAH_JENIS_DISABILITAS == 1 ~ 1L,
      TRUE                          ~ NA_integer_
    ),

    # X3: Tingkat Kesulitan Disabilitas (prioritas terberat)
    X3 = case_when(
      rowSums(across(R1002:R1009, ~ .x %in% c(1, 5)), na.rm = TRUE) > 0 ~ 0L,
      rowSums(across(R1002:R1009, ~ .x %in% c(2, 6)), na.rm = TRUE) > 0 ~ 1L,
      rowSums(across(R1002:R1009, ~ .x %in% c(3, 7)), na.rm = TRUE) > 0 ~ 2L,
      TRUE ~ NA_integer_
    ),

    # X7: Daerah Tempat Tinggal
    X7 = case_when(
      R105 == 1 ~ 1L,
      R105 == 2 ~ 0L,
      TRUE      ~ NA_integer_
    ),

    # X8: Kepemilikan KIP/PIP
    X8 = if_else(
      R615 %in% c(1, 2) | R616 %in% c(1, 2),
      1L, 0L
    )
  ) %>%
  left_join(data_krt,   by = id_rt) %>%
  left_join(data_kp_x9, by = id_rt) %>%
  select(prov, kabu, Y, X1, X2, X3, X4, X5, X6, X7, X8, X9)

1.7 Encoding Variabel Kategorik (Factor)

dataku_final <- dataku_final %>%
  mutate(
    Y  = factor(Y,  levels = c(0, 1),    labels = c("Tidak bersekolah", "Bersekolah")),
    X1 = factor(X1, levels = c(0, 1),    labels = c("Perempuan", "Laki-laki")),
    X2 = factor(X2, levels = c(0, 1),    labels = c("Disabilitas ganda", "Disabilitas tunggal")),
    X3 = factor(X3, levels = c(0, 1, 2), labels = c("Sangat kesulitan", "Kesulitan", "Sedikit kesulitan")),
    X4 = factor(X4, levels = c(0, 1),    labels = c("Perempuan", "Laki-laki")),
    X5 = factor(X5, levels = c(0, 1),    labels = c("≤ SMP", "≥ SMA")),
    X6 = factor(X6, levels = c(0, 1, 2), labels = c("Tidak bekerja", "Pertanian", "Nonpertanian")),
    X7 = factor(X7, levels = c(0, 1),    labels = c("Perdesaan", "Perkotaan")),
    X8 = factor(X8, levels = c(0, 1),    labels = c("Tidak memiliki", "Memiliki")),
    X9 = factor(X9, levels = c(0, 1),    labels = c("Miskin", "Tidak miskin"))
  )

1.8 Referensi Variabel

data.frame(
  Kode     = c("Y", paste0("X", 1:9)),
  Nama     = c(
    "Partisipasi Sekolah",
    "Jenis Kelamin Anak",
    "Jenis Disabilitas",
    "Tingkat Kesulitan Disabilitas",
    "Jenis Kelamin KRT",
    "Pendidikan KRT",
    "Pekerjaan KRT",
    "Daerah Tempat Tinggal",
    "Kepemilikan KIP/PIP",
    "Status Kemiskinan RT"
  ),
  Kategori = c(
    "Dependen",
    rep("Karakteristik Anak", 3),
    rep("Karakteristik KRT",  3),
    rep("Sosial-Ekonomi RT",  3)
  ),
  Koding = c(
    "1 = Bersekolah; 0 = Tidak bersekolah",
    "0 = Perempuan*; 1 = Laki-laki",
    "0 = Disabilitas ganda*; 1 = Disabilitas tunggal",
    "0 = Sangat kesulitan*; 1 = Kesulitan; 2 = Sedikit kesulitan",
    "0 = Perempuan*; 1 = Laki-laki",
    "0 = ≤ SMP/Sederajat*; 1 = Minimal SMA/Sederajat",
    "0 = Tidak bekerja*; 1 = Pertanian; 2 = Nonpertanian",
    "0 = Perdesaan*; 1 = Perkotaan",
    "0 = Tidak memiliki*; 1 = Memiliki",
    "0 = Miskin*; 1 = Tidak miskin"
  )
) %>%
  kable(caption = "Referensi Variabel Penelitian (Y dan X1–X9)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = TRUE) %>%
  column_spec(1, bold = TRUE, width = "4em") %>%
  column_spec(3, italic = TRUE) %>%
  row_spec(1, background = "#fff3e0") %>%
  footnote(
    general = "* = kategori referensi.",
    general_title = "Keterangan: ",
    footnote_as_chunk = TRUE,
    escape = FALSE
  )
Referensi Variabel Penelitian (Y dan X1–X9)
Kode Nama Kategori Koding
Y Partisipasi Sekolah Dependen 1 = Bersekolah; 0 = Tidak bersekolah
X1 Jenis Kelamin Anak Karakteristik Anak 0 = Perempuan*; 1 = Laki-laki
X2 Jenis Disabilitas Karakteristik Anak 0 = Disabilitas ganda*; 1 = Disabilitas tunggal
X3 Tingkat Kesulitan Disabilitas Karakteristik Anak 0 = Sangat kesulitan*; 1 = Kesulitan; 2 = Sedikit kesulitan
X4 Jenis Kelamin KRT Karakteristik KRT 0 = Perempuan*; 1 = Laki-laki
X5 Pendidikan KRT Karakteristik KRT 0 = ≤ SMP/Sederajat*; 1 = Minimal SMA/Sederajat
X6 Pekerjaan KRT Karakteristik KRT 0 = Tidak bekerja*; 1 = Pertanian; 2 = Nonpertanian
X7 Daerah Tempat Tinggal Sosial-Ekonomi RT 0 = Perdesaan*; 1 = Perkotaan
X8 Kepemilikan KIP/PIP Sosial-Ekonomi RT 0 = Tidak memiliki*; 1 = Memiliki
X9 Status Kemiskinan RT Sosial-Ekonomi RT 0 = Miskin*; 1 = Tidak miskin
Keterangan: * = kategori referensi.

2 Eksplorasi Data

2.1 Ukuran & Struktur Dataset

cat("Jumlah observasi :", nrow(dataku_final), "\n")
Jumlah observasi : 236 
cat("Jumlah variabel  :", ncol(dataku_final), "\n\n")
Jumlah variabel  : 12 
glimpse(dataku_final)
Rows: 236
Columns: 12
$ prov <dbl> 74, 53, 74, 71, 53, 53, 52, 82, 53, 53, 74, 71, 82, 76, 71, 53, 5…
$ kabu <dbl> 7411, 5302, 7414, 7106, 5313, 5307, 5204, 8207, 5319, 5312, 7472,…
$ Y    <fct> Bersekolah, Bersekolah, Bersekolah, Bersekolah, Bersekolah, Tidak…
$ X1   <fct> Perempuan, Laki-laki, Laki-laki, Perempuan, Perempuan, Laki-laki,…
$ X2   <fct> Disabilitas ganda, Disabilitas ganda, Disabilitas tunggal, Disabi…
$ X3   <fct> Sedikit kesulitan, Sedikit kesulitan, Sedikit kesulitan, Sedikit …
$ X4   <fct> Perempuan, Laki-laki, Laki-laki, Laki-laki, Laki-laki, Laki-laki,…
$ X5   <fct> ≤ SMP, ≤ SMP, ≤ SMP, ≥ SMA, ≤ SMP, ≤ SMP, ≤ SMP, ≤ SMP, ≤ SMP, ≤ …
$ X6   <fct> Pertanian, Nonpertanian, Pertanian, Nonpertanian, Pertanian, Pert…
$ X7   <fct> Perdesaan, Perdesaan, Perdesaan, Perkotaan, Perdesaan, Perdesaan,…
$ X8   <fct> Tidak memiliki, Memiliki, Tidak memiliki, Memiliki, Memiliki, Tid…
$ X9   <fct> Tidak miskin, Tidak miskin, Miskin, Tidak miskin, Tidak miskin, T…

2.2 Statistik Deskriptif Ringkas

summary(dataku_final)
      prov            kabu                     Y               X1     
 Min.   :52.00   Min.   :5201   Tidak bersekolah: 67   Perempuan:107  
 1st Qu.:53.00   1st Qu.:5317   Bersekolah      :169   Laki-laki:129  
 Median :73.00   Median :7316                                         
 Mean   :71.29   Mean   :7147                                         
 3rd Qu.:81.00   3rd Qu.:8107                                         
 Max.   :94.00   Max.   :9436                                         
                   X2                      X3              X4          X5     
 Disabilitas ganda  :107   Sangat kesulitan : 66   Perempuan: 32   ≤ SMP:179  
 Disabilitas tunggal:129   Kesulitan        : 57   Laki-laki:204   ≥ SMA: 57  
                           Sedikit kesulitan:113                              
                                                                              
                                                                              
                                                                              
             X6              X7                   X8                 X9     
 Tidak bekerja: 20   Perdesaan:172   Tidak memiliki:200   Miskin      : 48  
 Pertanian    :127   Perkotaan: 64   Memiliki      : 36   Tidak miskin:188  
 Nonpertanian : 89                                                          
                                                                            
                                                                            
                                                                            

2.3 Pemeriksaan Missing Values

missing_tbl <- dataku_final %>%
  summarise(across(everything(), ~ sum(is.na(.)))) %>%
  pivot_longer(everything(),
               names_to  = "Variabel",
               values_to = "Jumlah_NA") %>%
  mutate(Persen_NA = round(Jumlah_NA / nrow(dataku_final) * 100, 2)) %>%
  arrange(desc(Jumlah_NA))

kable(missing_tbl,
      caption = "Jumlah dan Persentase Missing Value per Variabel",
      col.names = c("Variabel", "Jumlah NA", "% NA")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE)
Jumlah dan Persentase Missing Value per Variabel
Variabel Jumlah NA % NA
prov 0 0
kabu 0 0
Y 0 0
X1 0 0
X2 0 0
X3 0 0
X4 0 0
X5 0 0
X6 0 0
X7 0 0
X8 0 0
X9 0 0

2.4 Distribusi Variabel Dependen (Y)

tbl_y <- dataku_final %>%
  count(Y) %>%
  mutate(Persen = round(n / sum(n) * 100, 2))

kable(tbl_y,
      caption = "Distribusi Partisipasi Sekolah Anak Disabilitas Usia 13–15 Tahun",
      col.names = c("Status Sekolah", "Frekuensi", "%")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE)
Distribusi Partisipasi Sekolah Anak Disabilitas Usia 13–15 Tahun
Status Sekolah Frekuensi %
Tidak bersekolah 67 28.39
Bersekolah 169 71.61
# ── Pie Chart Distribusi Y ──────────────────────────────────────
pd_y <- tbl_y %>%
  mutate(name = as.character(Y), y = Persen) %>%
  select(name, y)

highchart() %>%
  hc_chart(type = "pie", backgroundColor = "transparent",
           height = PIE_CHART_HEIGHT,
           style = list(fontFamily = "inherit")) %>%
  hc_title(text  = "Distribusi Partisipasi Sekolah",
           style = list(fontSize = "15px", fontWeight = "700", color = "#333")) %>%
  hc_subtitle(text = "Anak Penyandang Disabilitas Usia 13\u201315 Tahun (SUSENAS 2023)",
              style = list(fontSize = "12px", color = "#666")) %>%
  hc_series(list(name = "Persentase", colorByPoint = TRUE,
                 data = list_parse(pd_y))) %>%
  hc_colors(c("#D73027","#4575B4")) %>%
  hc_plotOptions(pie = list(
    size = PIE_SIZE,
    center = PIE_CENTER,
    allowPointSelect = TRUE, cursor = "pointer",
    dataLabels = list(enabled = TRUE,
                      format  = "<b>{point.name}</b><br>n = {point.y:.0f}%",
                      style   = list(fontSize = "13px", textOutline = "none")),
    showInLegend = TRUE
  )) %>%
  hc_tooltip(pointFormat = "<b>{point.name}</b>: {point.y:.2f}%") %>%
  hc_exporting(enabled = TRUE, filename = "distribusi_y",
               sourceWidth = 800, sourceHeight = 500,
               buttons = list(contextButton = list(
                 menuItems = c("downloadPNG","downloadSVG","downloadPDF"),
                 text = "Unduh HD")))

2.4.1 Partisipasi Sekolah Anak Penyandang Disabilitas Usia 13-15 Tahun di Kawasan Timur Indonesia (KTI) Tahun 2023

weighted_y_result <- tryCatch({
  y_design_data <- dataku_filtered %>%
    mutate(
      R101 = as.numeric(R101),
      R105 = as.numeric(R105),
      FWT  = as.numeric(FWT),
      status = as.numeric(status),
      STRATA_Y = paste0(sprintf("%02d", R101), R105)
    ) %>%
    filter(!is.na(status), !is.na(FWT), FWT > 0,
           !is.na(PSU), !is.na(SSU), !is.na(STRATA_Y))

  if (nrow(y_design_data) == 0) stop("data valid untuk desain survei tidak tersedia")

  options(survey.adjust.domain.lonely = TRUE)
  options(survey.lonely.psu           = "adjust")

  desain_y_kti <- svydesign(
    id      = ~PSU + SSU,
    strata  = ~STRATA_Y,
    weights = ~FWT,
    data    = y_design_data,
    nest    = TRUE
  )

  est_y <- svymean(~status, desain_y_kti, na.rm = TRUE)
  ci_y  <- confint(est_y, level = 0.95)

  est_pct <- as.numeric(coef(est_y)) * 100
  se_pct  <- as.numeric(SE(est_y)) * 100
  ci_low  <- max(0, as.numeric(ci_y[1, 1]) * 100)
  ci_up   <- min(100, as.numeric(ci_y[1, 2]) * 100)
  pct_sampel <- mean(y_design_data$status == 1, na.rm = TRUE) * 100

  data.frame(
    Wilayah = "Kawasan Timur Indonesia",
    `Persentase sampel (%)` = round(pct_sampel, 2),
    `Estimasi tertimbang (%)` = round(est_pct, 2),
    SE = round(se_pct, 2),
    `CI 95% bawah` = round(ci_low, 2),
    `CI 95% atas` = round(ci_up, 2),
    `RSE (%)` = round(se_pct / est_pct * 100, 2),
    `Persentase sampel masuk CI?` = ifelse(pct_sampel >= ci_low & pct_sampel <= ci_up, "Ya", "Tidak"),
    check.names = FALSE
  )
}, error = function(e) e)

if (inherits(weighted_y_result, "error")) {
  HTML(paste0("<p><em>Estimasi tertimbang variabel Y tidak dapat dihitung: ",
              weighted_y_result$message, "</em></p>"))
} else {
  kable(
    weighted_y_result,
    caption = "Estimasi Tertimbang Persentase Partisipasi Sekolah Anak Penyandang Disabilitas Usia 13–15 Tahun di KTI"
  ) %>%
    kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                  full_width = FALSE) %>%
    column_spec(3, bold = TRUE, color = "#1565c0")
}
Estimasi Tertimbang Persentase Partisipasi Sekolah Anak Penyandang Disabilitas Usia 13–15 Tahun di KTI
Wilayah Persentase sampel (%) Estimasi tertimbang (%) SE CI 95% bawah CI 95% atas RSE (%) Persentase sampel masuk CI?
Kawasan Timur Indonesia 71.61 72.39 4.46 63.66 81.13 6.16 Ya

2.4.2 Pie Chart Partisipasi Sekolah Anak Penyandang Disabilitas Usia 13-15 Tahun di Kawasan Timur Indonesia (KTI) Tahun 2023

if (!inherits(weighted_y_result, "error")) {
  est_bersekolah <- as.numeric(weighted_y_result$`Estimasi tertimbang (%)`[1])

  pd_y_weighted <- data.frame(
    name = c("Tidak Bersekolah", "Bersekolah"),
    y    = c(round(100 - est_bersekolah, 2), round(est_bersekolah, 2))
  )

  highchart() %>%
    hc_chart(type = "pie", backgroundColor = "transparent",
             height = PIE_CHART_HEIGHT,
             style = list(fontFamily = "inherit")) %>%
    hc_title(text  = "Distribusi Partisipasi Sekolah (Estimasi Tertimbang)",
             style = list(fontSize = "15px", fontWeight = "700", color = "#333")) %>%
    hc_subtitle(text = "Anak Penyandang Disabilitas Usia 13–15 Tahun di KTI (SUSENAS 2023)",
                style = list(fontSize = "12px", color = "#666")) %>%
    hc_series(list(name = "Persentase", colorByPoint = TRUE,
                   data = list_parse(pd_y_weighted))) %>%
    hc_colors(c("#D73027", "#4575B4")) %>%
    hc_plotOptions(pie = list(
      size = PIE_SIZE,
      center = PIE_CENTER,
      allowPointSelect = TRUE, cursor = "pointer",
      dataLabels = list(enabled = TRUE,
                        format  = "<b>{point.name}</b><br>{point.y:.2f}%",
                        style   = list(fontSize = "13px", textOutline = "none")),
      showInLegend = TRUE
    )) %>%
    hc_tooltip(pointFormat = "<b>{point.name}</b>: {point.y:.2f}%") %>%
    hc_exporting(enabled = TRUE, filename = "distribusi_y_tertimbang",
                 sourceWidth = 800, sourceHeight = 500,
                 buttons = list(contextButton = list(
                   menuItems = c("downloadPNG","downloadSVG","downloadPDF"),
                   text = "Unduh HD")))
}

2.5 Partisipasi Sekolah per Provinsi



2.6 Tabel Hasil Odds Ratio

Kategori yang diberi tanda * merupakan kategori referensi dan dikodekan sebagai 0 pada pembentukan variabel.

Hasil Odds Ratio dan Kategori Referensi
Variabel Kategori Odds Ratio
Jenis kelamin anak Laki-laki 1,246
Perempuan*
Jenis disabilitas anak Disabilitas tunggal 6,432
Disabilitas ganda*
Tingkat kesulitan disabilitas anak Sedikit kesulitan 9,002
Kesulitan 3,269
Sangat kesulitan*
Jenis kelamin KRT Laki-laki 0,424
Perempuan*
Tingkat pendidikan KRT Minimal SMA/Sederajat 1,663
SMP/Sederajat ke bawah*
Pekerjaan KRT Bekerja di sektor nonpertanian 2,175
Bekerja di sektor pertanian 4,235
Tidak bekerja*
Daerah tempat tinggal Perkotaan 1,264
Perdesaan*
Status kepemilikan KIP/PIP Memiliki 17,239
Tidak memiliki*
Status kemiskinan rumah tangga Tidak Miskin 1,343
Miskin*

2.7 Distribusi Variabel Independen

📈 X1: Jenis Kelamin Anak

📋 Tabulasi X1: Jenis Kelamin Anak

Distribusi X1: Jenis Kelamin Anak
Kategori Frekuensi Persen (%)
Perempuan 107 45.34
Laki-laki 129 54.66

🔗 Tabulasi X1: Jenis Kelamin Anak × Partisipasi Sekolah

Silang: X1: Jenis Kelamin Anak × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Perempuan Tidak bersekolah 33 30.84
Perempuan Bersekolah 74 69.16
Laki-laki Tidak bersekolah 34 26.36
Laki-laki Bersekolah 95 73.64

🥧 Pie Chart — X1: Jenis Kelamin Anak

📊 Stacked Bar — X1: Jenis Kelamin Anak × Partisipasi Sekolah

📈 X2: Jenis Disabilitas

📋 Tabulasi X2: Jenis Disabilitas

Distribusi X2: Jenis Disabilitas
Kategori Frekuensi Persen (%)
Disabilitas ganda 107 45.34
Disabilitas tunggal 129 54.66

🔗 Tabulasi X2: Jenis Disabilitas × Partisipasi Sekolah

Silang: X2: Jenis Disabilitas × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Disabilitas ganda Tidak bersekolah 51 47.66
Disabilitas ganda Bersekolah 56 52.34
Disabilitas tunggal Tidak bersekolah 16 12.40
Disabilitas tunggal Bersekolah 113 87.60

🥧 Pie Chart — X2: Jenis Disabilitas

📊 Stacked Bar — X2: Jenis Disabilitas × Partisipasi Sekolah

📈 X3: Tingkat Kesulitan

📋 Tabulasi X3: Tingkat Kesulitan

Distribusi X3: Tingkat Kesulitan
Kategori Frekuensi Persen (%)
Sangat kesulitan 66 27.97
Kesulitan 57 24.15
Sedikit kesulitan 113 47.88

🔗 Tabulasi X3: Tingkat Kesulitan × Partisipasi Sekolah

Silang: X3: Tingkat Kesulitan × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Sangat kesulitan Tidak bersekolah 37 56.06
Sangat kesulitan Bersekolah 29 43.94
Kesulitan Tidak bersekolah 16 28.07
Kesulitan Bersekolah 41 71.93
Sedikit kesulitan Tidak bersekolah 14 12.39
Sedikit kesulitan Bersekolah 99 87.61

🥧 Pie Chart — X3: Tingkat Kesulitan

📊 Stacked Bar — X3: Tingkat Kesulitan × Partisipasi Sekolah

📈 X4: Jenis Kelamin KRT

📋 Tabulasi X4: Jenis Kelamin KRT

Distribusi X4: Jenis Kelamin KRT
Kategori Frekuensi Persen (%)
Perempuan 32 13.56
Laki-laki 204 86.44

🔗 Tabulasi X4: Jenis Kelamin KRT × Partisipasi Sekolah

Silang: X4: Jenis Kelamin KRT × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Perempuan Tidak bersekolah 5 15.62
Perempuan Bersekolah 27 84.38
Laki-laki Tidak bersekolah 62 30.39
Laki-laki Bersekolah 142 69.61

🥧 Pie Chart — X4: Jenis Kelamin KRT

📊 Stacked Bar — X4: Jenis Kelamin KRT × Partisipasi Sekolah

📈 X5: Pendidikan KRT

📋 Tabulasi X5: Pendidikan KRT

Distribusi X5: Pendidikan KRT
Kategori Frekuensi Persen (%)
≤ SMP 179 75.85
≥ SMA 57 24.15

🔗 Tabulasi X5: Pendidikan KRT × Partisipasi Sekolah

Silang: X5: Pendidikan KRT × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
≤ SMP Tidak bersekolah 55 30.73
≤ SMP Bersekolah 124 69.27
≥ SMA Tidak bersekolah 12 21.05
≥ SMA Bersekolah 45 78.95

🥧 Pie Chart — X5: Pendidikan KRT

📊 Stacked Bar — X5: Pendidikan KRT × Partisipasi Sekolah

📈 X6: Pekerjaan KRT

📋 Tabulasi X6: Pekerjaan KRT

Distribusi X6: Pekerjaan KRT
Kategori Frekuensi Persen (%)
Tidak bekerja 20 8.47
Pertanian 127 53.81
Nonpertanian 89 37.71

🔗 Tabulasi X6: Pekerjaan KRT × Partisipasi Sekolah

Silang: X6: Pekerjaan KRT × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Tidak bekerja Tidak bersekolah 10 50.0
Tidak bekerja Bersekolah 10 50.0
Pertanian Tidak bersekolah 40 31.5
Pertanian Bersekolah 87 68.5
Nonpertanian Tidak bersekolah 17 19.1
Nonpertanian Bersekolah 72 80.9

🥧 Pie Chart — X6: Pekerjaan KRT

📊 Stacked Bar — X6: Pekerjaan KRT × Partisipasi Sekolah

📈 X7: Daerah Tinggal

📋 Tabulasi X7: Daerah Tinggal

Distribusi X7: Daerah Tinggal
Kategori Frekuensi Persen (%)
Perdesaan 172 72.88
Perkotaan 64 27.12

🔗 Tabulasi X7: Daerah Tinggal × Partisipasi Sekolah

Silang: X7: Daerah Tinggal × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Perdesaan Tidak bersekolah 51 29.65
Perdesaan Bersekolah 121 70.35
Perkotaan Tidak bersekolah 16 25.00
Perkotaan Bersekolah 48 75.00

🥧 Pie Chart — X7: Daerah Tinggal

📊 Stacked Bar — X7: Daerah Tinggal × Partisipasi Sekolah

📈 X8: Kepemilikan KIP/PIP

📋 Tabulasi X8: Kepemilikan KIP/PIP

Distribusi X8: Kepemilikan KIP/PIP
Kategori Frekuensi Persen (%)
Tidak memiliki 200 84.75
Memiliki 36 15.25

🔗 Tabulasi X8: Kepemilikan KIP/PIP × Partisipasi Sekolah

Silang: X8: Kepemilikan KIP/PIP × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Tidak memiliki Tidak bersekolah 66 33.00
Tidak memiliki Bersekolah 134 67.00
Memiliki Tidak bersekolah 1 2.78
Memiliki Bersekolah 35 97.22

🥧 Pie Chart — X8: Kepemilikan KIP/PIP

📊 Stacked Bar — X8: Kepemilikan KIP/PIP × Partisipasi Sekolah

📈 X9: Status Kemiskinan RT

📋 Tabulasi X9: Status Kemiskinan RT

Distribusi X9: Status Kemiskinan RT
Kategori Frekuensi Persen (%)
Miskin 48 20.34
Tidak miskin 188 79.66

🔗 Tabulasi X9: Status Kemiskinan RT × Partisipasi Sekolah

Silang: X9: Status Kemiskinan RT × Partisipasi Sekolah
Kategori Partisipasi Sekolah Frekuensi Persen (%)
Miskin Tidak bersekolah 16 33.33
Miskin Bersekolah 32 66.67
Tidak miskin Tidak bersekolah 51 27.13
Tidak miskin Bersekolah 137 72.87

🥧 Pie Chart — X9: Status Kemiskinan RT

📊 Stacked Bar — X9: Status Kemiskinan RT × Partisipasi Sekolah


2.8 Distribusi Jumlah Jenis Disabilitas

tbl_dis <- dataku_filtered %>%
  count(JUMLAH_JENIS_DISABILITAS) %>%
  mutate(Persen = round(n / sum(n) * 100, 2))

kable(tbl_dis,
      caption  = "Distribusi Jumlah Jenis Disabilitas",
      col.names = c("Jumlah Jenis Disabilitas", "Frekuensi", "%")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE)
Distribusi Jumlah Jenis Disabilitas
Jumlah Jenis Disabilitas Frekuensi %
1 129 54.66
2 25 10.59
3 25 10.59
4 19 8.05
5 17 7.20
6 7 2.97
7 12 5.08
8 2 0.85
make_col(
  cats  = tbl_dis$JUMLAH_JENIS_DISABILITAS,
  vals  = tbl_dis$n,
  title = "Distribusi Jumlah Jenis Disabilitas",
  color = "#4575B4",
  xlab  = "Jumlah Jenis Disabilitas",
  ylab  = "Frekuensi"
)

2.9 Distribusi Observasi per Provinsi

tbl_prov <- dataku_final %>%
  count(prov) %>%
  mutate(Persen = round(n / sum(n) * 100, 2)) %>%
  arrange(desc(n))

kable(tbl_prov,
      caption   = "Distribusi Observasi per Provinsi",
      col.names = c("Kode Provinsi", "Frekuensi", "%")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE)
Distribusi Observasi per Provinsi
Kode Provinsi Frekuensi %
53 49 20.76
73 42 17.80
94 22 9.32
82 20 8.47
52 19 8.05
71 17 7.20
74 17 7.20
81 16 6.78
91 11 4.66
72 9 3.81
75 8 3.39
76 6 2.54
tbl_prov_sorted <- tbl_prov %>% arrange(n)

make_col(
  cats       = tbl_prov_sorted$prov,
  vals       = tbl_prov_sorted$n,
  title      = "Jumlah Observasi per Provinsi",
  color      = "#74ADD1",
  xlab       = "Kode Provinsi",
  ylab       = "Frekuensi",
  horizontal = TRUE
)

2.10 Tabulasi Silang: Partisipasi Sekolah (Y) vs Setiap Prediktor

Tabel berikut menyajikan distribusi status sekolah anak berdasarkan masing-masing variabel prediktor, beserta hasil uji Chi-Square.

vars_for_tab <- c("X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9")
label_vars   <- c(
  "Jenis Kelamin Anak (X1)",
  "Jenis Disabilitas (X2)",
  "Tingkat Kesulitan (X3)",
  "Jenis Kelamin KRT (X4)",
  "Pendidikan KRT (X5)",
  "Pekerjaan KRT (X6)",
  "Daerah Tinggal (X7)",
  "Kepemilikan KIP/PIP (X8)",
  "Status Kemiskinan RT (X9)"
)

for (i in seq_along(vars_for_tab)) {
  var <- vars_for_tab[i]
  cat("\n###", label_vars[i], "\n\n")

  df_tmp <- dataku_final %>%
    filter(!is.na(.data[[var]]), !is.na(Y))

  tab     <- table(df_tmp[[var]], df_tmp$Y)
  tab_pct <- prop.table(tab, margin = 1) * 100

  tbl_out <- as.data.frame.matrix(tab) %>%
    mutate(
      Total          = rowSums(.),
      `% Bersekolah` = round(tab_pct[, "Bersekolah"], 1)
    )

  chi_res <- tryCatch(chisq.test(tab), error = function(e) NULL)
  p_val   <- if (!is.null(chi_res)) round(chi_res$p.value, 4) else NA

  print(
    kable(tbl_out,
          caption = paste0(label_vars[i], " — Chi-Square p-value: ", p_val)) %>%
      kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                    full_width = FALSE)
  )
}

2.10.1 Jenis Kelamin Anak (X1)

Jenis Kelamin Anak (X1) — Chi-Square p-value: 0.5381
Tidak bersekolah Bersekolah Total % Bersekolah
Perempuan 33 74 107 69.2
Laki-laki 34 95 129 73.6

2.10.2 Jenis Disabilitas (X2)

Jenis Disabilitas (X2) — Chi-Square p-value: 0
Tidak bersekolah Bersekolah Total % Bersekolah
Disabilitas ganda 51 56 107 52.3
Disabilitas tunggal 16 113 129 87.6

2.10.3 Tingkat Kesulitan (X3)

Tingkat Kesulitan (X3) — Chi-Square p-value: 0
Tidak bersekolah Bersekolah Total % Bersekolah
Sangat kesulitan 37 29 66 43.9
Kesulitan 16 41 57 71.9
Sedikit kesulitan 14 99 113 87.6

2.10.4 Jenis Kelamin KRT (X4)

Jenis Kelamin KRT (X4) — Chi-Square p-value: 0.1306
Tidak bersekolah Bersekolah Total % Bersekolah
Perempuan 5 27 32 84.4
Laki-laki 62 142 204 69.6

2.10.5 Pendidikan KRT (X5)

Pendidikan KRT (X5) — Chi-Square p-value: 0.2142
Tidak bersekolah Bersekolah Total % Bersekolah
≤ SMP 55 124 179 69.3
≥ SMA 12 45 57 78.9

2.10.6 Pekerjaan KRT (X6)

Pekerjaan KRT (X6) — Chi-Square p-value: 0.0113
Tidak bersekolah Bersekolah Total % Bersekolah
Tidak bekerja 10 10 20 50.0
Pertanian 40 87 127 68.5
Nonpertanian 17 72 89 80.9

2.10.7 Daerah Tinggal (X7)

Daerah Tinggal (X7) — Chi-Square p-value: 0.5877
Tidak bersekolah Bersekolah Total % Bersekolah
Perdesaan 51 121 172 70.3
Perkotaan 16 48 64 75.0

2.10.8 Kepemilikan KIP/PIP (X8)

Kepemilikan KIP/PIP (X8) — Chi-Square p-value: 5e-04
Tidak bersekolah Bersekolah Total % Bersekolah
Tidak memiliki 66 134 200 67.0
Memiliki 1 35 36 97.2

2.10.9 Status Kemiskinan RT (X9)

Status Kemiskinan RT (X9) — Chi-Square p-value: 0.5018
Tidak bersekolah Bersekolah Total % Bersekolah
Miskin 16 32 48 66.7
Tidak miskin 51 137 188 72.9

2.11 Ringkasan Persentase Status Sekolah per Variabel

Tabel ringkasan status sekolah untuk setiap kategori prediktor. Kolom % Tidak Bersekolah dan % Bersekolah berjumlah 100 persen pada setiap kategori.

ringkasan <- lapply(seq_along(vars_for_tab), function(i) {
  var <- vars_for_tab[i]
  dataku_final %>%
    filter(!is.na(.data[[var]]), !is.na(Y)) %>%
    group_by(Variabel = label_vars[i], Kategori = .data[[var]]) %>%
    summarise(
      n                    = n(),
      pct_tidak_bersekolah = round(sum(Y == "Tidak bersekolah") / n * 100, 1),
      pct_bersekolah       = round(sum(Y == "Bersekolah") / n * 100, 1),
      .groups              = "drop"
    )
}) %>% bind_rows()

kable(ringkasan,
      caption   = "Ringkasan % Status Sekolah per Kategori Prediktor",
      col.names = c("Variabel", "Kategori", "n", "% Tidak Bersekolah", "% Bersekolah")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE) %>%
  collapse_rows(columns = 1, valign = "top")
Ringkasan % Status Sekolah per Kategori Prediktor
Variabel Kategori n % Tidak Bersekolah % Bersekolah
Jenis Kelamin Anak (X1) Perempuan 107 30.8 69.2
Laki-laki 129 26.4 73.6
Jenis Disabilitas (X2) Disabilitas ganda 107 47.7 52.3
Disabilitas tunggal 129 12.4 87.6
Tingkat Kesulitan (X3) Sangat kesulitan 66 56.1 43.9
Kesulitan 57 28.1 71.9
Sedikit kesulitan 113 12.4 87.6
Jenis Kelamin KRT (X4) Perempuan 32 15.6 84.4
Laki-laki 204 30.4 69.6
Pendidikan KRT (X5) ≤ SMP 179 30.7 69.3
≥ SMA 57 21.1 78.9
Pekerjaan KRT (X6) Tidak bekerja 20 50.0 50.0
Pertanian 127 31.5 68.5
Nonpertanian 89 19.1 80.9
Daerah Tinggal (X7) Perdesaan 172 29.7 70.3
Perkotaan 64 25.0 75.0
Kepemilikan KIP/PIP (X8) Tidak memiliki 200 33.0 67.0
Memiliki 36 2.8 97.2
Status Kemiskinan RT (X9) Miskin 48 33.3 66.7
Tidak miskin 188 27.1 72.9

3 Estimasi Langsung Indikator

Indikator: Persentase penyandang disabilitas usia 13–15 tahun yang sedang bersekolah, diestimasi di tingkat provinsi menggunakan metode estimasi langsung dengan desain survei SUSENAS 2023.

3.1 Pembentukan Data Indikator & Desain Survei

library(survey)

allowed_vals_ind <- c(1, 2, 3, 5, 6, 7)

# ── Bentuk data indikator dari data_susenas mentah ────────────────────────
indicator_disab <- data_susenas %>%
  mutate(
    across(R1002:R1009, ~ as.numeric(.x)),
    R101 = as.numeric(R101),
    R102 = as.numeric(R102),
    R105 = as.numeric(R105),
    R407 = as.numeric(R407),
    R610 = as.numeric(R610),
    FWT  = as.numeric(FWT),

    # Jumlah jenis disabilitas (nilai 1,2,3,5,6,7 = ada kesulitan)
    JUMLAH_DISAB = rowSums(
      across(R1002:R1009, ~ .x %in% allowed_vals_ind),
      na.rm = TRUE
    ),

    # Strata: kombinasi kode provinsi × daerah (perkotaan/perdesaan)
    STRATA_IND = paste0(sprintf("%02d", R101), R105),

    jml_pddk = 100,

    # Variabel respons: 100 = bersekolah (R610==2), 0 = tidak
    pa = ifelse(R610 == 2, 100, 0)
  ) %>%
  filter(
    R407 >= 13 & R407 <= 15,          # Usia 13–15 tahun
    JUMLAH_DISAB > 0,                 # Penyandang disabilitas
    R101 %in% c(52:53, 71:76, 81:82, 91:97)
    
  )

cat("Jumlah observasi domain indikator:", nrow(indicator_disab), "\n")
Jumlah observasi domain indikator: 236 
# ── Desain survei ─────────────────────────────────────────────────────────
options(survey.adjust.domain.lonely = TRUE)
options(survey.lonely.psu           = "adjust")

susenas_ind_design <- svydesign(
  id      = ~PSU + SSU,
  strata  = ~STRATA_IND,
  data    = indicator_disab,
  weights = ~FWT,
  nest    = TRUE
)

summary(susenas_ind_design$prob)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
0.000793 0.008747 0.017686 0.036946 0.036458 0.316958 

3.2 Estimasi Tingkat Provinsi

# ── Estimasi langsung per provinsi ────────────────────────────────────────
resultP_ind <- svyby(
  formula = ~pa,
  denom   = ~jml_pddk,
  by      = ~R101,
  design  = susenas_ind_design,
  deff    = TRUE,
  svyratio,
  vartype = c("se", "ci", "cv", "cvpct", "var")
)
resultP_ind[is.na(resultP_ind)] <- 0

# ── Hitung turunan statistik ──────────────────────────────────────────────
resultP_ind <- resultP_ind %>%
  mutate(
    theta    = round(`pa/jml_pddk` * 100, 2),
    SE       = round(`se.pa/jml_pddk` * 100, 2),
    VAR      = round(SE^2, 2),
    CI_LOWER = round(ci_l * 100, 2),
    CI_UPPER = round(ci_u * 100, 2),
    RSE      = round(`cv%`, 2),
    DEFF     = round(DEff, 2)
  )
resultP_ind$CI_LOWER[resultP_ind$CI_LOWER < 0] <- 0

# ── Label Nama Provinsi Lengkap (Kode BPS) ───────────────────────────────────
prov_label_ind <- data.frame(
  R101 = c(
    11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 
    31, 32, 33, 34, 35, 36, 
    51, 52, 53, 
    61, 62, 63, 64, 65, 
    71, 72, 73, 74, 75, 76, 
    81, 82, 
    91, 94
  ),
  Nama_Prov = c(
    "Aceh", "Sumatera Utara", "Sumatera Barat", "Riau", "Jambi", 
    "Sumatera Selatan", "Bengkulu", "Lampung", "Kepulauan Bangka Belitung", "Kepulauan Riau",
    "DKI Jakarta", "Jawa Barat", "Jawa Tengah", "DI Yogyakarta", "Jawa Timur", 
    "Banten",
    "Bali", "Nusa Tenggara Barat", "Nusa Tenggara Timur",
    "Kalimantan Barat", "Kalimantan Tengah", "Kalimantan Selatan", "Kalimantan Timur", "Kalimantan Utara",
    "Sulawesi Utara", "Sulawesi Tengah", "Sulawesi Selatan", "Sulawesi Tenggara", "Gorontalo", 
    "Sulawesi Barat",
    "Maluku", "Maluku Utara",
    "Papua Barat", "Papua"
  ),
  Wilayah = c(
    rep("Sumatera", 10),
    rep("Jawa", 6),
    "Bali", rep("Nusa Tenggara", 2),
    rep("Kalimantan", 5),
    rep("Sulawesi", 6),
    rep("Maluku", 2),
    rep("Papua", 2)
  )
)

# ── Tabel output bersih ───────────────────────────────────────────────────
outputP_ind <- resultP_ind %>%
  select(R101, theta, SE, VAR, CI_LOWER, CI_UPPER, RSE, DEFF) %>%
  rename(
    Prov      = R101,
    Estimasi  = theta,
    CI_LOWER  = CI_LOWER,
    CI_UPPER  = CI_UPPER
  ) %>%
  left_join(prov_label_ind, by = c("Prov" = "R101")) %>%
  arrange(Prov)

kable(
  outputP_ind[, c("Nama_Prov", "Wilayah", "Estimasi", "SE",
                  "CI_LOWER", "CI_UPPER", "RSE", "DEFF")],
  caption   = "Estimasi Langsung: % Penyandang Disabilitas 13–15 Tahun yang Bersekolah per Provinsi",
  col.names = c("Provinsi", "Wilayah", "Estimasi (%)", "SE",
                "CI Lower", "CI Upper", "RSE (%)", "DEFF"),
  digits    = 2
) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = TRUE) %>%
  column_spec(3, bold = TRUE, color = "#1565c0") %>%
  column_spec(7, color = ifelse(outputP_ind$RSE > 25, "red", "darkgreen"),
              bold = ifelse(outputP_ind$RSE > 25, TRUE, FALSE)) %>%
  row_spec(which(outputP_ind$RSE > 25), background = "#fff3e0")
Estimasi Langsung: % Penyandang Disabilitas 13–15 Tahun yang Bersekolah per Provinsi
Provinsi Wilayah Estimasi (%) SE CI Lower CI Upper RSE (%) DEFF
Nusa Tenggara Barat Nusa Tenggara 83.39 11.17 61.49 105.29 13.40 1.63
Nusa Tenggara Timur Nusa Tenggara 76.48 8.26 60.30 92.66 10.79 1.84
Sulawesi Utara Sulawesi 82.46 10.52 61.84 103.09 12.76 1.24
Sulawesi Tengah Sulawesi 86.23 12.31 62.11 110.35 14.27 1.03
Sulawesi Selatan Sulawesi 67.28 10.36 46.97 87.59 15.40 2.01
Sulawesi Tenggara Sulawesi 29.57 12.54 4.99 54.16 42.42 1.23
Gorontalo Sulawesi 61.81 24.79 13.22 110.39 40.11 1.85
Sulawesi Barat Sulawesi 9.15 9.97 0.00 28.70 109.01 0.60
Maluku Maluku 89.16 8.66 72.20 106.13 9.71 1.17
Maluku Utara Maluku 84.10 8.34 67.75 100.45 9.92 1.01
Papua Barat Papua 84.91 10.55 64.23 105.59 12.42 0.90
Papua Papua 68.44 15.75 37.58 99.30 23.01 2.47

3.3 Visualisasi Estimasi & RSE per Provinsi

📈 Panel 1: Estimasi Angka Sekolah per Provinsi

⚠️ Panel 2: RSE Reliabilitas Data per Provinsi

📈 Estimasi Angka Sekolah per Wilayah KTI

⚠️ RSE Reliabilitas per Wilayah KTI


4 Analisis Regresi Logistik

Catatan: Semua 4 metode (Reglog Biasa, Firth, SMOTE, Class Weight) dijalankan terhadap satu dataset analisis (dataku_final). Gunakan panel filter di bawah untuk memilih metode yang ingin ditampilkan.

4.1 Fungsi Pembantu

xvars_global <- paste0("X", 1:9)

# ── Konversi kable ke string HTML ─────────────────────────────────
kbl_h <- function(df, caption = NULL) {
  knitr::kable(df, format = "html", caption = caption, escape = FALSE) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover", "condensed"),
      full_width = FALSE, font_size = 13, position = "left"
    ) %>%
    as.character()
}

# ── Pra-pemrosesan data standar ───────────────────────────────────
# Y dikonversi ke 0/1 (0 = tidak bersekolah; 1 = bersekolah).
# Seluruh X dipertahankan sebagai faktor agar kategori referensi mengikuti
# level pertama/faktor berkode 0 yang ditandai (*) pada tabel referensi.
prep_data <- function(data) {
  df <- data %>%
    select(all_of(c("Y", xvars_global))) %>%
    mutate(
      status_sekolah = if_else(Y == "Bersekolah", 1L, 0L),
      across(all_of(xvars_global), ~ droplevels(as.factor(.x)))
    ) %>%
    select(-Y) %>%
    na.omit()

  konstan <- xvars_global[sapply(xvars_global, function(v) dplyr::n_distinct(df[[v]]) < 2)]
  xvars_model <- setdiff(xvars_global, konstan)
  df <- df %>% mutate(across(all_of(xvars_model), ~ droplevels(as.factor(.x))))
  formula_mod <- as.formula(paste("status_sekolah ~", paste(xvars_model, collapse = " + ")))
  list(df = df, xvars_model = xvars_model, formula_mod = formula_mod, konstan = konstan)
}

# ── Wrapper HTML untuk tiap sub-bagian ───────────────────────────
sec <- function(icon, judul, isi) {
  paste0(
    '<div style="margin-bottom:18px">',
    '<h5 style="color:#1565c0;border-bottom:2px solid #bbdefb;',
    'padding-bottom:5px;margin-top:18px;font-size:13.5px;">',
    icon, ' ', judul, '</h5>', isi, '</div>'
  )
}

# ── EDA: distribusi Y ────────────────────────────────────────────
eda_html <- function(df) {
  tbl <- table(df$status_sekolah)
  pct <- round(prop.table(tbl) * 100, 2)
  kbl_h(data.frame(
    Kategori = c("Tidak Bersekolah (0)", "Bersekolah (1)"),
    N        = as.integer(c(tbl["0"], tbl["1"])),
    Persen   = paste0(c(pct["0"], pct["1"]), " %")
  ), "Distribusi Y — Partisipasi Sekolah")
}

# ── Uji Simultan (GLM-based) ─────────────────────────────────────
simultan_html <- function(model, model_null, xvars_model) {
  G2    <- model_null$deviance - model$deviance
  df_G2 <- model_null$df.residual - model$df.residual
  chi_k <- qchisq(0.95, df_G2)
  pval  <- pchisq(G2, df_G2, lower.tail = FALSE)
  kbl_h(data.frame(
    Statistik = c("-2LL Null", "-2LL Model", "G² Hitung", "df",
                  "χ² Tabel (α=5%)", "p-value", "Keputusan"),
    Nilai = c(
      round(model_null$deviance, 3), round(model$deviance, 3),
      round(G2, 3), df_G2, round(chi_k, 3), round(pval, 4),
      ifelse(G2 > chi_k, "✅ Tolak H0 — Model Signifikan", "❌ Gagal Tolak H0")
    )
  ), "Uji Simultan (Likelihood Ratio Test / G²)")
}

# ── Uji Parsial Wald (GLM-based) ────────────────────────────────
wald_html <- function(model) {
  koef <- summary(model)$coefficients
  kbl_h(data.frame(
    Variabel   = rownames(koef),
    B          = round(koef[, 1], 4),
    SE         = round(koef[, 2], 4),
    Wald       = round((koef[, 1] / koef[, 2])^2, 4),
    `p-value`  = round(koef[, 4], 4),
    Kesimpulan = ifelse(koef[, 4] < 0.05, "✅ Signifikan", "❌ Tdk Signifikan"),
    check.names = FALSE
  ), "Uji Parsial (Wald Test)")
}

# ── Hosmer-Lemeshow ──────────────────────────────────────────────
hl_html <- function(model, y) {
  hl <- tryCatch(hoslem.test(y, fitted(model), g = 10), error = function(e) NULL)
  if (is.null(hl)) return("<p><em>⚠️ Hosmer-Lemeshow tidak dapat dihitung.</em></p>")
  kbl_h(data.frame(
    Statistik = c("χ² HL", "df", "p-value", "Keputusan"),
    Nilai = c(
      round(hl$statistic, 3), hl$parameter, round(hl$p.value, 4),
      ifelse(hl$p.value > 0.05,
             "✅ Gagal Tolak H0 — Model FIT",
             "❌ Tolak H0 — TIDAK FIT")
    )
  ), "Goodness of Fit (Hosmer-Lemeshow)")
}

# ── Odds Ratio (GLM-based) ───────────────────────────────────────
or_html <- function(model) {
  or <- exp(coef(model))
  kbl_h(data.frame(
    Variabel     = names(or),
    `exp(B)`     = round(or, 4),
    Interpretasi = ifelse(names(or) == "(Intercept)", "Baseline odds",
                   ifelse(or > 1,
                          "↑ Peluang bersekolah lebih besar dibanding referensi",
                          "↓ Peluang bersekolah lebih kecil dibanding referensi")),
    check.names = FALSE
  ), "Interpretasi Parameter (Odds Ratio)")
}

# ── Kriteria Informasi: AIC / AICc / BIC ─────────────────────────
ic_html <- function(model, n, k, method = "glm") {
  if (method == "glm") {
    aic_val <- tryCatch(AIC(model),                error = function(e) NA)
    bic_val <- tryCatch(BIC(model),                error = function(e) NA)
    ll_val  <- tryCatch(as.numeric(logLik(model)), error = function(e) NA)
  } else if (method == "firth") {
    ll_val  <- max(model$loglik)
    aic_val <- -2 * ll_val + 2 * k
    bic_val <- -2 * ll_val + log(n) * k
  } else {
    aic_val <- NA; bic_val <- NA; ll_val <- NA
  }

  aicc_val <- if (!is.na(aic_val) && (n - k - 1) > 0) {
    aic_val + (2 * k^2 + 2 * k) / (n - k - 1)
  } else NA

  if (method == "quasi") {
    phi_est  <- tryCatch(summary(model)$dispersion, error = function(e) 1)
    dev_val  <- model$deviance
    df_r     <- model$df.residual
    qaic_val <- round(dev_val / phi_est + 2 * k, 3)
    rows <- paste0(
      '<tr><td><strong>QAIC</strong></td><td>', qaic_val,
      '</td><td>Quasi-AIC (φ̂ = ', round(phi_est, 3), ')</td></tr>',
      '<tr><td>Deviance Residual</td><td>', round(dev_val, 3),
      '</td><td>df = ', df_r, '</td></tr>',
      '<tr><td>Dispersi (φ̂)</td><td>', round(phi_est, 3),
      '</td><td>Estimasi dispersi quasibinomial</td></tr>',
      '<tr><td style="color:#888;font-style:italic">AIC / BIC</td>',
      '<td style="color:#888">N/A</td>',
      '<td style="color:#888;font-style:italic">Tidak terdefinisi untuk quasibinomial</td></tr>'
    )
  } else {
    rows <- paste0(
      '<tr><td><strong>AIC</strong></td><td>',  round(aic_val,  3),
      '</td><td>Semakin kecil semakin baik</td></tr>',
      '<tr><td><strong>AICc</strong></td><td>', round(aicc_val, 3),
      '</td><td>Koreksi utk sampel kecil</td></tr>',
      '<tr><td><strong>BIC</strong></td><td>',  round(bic_val,  3),
      '</td><td>Penalti lebih besar pada parameter</td></tr>',
      '<tr><td>Log-Likelihood</td><td>',         round(ll_val,  3),
      '</td><td></td></tr>'
    )
  }

  paste0(
    '<table class="table table-striped table-condensed" style="font-size:13px;width:auto;margin-bottom:0">',
    '<thead><tr>',
    '<th style="min-width:130px">Kriteria</th>',
    '<th style="min-width:90px">Nilai</th>',
    '<th>Keterangan</th></tr></thead><tbody>',
    rows,
    '<tr><td>k (parameter)</td><td>', k, '</td><td>Termasuk intercept</td></tr>',
    '<tr><td>n (observasi)</td><td>', n, '</td><td></td></tr>',
    '</tbody></table>'
  )
}

4.2 Fungsi Evaluasi Model

# ── A. Perfect Separation Check ──────────────────────────────────
separation_html <- function(coefs, ses, is_firth = FALSE) {
  if (is_firth) {
    return(paste0(
      '<div class="eval-sub">',
      '<h6>Perfect Separation Check</h6>',
      '<p class="sep-ok">&#10003; Firth (Penalized Likelihood) dirancang khusus ',
      'menangani complete/quasi-complete separation — hasil tetap valid tanpa bias.</p>',
      '</div>'
    ))
  }
  flag_b  <- abs(coefs) > 10
  flag_se <- !is.na(ses) & ses > 5
  flag    <- flag_b | flag_se
  status  <- if (any(flag, na.rm = TRUE)) {
    '<p class="sep-flag">&#9888; Terdeteksi potensi separation pada variabel berikut:</p>'
  } else {
    '<p class="sep-ok">&#10003; Tidak terdeteksi perfect/quasi-complete separation.</p>'
  }
  tbl <- kbl_h(data.frame(
    Variabel   = names(coefs),
    `|B|>10`   = ifelse(flag_b,  "&#9888; Ya", "&#10003; Tidak"),
    `SE>5`     = ifelse(flag_se, "&#9888; Ya", "&#10003; Tidak"),
    Status     = ifelse(flag,
                        '<span class="sep-flag">&#9888; Potensi Separation</span>',
                        '<span class="sep-ok">&#10003; Aman</span>'),
    check.names = FALSE
  ), "Perfect Separation Check")
  paste0('<div class="eval-sub"><h6>Perfect Separation Check</h6>', status, tbl, '</div>')
}

# ── B. Confusion Matrix + Metrics ────────────────────────────────
conf_metrics <- function(y_true, y_prob, cutoff) {
  y_pred <- as.integer(y_prob >= cutoff)
  tp <- sum(y_true == 1 & y_pred == 1)
  tn <- sum(y_true == 0 & y_pred == 0)
  fp <- sum(y_true == 0 & y_pred == 1)
  fn <- sum(y_true == 1 & y_pred == 0)
  acc  <- ifelse((tp + tn + fp + fn) > 0, (tp + tn) / (tp + tn + fp + fn), NA)
  sens <- ifelse((tp + fn) > 0, tp / (tp + fn), NA)
  spec <- ifelse((tn + fp) > 0, tn / (tn + fp), NA)
  prec <- ifelse((tp + fp) > 0, tp / (tp + fp), NA)
  f1   <- ifelse(!is.na(prec) & !is.na(sens) & (prec + sens) > 0,
                 2 * prec * sens / (prec + sens), NA)
  list(tp = tp, tn = tn, fp = fp, fn = fn,
       acc = acc, sens = sens, spec = spec, prec = prec, f1 = f1)
}

conf_block_html <- function(y_true, y_prob, cutoff, label_class, label_text) {
  m   <- conf_metrics(y_true, y_prob, cutoff)
  pct <- function(x) paste0(round(x * 100, 2), " %")
  cm_tbl <- kbl_h(data.frame(
    ` `          = c("Pred: Tidak Bersekolah (0)", "Pred: Bersekolah (1)"),
    `Aktual: 0`  = c(m$tn, m$fp),
    `Aktual: 1`  = c(m$fn, m$tp),
    check.names  = FALSE
  ), paste0("Confusion Matrix — ", label_text))
  chips <- paste0(
    '<div class="metric-row">',
    '<span class="metric-chip">Accuracy: ',    pct(m$acc),  '</span>',
    '<span class="metric-chip">Sensitivity: ', pct(m$sens), '</span>',
    '<span class="metric-chip">Specificity: ', pct(m$spec), '</span>',
    '<span class="metric-chip">Precision: ',   pct(m$prec), '</span>',
    '<span class="metric-chip">F1-Score: ',    pct(m$f1),   '</span>',
    '</div>'
  )
  paste0(
    '<div class="cm-box">',
    '<span class="cm-label ', label_class, '">', label_text, '</span>',
    cm_tbl, chips,
    '</div>'
  )
}

cm_html <- function(y_true, y_prob) {
  roc_obj <- tryCatch(pROC::roc(y_true, y_prob, quiet = TRUE), error = function(e) NULL)
  cut_you <- if (!is.null(roc_obj)) {
    co <- pROC::coords(roc_obj, "best", best.method = "youden", ret = "threshold")
    as.numeric(co[1, 1])
  } else 0.5

  b50 <- conf_block_html(y_true, y_prob, 0.5,     "cut50",  "Cutoff 0.5")
  byo <- conf_block_html(y_true, y_prob, cut_you, "cutyou",
                         paste0("Youden Optimal (", round(cut_you, 3), ")"))
  paste0('<div class="eval-sub"><h6>Confusion Matrix &amp; Metrik Klasifikasi</h6>',
         '<div class="cm-wrap">', b50, byo, '</div></div>')
}

# ── C. ROC-AUC + Toggle Plot ─────────────────────────────────────
roc_html <- function(y_true, y_prob, plot_id) {
  roc_obj <- tryCatch(pROC::roc(y_true, y_prob, quiet = TRUE), error = function(e) NULL)
  if (is.null(roc_obj))
    return('<div class="eval-sub"><h6>ROC-AUC</h6><p><em>ROC tidak dapat dihitung.</em></p></div>')

  auc_val <- as.numeric(pROC::auc(roc_obj))
  auc_cat <- if (auc_val >= 0.9) list(cls = "auc-great", txt = "Sangat Baik")
        else if (auc_val >= 0.8) list(cls = "auc-good",  txt = "Baik")
        else if (auc_val >= 0.7) list(cls = "auc-fair",  txt = "Cukup")
        else                     list(cls = "auc-poor",  txt = "Kurang")

  tmp <- tempfile(fileext = ".png")
  png(tmp, width = 400, height = 400, res = 90)
  plot(roc_obj, col = "#1565c0", lwd = 2.5,
       main = paste0("ROC Curve\nAUC = ", round(auc_val, 4)),
       cex.main = 0.9, cex.axis = 0.8, cex.lab = 0.85)
  abline(a = 0, b = 1, lty = 2, col = "gray60")
  dev.off()
  b64 <- knitr::image_uri(tmp)
  unlink(tmp)

  pid <- gsub("[^a-zA-Z0-9]", "_", plot_id)
  paste0(
    '<div class="eval-sub"><h6>ROC-AUC</h6>',
    '<span class="auc-badge ', auc_cat$cls, '">AUC = ', round(auc_val, 4), '</span>',
    '<strong>', auc_cat$txt, '</strong>',
    ' &nbsp;|&nbsp; Skala: 0.9–1.0 Sangat Baik | 0.8–0.9 Baik | 0.7–0.8 Cukup | &lt;0.7 Kurang<br>',
    '<button class="btn-roc" onclick="toggleRoc(\'', pid, '\')">',
    '&#128200; Tampilkan / Sembunyikan Plot ROC</button>',
    '<div class="roc-plot-wrap" id="roc_', pid, '">',
    '<img src="', b64, '" alt="ROC Curve">',
    '</div></div>'
  )
}

# ── D. Full Evaluasi Section (GLM-based) ─────────────────────────
evaluasi_html <- function(model, y_true, y_prob, plot_id, is_firth = FALSE) {
  coefs <- coef(model)
  ses   <- tryCatch(sqrt(diag(vcov(model))), error = function(e) rep(NA, length(coefs)))
  paste0(
    '<div class="eval-wrap">',
    separation_html(coefs, ses, is_firth),
    cm_html(y_true, y_prob),
    roc_html(y_true, y_prob, plot_id),
    '</div>'
  )
}

# ── D2. Evaluasi SMOTE (2 data: asli + SMOTE) ────────────────────
evaluasi_smote_html <- function(model,
                                 y_true_ori, y_prob_ori,
                                 y_true_sm,  y_prob_sm,
                                 plot_id) {
  coefs <- coef(model)
  ses   <- tryCatch(sqrt(diag(vcov(model))), error = function(e) rep(NA, length(coefs)))
  pid   <- gsub("[^a-zA-Z0-9]", "_", plot_id)

  panel_ori <- paste0(
    '<div class="smote-panel active" id="panel_ori_', pid, '">',
    cm_html(y_true_ori, y_prob_ori),
    roc_html(y_true_ori, y_prob_ori, paste0(plot_id, "_ori")),
    '</div>'
  )
  panel_sm <- paste0(
    '<div class="smote-panel" id="panel_sm_', pid, '">',
    cm_html(y_true_sm, y_prob_sm),
    roc_html(y_true_sm, y_prob_sm, paste0(plot_id, "_smote")),
    '</div>'
  )
  tabs <- paste0(
    '<div class="smote-tabs">',
    '<button class="smote-tab-btn active" ',
    paste0('onclick="switchSmote(\'', pid, '\',\'ori\')">&#128202; Data Asli (Fair)</button>'),
    '<button class="smote-tab-btn" ',
    paste0('onclick="switchSmote(\'', pid, '\',\'sm\')">&#129512; Data SMOTE (In-Sample)</button>'),
    '</div>'
  )
  paste0(
    '<div class="eval-wrap">',
    separation_html(coefs, ses, FALSE),
    '<div class="eval-sub"><h6>Confusion Matrix, Metrik &amp; ROC — Pilih Data</h6>',
    tabs, panel_ori, panel_sm,
    '</div></div>'
  )
}

4.3 Fungsi Analisis — Reglog Biasa

run_biasa <- function(data, nama_dataset) {
  p   <- prep_data(data)
  df  <- p$df; xm <- p$xvars_model; fm <- p$formula_mod

  if (length(xm) == 0) return("<p>⚠️ Tidak ada variabel valid.</p>")

  mdl  <- tryCatch(glm(fm, data = df, family = binomial), error = function(e) NULL)
  mdl0 <- tryCatch(glm(status_sekolah ~ 1, data = df, family = binomial), error = function(e) NULL)
  if (is.null(mdl)) return("<p>⚠️ Model gagal di-fit.</p>")

  info <- paste0('<p><strong>n valid:</strong> ', nrow(df), ' obs.',
    if (length(p$konstan) > 0) paste0(' | <em>Konstan (dikeluarkan): ',
                                       paste(p$konstan, collapse = ", "), '</em>') else '',
    '</p>')

  k_biasa <- length(coef(mdl))
  n_biasa <- nrow(df)
  pid     <- paste0("biasa-", gsub("[^a-zA-Z0-9]", "_", nama_dataset))

  paste0(info,
    sec("📊", "EDA — Distribusi Y",               eda_html(df)),
    sec("📐", "Uji Simultan (G²)",                simultan_html(mdl, mdl0, xm)),
    sec("📋", "Uji Parsial (Wald Test)",           wald_html(mdl)),
    sec("✅", "Goodness of Fit (H-L Test)",        hl_html(mdl, df$status_sekolah)),
    sec("📊", "Kriteria Informasi (AIC/AICc/BIC)", ic_html(mdl, n_biasa, k_biasa, "glm")),
    sec("📈", "Interpretasi Parameter (OR)",       or_html(mdl)),
    sec("🔍", "Evaluasi Model",
        evaluasi_html(mdl, df$status_sekolah, fitted(mdl), pid))
  )
}

4.4 Fungsi Analisis — SMOTE

run_smote <- function(data, nama_dataset) {
  p  <- prep_data(data)
  df <- p$df; xm <- p$xvars_model; fm <- p$formula_mod

  if (length(xm) == 0) return("<p>⚠️ Tidak ada variabel valid.</p>")

  # SMOTE memerlukan input numerik. Faktor X diubah menjadi dummy dengan
  # model.matrix sehingga referensi tetap kategori berkode 0/*.
  X_dummy <- model.matrix(fm, data = df)[, -1, drop = FALSE]
  X_dummy <- as.data.frame(X_dummy)
  names(X_dummy) <- make.names(names(X_dummy), unique = TRUE)
  xm_sm <- names(X_dummy)
  df_eval <- cbind(status_sekolah = df$status_sekolah, X_dummy)
  fm_sm <- as.formula(paste("status_sekolah ~", paste(xm_sm, collapse = " + ")))

  df_sm <- tryCatch({
    res <- smotefamily::SMOTE(
      X        = X_dummy,
      target   = as.character(df$status_sekolah),
      K        = 5,
      dup_size = 0
    )$data
    res$status_sekolah <- as.numeric(as.character(res$class))
    res$class         <- NULL
    res[, c("status_sekolah", xm_sm)]
  }, error = function(e) NULL)

  if (is.null(df_sm))
    return("<p>⚠️ SMOTE gagal — kemungkinan n terlalu kecil atau kelas sangat tidak seimbang.</p>")

  mdl  <- tryCatch(glm(fm_sm, data = df_sm, family = binomial), error = function(e) NULL)
  mdl0 <- tryCatch(glm(status_sekolah ~ 1, data = df_sm, family = binomial), error = function(e) NULL)
  if (is.null(mdl)) return("<p>⚠️ Model GLM setelah SMOTE gagal.</p>")

  # EDA before & after
  t_ori   <- table(df$status_sekolah)
  t_sm    <- table(df_sm$status_sekolah)
  eda_tbl <- kbl_h(data.frame(
    Kategori  = c("Tidak Bersekolah (0)", "Bersekolah (1)"),
    `N Asal`  = as.integer(c(t_ori["0"], t_ori["1"])),
    `N SMOTE` = as.integer(c(t_sm["0"], t_sm["1"])),
    check.names = FALSE
  ), "Distribusi Y Sebelum & Sesudah SMOTE")

  info <- paste0('<p><strong>n asli:</strong> ', nrow(df),
    ' | <strong>n setelah SMOTE:</strong> ', nrow(df_sm),
    ' | <em>X kategorik dikonversi menjadi dummy; referensi tetap kategori bertanda (*).</em></p>')

  k_smote <- length(coef(mdl))
  n_smote <- nrow(df_sm)
  pid     <- paste0("smote-", gsub("[^a-zA-Z0-9]", "_", nama_dataset))

  paste0(info,
    sec("📊", "EDA — Distribusi Y (Sebelum & Sesudah SMOTE)", eda_tbl),
    sec("📐", "Uji Simultan (G²)",       simultan_html(mdl, mdl0, xm_sm)),
    sec("📋", "Uji Parsial (Wald Test)",  wald_html(mdl)),
    sec("✅", "Goodness of Fit (H-L Test)", hl_html(mdl, df_sm$status_sekolah)),
    sec("📊", "Kriteria Informasi (AIC/AICc/BIC)",
        paste0(ic_html(mdl, n_smote, k_smote, "glm"),
               '<p><em><small>&#9432; AIC/AICc/BIC dihitung dari data SMOTE (n = ',
               n_smote, '). Gunakan sebagai perbandingan; evaluasi fair tetap di data asli.</small></em></p>')),
    sec("📈", "Interpretasi Parameter (OR)", or_html(mdl)),
    sec("🔍", "Evaluasi Model",
        evaluasi_smote_html(
          mdl,
          df_eval$status_sekolah, predict(mdl, newdata = df_eval, type = "response"),
          df_sm$status_sekolah,   predict(mdl, newdata = df_sm,   type = "response"),
          pid
        ))
  )
}


5 Hasil Analisis Interaktif

🔧 Filter Hasil Analisis

Metode Analisis

Menghitung...
⚠ Tidak ada hasil yang sesuai pilihan.
Centang minimal satu Metode.

Disabilitas 13–15 Thn | SUSENAS 2023

Reglog Biasa

Reglog Biasa

n valid: 236 obs.

📊 EDA — Distribusi Y
Distribusi Y — Partisipasi Sekolah
Kategori N Persen
Tidak Bersekolah (0) 67 28.39 %
Bersekolah (1) 169 71.61 %
📐 Uji Simultan (G²)
Uji Simultan (Likelihood Ratio Test / G²)
Statistik Nilai
-2LL Null 281.594
-2LL Model 203.756
G² Hitung 77.838
df 11
χ² Tabel (α=5%) 19.675
p-value 0
Keputusan ✅ Tolak H0 — Model Signifikan
📋 Uji Parsial (Wald Test)
Uji Parsial (Wald Test)
Variabel B SE Wald p-value Kesimpulan
(Intercept) (Intercept) -0.6797 0.7621 0.7953 0.3725 ❌ Tdk Signifikan
X1Laki-laki X1Laki-laki 0.6508 0.3658 3.1658 0.0752 ❌ Tdk Signifikan
X2Disabilitas tunggal X2Disabilitas tunggal 1.0966 0.4102 7.1461 0.0075 ✅ Signifikan
X3Kesulitan X3Kesulitan 0.7096 0.4436 2.5596 0.1096 ❌ Tdk Signifikan
X3Sedikit kesulitan X3Sedikit kesulitan 1.5311 0.4762 10.3394 0.0013 ✅ Signifikan
X4Laki-laki X4Laki-laki -1.8781 0.6804 7.6193 0.0058 ✅ Signifikan
X5≥ SMA X5≥ SMA 0.5410 0.4552 1.4125 0.2346 ❌ Tdk Signifikan
X6Pertanian X6Pertanian 1.3186 0.6653 3.9278 0.0475 ✅ Signifikan
X6Nonpertanian X6Nonpertanian 1.9587 0.7039 7.7429 0.0054 ✅ Signifikan
X7Perkotaan X7Perkotaan 0.0628 0.4463 0.0198 0.8881 ❌ Tdk Signifikan
X8Memiliki X8Memiliki 2.4296 1.0571 5.2825 0.0215 ✅ Signifikan
X9Tidak miskin X9Tidak miskin -0.1077 0.4360 0.0611 0.8048 ❌ Tdk Signifikan
✅ Goodness of Fit (H-L Test)
Goodness of Fit (Hosmer-Lemeshow)
Statistik Nilai
χ² HL 5.362
df 8
p-value 0.7183
Keputusan ✅ Gagal Tolak H0 — Model FIT
📊 Kriteria Informasi (AIC/AICc/BIC)
KriteriaNilaiKeterangan
AIC227.756Semakin kecil semakin baik
AICc229.155Koreksi utk sampel kecil
BIC269.322Penalti lebih besar pada parameter
Log-Likelihood-101.878
k (parameter)12Termasuk intercept
n (observasi)236
📈 Interpretasi Parameter (OR)
Interpretasi Parameter (Odds Ratio)
Variabel exp(B) Interpretasi
(Intercept) (Intercept) 0.5068 Baseline odds
X1Laki-laki X1Laki-laki 1.9171 ↑ Peluang bersekolah lebih besar dibanding referensi
X2Disabilitas tunggal X2Disabilitas tunggal 2.9941 ↑ Peluang bersekolah lebih besar dibanding referensi
X3Kesulitan X3Kesulitan 2.0333 ↑ Peluang bersekolah lebih besar dibanding referensi
X3Sedikit kesulitan X3Sedikit kesulitan 4.6233 ↑ Peluang bersekolah lebih besar dibanding referensi
X4Laki-laki X4Laki-laki 0.1529 ↓ Peluang bersekolah lebih kecil dibanding referensi
X5≥ SMA X5≥ SMA 1.7177 ↑ Peluang bersekolah lebih besar dibanding referensi
X6Pertanian X6Pertanian 3.7381 ↑ Peluang bersekolah lebih besar dibanding referensi
X6Nonpertanian X6Nonpertanian 7.0899 ↑ Peluang bersekolah lebih besar dibanding referensi
X7Perkotaan X7Perkotaan 1.0648 ↑ Peluang bersekolah lebih besar dibanding referensi
X8Memiliki X8Memiliki 11.3545 ↑ Peluang bersekolah lebih besar dibanding referensi
X9Tidak miskin X9Tidak miskin 0.8979 ↓ Peluang bersekolah lebih kecil dibanding referensi
🔍 Evaluasi Model
Perfect Separation Check

✓ Tidak terdeteksi perfect/quasi-complete separation.

Perfect Separation Check
Variabel |B|>10 SE>5 Status
(Intercept) (Intercept) ✓ Tidak ✓ Tidak ✓ Aman
X1Laki-laki X1Laki-laki ✓ Tidak ✓ Tidak ✓ Aman
X2Disabilitas tunggal X2Disabilitas tunggal ✓ Tidak ✓ Tidak ✓ Aman
X3Kesulitan X3Kesulitan ✓ Tidak ✓ Tidak ✓ Aman
X3Sedikit kesulitan X3Sedikit kesulitan ✓ Tidak ✓ Tidak ✓ Aman
X4Laki-laki X4Laki-laki ✓ Tidak ✓ Tidak ✓ Aman
X5≥ SMA X5≥ SMA ✓ Tidak ✓ Tidak ✓ Aman
X6Pertanian X6Pertanian ✓ Tidak ✓ Tidak ✓ Aman
X6Nonpertanian X6Nonpertanian ✓ Tidak ✓ Tidak ✓ Aman
X7Perkotaan X7Perkotaan ✓ Tidak ✓ Tidak ✓ Aman
X8Memiliki X8Memiliki ✓ Tidak ✓ Tidak ✓ Aman
X9Tidak miskin X9Tidak miskin ✓ Tidak ✓ Tidak ✓ Aman
Confusion Matrix & Metrik Klasifikasi
Cutoff 0.5
Confusion Matrix — Cutoff 0.5
Aktual: 0 Aktual: 1
Pred: Tidak Bersekolah (0) 32 20
Pred: Bersekolah (1) 35 149
Accuracy: 76.69 %Sensitivity: 88.17 %Specificity: 47.76 %Precision: 80.98 %F1-Score: 84.42 %
Youden Optimal (0.682)
Confusion Matrix — Youden Optimal (0.682)
Aktual: 0 Aktual: 1
Pred: Tidak Bersekolah (0) 50 36
Pred: Bersekolah (1) 17 133
Accuracy: 77.54 %Sensitivity: 78.7 %Specificity: 74.63 %Precision: 88.67 %F1-Score: 83.39 %
ROC-AUC
AUC = 0.8386Baik  |  Skala: 0.9–1.0 Sangat Baik | 0.8–0.9 Baik | 0.7–0.8 Cukup | <0.7 Kurang
ROC Curve

Disabilitas 13–15 Thn | SUSENAS 2023

SMOTE

SMOTE

n asli: 236 | n setelah SMOTE: 303 | X kategorik dikonversi menjadi dummy; referensi tetap kategori bertanda (*).

📊 EDA — Distribusi Y (Sebelum & Sesudah SMOTE)
Distribusi Y Sebelum & Sesudah SMOTE
Kategori N Asal N SMOTE
Tidak Bersekolah (0) 67 134
Bersekolah (1) 169 169
📐 Uji Simultan (G²)
Uji Simultan (Likelihood Ratio Test / G²)
Statistik Nilai
-2LL Null 415.995
-2LL Model 284.483
G² Hitung 131.513
df 11
χ² Tabel (α=5%) 19.675
p-value 0
Keputusan ✅ Tolak H0 — Model Signifikan
📋 Uji Parsial (Wald Test)
Uji Parsial (Wald Test)
Variabel B SE Wald p-value Kesimpulan
(Intercept) (Intercept) -1.2632 0.6591 3.6726 0.0553 ❌ Tdk Signifikan
X1Laki.laki X1Laki.laki 0.7577 0.3183 5.6679 0.0173 ✅ Signifikan
X2Disabilitas.tunggal X2Disabilitas.tunggal 1.0459 0.3573 8.5694 0.0034 ✅ Signifikan
X3Kesulitan X3Kesulitan 0.8244 0.3837 4.6165 0.0317 ✅ Signifikan
X3Sedikit.kesulitan X3Sedikit.kesulitan 1.6785 0.4224 15.7910 0.0001 ✅ Signifikan
X4Laki.laki X4Laki.laki -2.2616 0.6079 13.8394 0.0002 ✅ Signifikan
X5..SMA X5..SMA 0.7019 0.4010 3.0635 0.0801 ❌ Tdk Signifikan
X6Pertanian X6Pertanian 1.4950 0.6385 5.4819 0.0192 ✅ Signifikan
X6Nonpertanian X6Nonpertanian 2.2649 0.6658 11.5709 0.0007 ✅ Signifikan
X7Perkotaan X7Perkotaan -0.1586 0.4006 0.1567 0.6922 ❌ Tdk Signifikan
X8Memiliki X8Memiliki 2.9258 0.9464 9.5569 0.0020 ✅ Signifikan
X9Tidak.miskin X9Tidak.miskin -0.1674 0.3845 0.1895 0.6633 ❌ Tdk Signifikan
✅ Goodness of Fit (H-L Test)
Goodness of Fit (Hosmer-Lemeshow)
Statistik Nilai
χ² HL 12.392
df 8
p-value 0.1345
Keputusan ✅ Gagal Tolak H0 — Model FIT
📊 Kriteria Informasi (AIC/AICc/BIC)
KriteriaNilaiKeterangan
AIC308.483Semakin kecil semakin baik
AICc309.559Koreksi utk sampel kecil
BIC353.047Penalti lebih besar pada parameter
Log-Likelihood-142.241
k (parameter)12Termasuk intercept
n (observasi)303

ⓘ AIC/AICc/BIC dihitung dari data SMOTE (n = 303). Gunakan sebagai perbandingan; evaluasi fair tetap di data asli.

📈 Interpretasi Parameter (OR)
Interpretasi Parameter (Odds Ratio)
Variabel exp(B) Interpretasi
(Intercept) (Intercept) 0.2828 Baseline odds
X1Laki.laki X1Laki.laki 2.1334 ↑ Peluang bersekolah lebih besar dibanding referensi
X2Disabilitas.tunggal X2Disabilitas.tunggal 2.8459 ↑ Peluang bersekolah lebih besar dibanding referensi
X3Kesulitan X3Kesulitan 2.2804 ↑ Peluang bersekolah lebih besar dibanding referensi
X3Sedikit.kesulitan X3Sedikit.kesulitan 5.3574 ↑ Peluang bersekolah lebih besar dibanding referensi
X4Laki.laki X4Laki.laki 0.1042 ↓ Peluang bersekolah lebih kecil dibanding referensi
X5..SMA X5..SMA 2.0176 ↑ Peluang bersekolah lebih besar dibanding referensi
X6Pertanian X6Pertanian 4.4591 ↑ Peluang bersekolah lebih besar dibanding referensi
X6Nonpertanian X6Nonpertanian 9.6298 ↑ Peluang bersekolah lebih besar dibanding referensi
X7Perkotaan X7Perkotaan 0.8533 ↓ Peluang bersekolah lebih kecil dibanding referensi
X8Memiliki X8Memiliki 18.6498 ↑ Peluang bersekolah lebih besar dibanding referensi
X9Tidak.miskin X9Tidak.miskin 0.8459 ↓ Peluang bersekolah lebih kecil dibanding referensi
🔍 Evaluasi Model
Perfect Separation Check

✓ Tidak terdeteksi perfect/quasi-complete separation.

Perfect Separation Check
Variabel |B|>10 SE>5 Status
(Intercept) (Intercept) ✓ Tidak ✓ Tidak ✓ Aman
X1Laki.laki X1Laki.laki ✓ Tidak ✓ Tidak ✓ Aman
X2Disabilitas.tunggal X2Disabilitas.tunggal ✓ Tidak ✓ Tidak ✓ Aman
X3Kesulitan X3Kesulitan ✓ Tidak ✓ Tidak ✓ Aman
X3Sedikit.kesulitan X3Sedikit.kesulitan ✓ Tidak ✓ Tidak ✓ Aman
X4Laki.laki X4Laki.laki ✓ Tidak ✓ Tidak ✓ Aman
X5..SMA X5..SMA ✓ Tidak ✓ Tidak ✓ Aman
X6Pertanian X6Pertanian ✓ Tidak ✓ Tidak ✓ Aman
X6Nonpertanian X6Nonpertanian ✓ Tidak ✓ Tidak ✓ Aman
X7Perkotaan X7Perkotaan ✓ Tidak ✓ Tidak ✓ Aman
X8Memiliki X8Memiliki ✓ Tidak ✓ Tidak ✓ Aman
X9Tidak.miskin X9Tidak.miskin ✓ Tidak ✓ Tidak ✓ Aman
Confusion Matrix, Metrik & ROC — Pilih Data
Confusion Matrix & Metrik Klasifikasi
Cutoff 0.5
Confusion Matrix — Cutoff 0.5
Aktual: 0 Aktual: 1
Pred: Tidak Bersekolah (0) 47 33
Pred: Bersekolah (1) 20 136
Accuracy: 77.54 %Sensitivity: 80.47 %Specificity: 70.15 %Precision: 87.18 %F1-Score: 83.69 %
Youden Optimal (0.515)
Confusion Matrix — Youden Optimal (0.515)
Aktual: 0 Aktual: 1
Pred: Tidak Bersekolah (0) 49 33
Pred: Bersekolah (1) 18 136
Accuracy: 78.39 %Sensitivity: 80.47 %Specificity: 73.13 %Precision: 88.31 %F1-Score: 84.21 %
ROC-AUC
AUC = 0.8378Baik  |  Skala: 0.9–1.0 Sangat Baik | 0.8–0.9 Baik | 0.7–0.8 Cukup | <0.7 Kurang
ROC Curve
Confusion Matrix & Metrik Klasifikasi
Cutoff 0.5
Confusion Matrix — Cutoff 0.5
Aktual: 0 Aktual: 1
Pred: Tidak Bersekolah (0) 99 33
Pred: Bersekolah (1) 35 136
Accuracy: 77.56 %Sensitivity: 80.47 %Specificity: 73.88 %Precision: 79.53 %F1-Score: 80 %
Youden Optimal (0.515)
Confusion Matrix — Youden Optimal (0.515)
Aktual: 0 Aktual: 1
Pred: Tidak Bersekolah (0) 101 33
Pred: Bersekolah (1) 33 136
Accuracy: 78.22 %Sensitivity: 80.47 %Specificity: 75.37 %Precision: 80.47 %F1-Score: 80.47 %
ROC-AUC
AUC = 0.8511Baik  |  Skala: 0.9–1.0 Sangat Baik | 0.8–0.9 Baik | 0.7–0.8 Cukup | <0.7 Kurang
ROC Curve