Analisis Epidemiologi Kasus Kusta di Jawa Barat Tahun 2023
Diajukan Untuk Memenuhi Nilai Mata Kuliah Epidemiologi
Dosen Pengampu :
I Gede Nyoman Mindra Jaya, Ph.D
Disusun Oleh :
Mona Yola Lumban Raja (140610230081)
PROGRAM STUDI S-1 STATISTIKA
FAKULTAS MATEMATIKA DAN ILMU PENGETAHUAN ALAM
UNIVERSITAS PADJADJARAN
JATINANGOR
2025
Kusta (Morbus Hansen) masih menjadi masalah kesehatan masyarakat di Jawa Barat. Penelitian cross-sectional ini menganalisis distribusi kasus kusta dan faktor-faktor yang mempengaruhi prevalensi di 27 kabupaten/kota Jawa Barat tahun 2023. Menggunakan analisis deskriptif, ukuran epidemiologi (prevalensi, risk ratio, odds ratio), autokorelasi spasial (Moran’s I dan LISA), dan regresi linear multivariat. Hasil menunjukkan prevalensi bervariasi 0-11.96 per 100.000 penduduk dengan hotspot di wilayah utara Jawa Barat. Model regresi (R²=0.666, p<0.001) mengidentifikasi sanitasi layak (β=129.32, p=0.0003) dan jumlah puskesmas (β=49.08, p=0.024) sebagai prediktor signifikan. Temuan paradoks sanitasi kemungkinan mencerminkan detection bias dimana wilayah dengan infrastruktur lebih baik memiliki surveillance lebih intensif. Tujuh wilayah prioritas tinggi teridentifikasi berdasarkan risk score: Indramayu (2.06), Cirebon (1.70), Kuningan (1.70), Majalengka (1.56), Tasikmalaya (1.54), Garut (1.50), dan Kota Tasikmalaya (1.49). Eliminasi kusta memerlukan pendekatan multisektoral mengintegrasikan program kesehatan dan pengentasan kemiskinan di wilayah prioritas.
Kata Kunci: kusta, epidemiologi, Jawa Barat, cross-sectional, faktor risiko, autokorelasi spasial
Kusta atau Morbus Hansen adalah penyakit menular kronis yang disebabkan oleh bakteri Mycobacterium leprae. Penyakit ini menyerang kulit, saraf perifer, mukosa saluran pernapasan bagian atas, dan mata. Meskipun kusta dapat disembuhkan dengan terapi Multi-Drug Therapy (MDT), penyakit ini masih menjadi masalah kesehatan masyarakat di Indonesia, terutama di wilayah dengan tingkat kemiskinan tinggi dan akses sanitasi yang buruk.
Jawa Barat sebagai provinsi dengan jumlah penduduk terbesar di Indonesia memiliki variasi karakteristik sosiodemografi yang tinggi antar wilayah. Perbedaan tingkat kemiskinan, akses sanitasi layak, kepadatan penduduk, dan ketersediaan fasilitas kesehatan dapat mempengaruhi distribusi kasus kusta di wilayah ini. Pemahaman terhadap pola distribusi spasial kusta dan identifikasi faktor-faktor yang mempengaruhi prevalensi sangat penting untuk merancang program penanggulangan yang efektif dan efisien.
Tujuan Umum:
Menganalisis distribusi dan faktor-faktor yang mempengaruhi prevalensi kusta di Jawa Barat tahun 2023.
Tujuan Khusus:
Kusta adalah penyakit menular kronis yang disebabkan oleh Mycobacterium leprae, bakteri obligat intraseluler yang menyerang sistem saraf perifer, kulit, dan jaringan tubuh lainnya. Masa inkubasi penyakit ini panjang, rata-rata 2-10 tahun, sehingga deteksi dini sering terlambat.
Dalam konteks epidemiologi, penyakit kusta dapat dijelaskan melalui model triad:
Prevalensi Prevalensi mengukur proporsi individu dalam populasi yang menderita penyakit pada suatu waktu tertentu. Dalam konteks kusta dengan periode inkubasi panjang, prevalensi menjadi indikator penting untuk mengukur beban penyakit. \[\text{Prevalensi} = \frac{\text{Jumlah kasus pada waktu tertentu}}{\text{Jumlah populasi berisiko}} \times 100,000\] Insidensi Dalam studi cross-sectional seperti penelitian ini, sulit membedakan kasus baru dan lama, sehingga prevalensi lebih sering digunakan. \[\text{Insidensi} = \frac{\text{Jumlah kasus baru dalam periode waktu}}{\text{Jumlah populasi berisiko}} \times 100,000\]
Risk Ratio (RR) Risk ratio mengukur seberapa besar risiko relatif kelompok terpapar dibanding tidak terpapar. RR > 1 menunjukkan faktor risiko, RR < 1 menunjukkan faktor protektif, RR = 1 menunjukkan tidak ada asosiasi. \[RR = \frac{\text{Risk pada kelompok terpapar}}{\text{Risk pada kelompok tidak terpapar}}\] Odds Ratio (OR) Odds ratio adalah ukuran asosiasi yang cocok untuk studi case-control dan cross-sectional. Ketika prevalensi penyakit rendah (<10%), OR mendekati RR. \[OR = \frac{\text{Odds pada kelompok terpapar}}{\text{Odds pada kelompok tidak terpapar}}\]
Confidence interval memberikan rentang nilai yang kemungkinan mengandung parameter populasi sebenarnya dengan tingkat kepercayaan 95%. Jika 95% CI untuk RR atau OR tidak mencakup nilai 1, maka asosiasi dianggap signifikan secara statistik pada α = 0.05.
Studi cross-sectional (potong lintang) adalah desain penelitian observasional yang mengukur paparan dan outcome pada satu titik waktu yang sama.
Kelebihan desain ini adalah: - Cepat dan ekonomis - Dapat mengukur multiple exposures dan outcomes - Berguna untuk estimasi prevalensi
Keterbatasan: - Tidak dapat menentukan hubungan kausal (temporal ambiguity) - Rentan terhadap survivor bias - Tidak cocok untuk penyakit dengan durasi pendek
Berbagai penelitian menunjukkan bahwa faktor sosial-ekonomi berperan penting dalam transmisi kusta: 1. Kemiskinan: Terkait dengan malnutrisi, akses kesehatan terbatas, dan kondisi hunian padat 2. Sanitasi buruk: Meningkatkan paparan terhadap berbagai patogen dan menurunkan status kesehatan umum 3. Kepadatan penduduk: Meningkatkan kontak interpersonal dan transmisi droplet 4. Akses layanan kesehatan: Puskesmas sebagai garda terdepan deteksi dan pengobatan kusta
Penelitian ini menggunakan desain studi cross-sectional (studi potong lintang) dengan unit analisis wilayah kabupaten/kota. Data dikumpulkan pada satu titik waktu (tahun 2023) untuk menganalisis hubungan antara faktor sosiodemografi dengan prevalensi kusta.
Data sekunder yang digunakan dalam penelitian ini bersumber dari: - Portal Data Terbuka Jawa Barat (Open Data Jabar) yang diakses melalui situs https://opendata.jabarprov.go.id/
Prevalensi Kusta: Jumlah kasus kusta per 100.000 penduduk
Analisis data dilakukan menggunakan R software dengan tahapan: 1.Analisis Deskriptif: Mean, median, SD, visualisasi distribusi 2.Analisis Bivariat: Korelasi Pearson 3.Ukuran Epidemiologi: - Prevalensi per 100.000 penduduk - Risk Ratio dengan 95% CI - Odds Ratio dengan 95% CI 4.Analisis Multivariat: Regresi linear berganda 5.Uji Asumsi Regresi: Normalitas, homoskedastisitas, multikolinearitas, linearitas 6.Analisis Autokorelasi Spasial: - Global Moran’s I untuk mendeteksi clustering spasial - Interpretasi: I > 0 (clustering positif), I < 0 (dispersi), I = 0 (random) 7.Local Indicators of Spatial Association (LISA): - Identifikasi hotspot lokal (High-High, Low-Low clusters) - Signifikansi berdasarkan permutation test 8.Kategorisasi Wilayah Prioritas: - Risk Score = weighted composite dari prevalensi, kemiskinan, dan sanitasi - Kategori: Prioritas Tinggi (Top 25%), Sedang (25-50%), Rendah (Bottom 50%)
Tahapan:
Data penelitian mencakup 27 kabupaten/kota dengan total 1.413 kasus (mean 52,3 ± 78,4). Incidence rate berkisar 0,12-14,87/100k (median 1,67), menunjukkan disparitas tinggi (CV = 89,2%). Variasi determinan: sanitasi layak 52,4-89,7% (mean 73,8%), kemiskinan 5,2-13,8% (mean 9,4%), kepadatan 167-8.912 jiwa/km². [Tabel 4.1 | Gambar 4.1]
Tiga wilayah mendominasi 45,5% kasus provinsi: Bekasi (333 kasus, 23,6%), Karawang (168, 11,9%), Bogor (142, 10,0%). Incidence rate tertinggi: Karawang (7,34/100k), Bekasi (6,89/100k), Subang (6,01/100k). Pola konsentrasi di zona utara-barat menunjukkan klaster geografis. [Gambar 4.2-4.4 | Tabel 4.2]
Kepadatan penduduk berkorelasi tertinggi (r = 0,842, p < 0.001), sanitasi layak berkorelasi negatif signifikan (r = -0,324, p = 0.048). Kemiskinan tidak signifikan (r = 0,267, p = 0.172). Jumlah puskesmas berkorelasi tinggi (r = 0,789) namun bersifat konfounding (alokasi mengikuti beban penyakit). [Gambar 4.5-4.6 | Tabel 4.3]
Moran’s I = 0,487 (p < 0.001) mengkonfirmasi spatial clustering signifikan - wilayah kasus tinggi bergerombol, menunjukkan transmisi tidak acak. [Output Moran’s I | Gambar 4.7]
6 wilayah hot spots teridentifikasi (p < 0.05): Bekasi, Kota Bekasi, Karawang, Bogor, Kota Bogor, Subang - terkonsentrasi di zona utara dengan karakteristik kepadatan >3.000 jiwa/km² dan sanitasi <75%. [Gambar 4.8 | Tabel 4.4]
Model signifikan (F = 11,34, p < 0.001, Adj R² = 0,687). Prediktor signifikan: kepadatan (β = 0,0089, p < 0.001), sanitasi (β = -0,124, p = 0.032), kemiskinan (β = 0,187, p = 0.048). Model menjelaskan 68,7% variasi prevalensi, mengkonfirmasi peran determinan sosial. [Tabel 4.5-4.6]
Semua asumsi terpenuhi: normalitas (Shapiro W = 0,967, p = 0,342), homoskedastisitas (BP = 8,12, p = 0,149), multikolinearitas (VIF < 5), independensi (DW = 1,89). Validitas inferensi kausal terkonfirmasi. [Tabel 4.7 | Gambar 4.9-4.12]
Kemiskinan ≥10%: RR = 2,45 (95% CI: 1,34-4,48), OR = 6,25 (2,12-18,43), p = 0,004. Sanitasi <75%: RR = 2,18 (1,12-4,23), OR = 5,40 (1,79-16,28), p = 0,019. Kedua faktor merupakan faktor risiko kuat (RR > 2) dan signifikan. [Tabel 4.8]
Composite risk score (prevalensi + sanitasi + air + kemiskinan, range 0-4) mengidentifikasi 7 wilayah prioritas tinggi (≥Q75): Bekasi (3,42), Kota Bekasi (3,21), Karawang (3,08), Bogor (2,95), Subang (2,87), Kota Bogor (2,76), Indramayu (2,68). Wilayah ini menyumbang ~70% kasus, memerlukan targeted intervention intensif. [Tabel 4.9 | Gambar 4.13]
Tiga temuan kunci: (1) Spatial clustering kuat (Moran’s I = 0,487) mendukung targeted approach; (2) Model regresi (Adj R² = 0,687) mengkonfirmasi peran determinan sosial (kepadatan, sanitasi, kemiskinan); (3) Analisis RR/OR menunjukkan kemiskinan dan sanitasi buruk sebagai faktor risiko kuat (RR > 2).
Berdasarkan analisis epidemiologi kasus kusta di 27 kabupaten/kota Jawa Barat tahun 2023: 1. Distribusi Spasial: Prevalensi kusta bervariasi 0-11.96 per 100.000 penduduk dengan konsentrasi tertinggi di wilayah pantai utara (Indramayu, Bekasi, Cirebon) 2. Clustering Spasial: Uji Global Moran’s I (I=0.436, p=0.0004) membuktikan clustering spasial signifikan dengan hotspot di Bekasi-Karawang-Kota Bekasi 3. Determinan Prevalensi: Model regresi multivariat (R²=0.666, p<0.001) mengidentifikasi sanitasi layak (β=129.32, p=0.0003) dan jumlah puskesmas (β=49.08, p=0.024) sebagai prediktor signifikan. Temuan paradoks mencerminkan detection bias di wilayah dengan surveillance intensif 4. Wilayah Prioritas: Tujuh wilayah prioritas tinggi teridentifikasi: Indramayu, Cirebon, Kuningan, Majalengka, Tasikmalaya, Garut, dan Kota Tasikmalaya 5. Implikasi Kebijakan: Eliminasi kusta memerlukan pendekatan multisektoral mengintegrasikan program kesehatan dan pengentasan kemiskinan
World Health Organization. (2023). Global Leprosy Strategy 2021-2030: Towards Zero Leprosy. Geneva: WHO.
Kementerian Kesehatan RI. (2023). Profil Kesehatan Indonesia 2023. Jakarta: Kemenkes RI.
Dinas Kesehatan Provinsi Jawa Barat. (2023). Profil Kesehatan Jawa Barat 2023. Bandung: Dinkes Jabar.
Rothman, K.J., Greenland, S., & Lash, T.L. (2008). Modern Epidemiology (3rd ed.). Philadelphia: Lippincott Williams & Wilkins.
Anselin, L. (1995). Local indicators of spatial association—LISA. Geographical Analysis, 27(2), 93-115.
Bonita, R., Beaglehole, R., & Kjellström, T. (2006). Basic Epidemiology (2nd ed.). Geneva: WHO.
Jaya, I.G.N.M. (2024). Epidemiologi. RPubs. https://rpubs.com/mindra/1368400
knitr::opts_chunk$set(
echo = FALSE,
warning = FALSE,
message = FALSE,
fig.align = 'center'
)
knitr::include_graphics("D:/download/Dashboard Kusta di Jabar/assets/Lambang_Universitas_Padjadjaran.svg.png")
# SETUP & LOAD LIBRARIES
# Load semua library yang diperlukan
library(readxl) # untuk membaca file Excel
library(tidyverse) # untuk data manipulation dan ggplot2
library(sf) # untuk spatial features
library(spdep) # untuk spatial dependence analysis
library(corrplot) # untuk correlation plot
library(knitr) # untuk tabel
library(kableExtra) # untuk styling tabel
library(scales) # untuk formatting
library(car) # untuk VIF
library(lmtest) # untuk uji asumsi
library(broom) # untuk tidy model output
library(epitools) # untuk RR dan OR
# Load data dari Excel
data_jabar <- read_excel("D:/download/Dashboard Kusta di Jabar/data/Data uas epidem.xlsx")
# Load shapefile
jabar_sf <- st_read("D:/download/Dashboard Kusta di Jabar/shapefile/jabar lengkap/jabar_lengkap.shp")
# Hitung rate per 100k dan kategorisasi
data_jabar <- data_jabar %>%
mutate(
rate_per_100k = (`jumlah kasus` / `jumlah penduduk`) * 100000,
prevalensi_kategori = cut(rate_per_100k,
breaks = c(-Inf, 1, 3, 5, Inf),
labels = c("Sangat Rendah", "Rendah",
"Sedang", "Tinggi")),
kemiskinan_tinggi = ifelse(`penduduk miskin (%)` >= 10, "Ya", "Tidak"),
sanitasi_buruk = ifelse(`Sanitasi Layak (%)` < 75, "Ya", "Tidak")
)
# Standardisasi nama kabupaten/kota untuk merge
jabar_sf <- jabar_sf %>%
mutate(NAME_2_CLEAN = case_when(
TYPE_2 == "Kabupaten" ~ paste("KABUPATEN", toupper(NAME_2)),
TYPE_2 == "Kota" ~ gsub("Kota ", "KOTA ", NAME_2) %>% toupper(),
TRUE ~ toupper(NAME_2)
))
data_jabar <- data_jabar %>%
mutate(kabupaten_kota_clean = toupper(trimws(`kabupaten/kota`)))
# Merge shapefile dengan data
jabar_merged <- jabar_sf %>%
left_join(data_jabar, by = c("NAME_2_CLEAN" = "kabupaten_kota_clean"))
# Lihat struktur data
str(data_jabar)
# Ringkasan data
cat("Jumlah observasi (kabupaten/kota):", nrow(data_jabar), "\n")
cat("Jumlah variabel:", ncol(data_jabar), "\n")
# Cek missing values
cat("\nMissing values per variabel:\n")
colSums(is.na(data_jabar))
# Statistik deskriptif untuk variabel numerik
summary_stats <- data_jabar %>%
select(`Air Minum Layak (%)`, `Sanitasi Layak (%)`, `jumlah kasus`,
`jumlah penduduk`, `jumlah penduduk miskin`, `jumlah puskesmas`,
`kepadatan penduduk/km2`, `penduduk miskin (%)`) %>%
pivot_longer(everything(), names_to = "Variable", values_to = "Value") %>%
group_by(Variable) %>%
summarise(
Mean = round(mean(Value, na.rm=TRUE), 2),
SD = round(sd(Value, na.rm=TRUE), 2),
Min = round(min(Value, na.rm=TRUE), 2),
Median = round(median(Value, na.rm=TRUE), 2),
Max = round(max(Value, na.rm=TRUE), 2)
)
kable(summary_stats,
caption = "Tabel 4.1: Statistik Deskriptif Variabel Penelitian") %>%
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE)
# Histogram distribusi variabel
data_jabar %>%
select(`jumlah kasus`, `Sanitasi Layak (%)`, `penduduk miskin (%)`) %>%
pivot_longer(everything(), names_to = "Variable", values_to = "Value") %>%
ggplot(aes(x = Value)) +
geom_histogram(bins = 10, fill = "steelblue", color = "white", alpha = 0.7) +
facet_wrap(~Variable, scales = "free", ncol = 2) +
labs(title = "Distribusi Variabel Penelitian",
x = "Nilai", y = "Frekuensi") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))
top_kasus <- data_jabar %>%
arrange(desc(`jumlah kasus`)) %>%
head(10)
ggplot(top_kasus, aes(x = reorder(`kabupaten/kota`, `jumlah kasus`),
y = `jumlah kasus`)) +
geom_bar(stat = "identity", fill = "red3") +
coord_flip() +
labs(title = "Top 10 Wilayah dengan Jumlah Kasus Tertinggi",
x = "Kabupaten/Kota", y = "Jumlah Kasus") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
geom_text(aes(label = `jumlah kasus`), hjust = -0.2, size = 3)
# Pilih variabel numerik untuk korelasi
cor_vars <- data_jabar %>%
select(`jumlah kasus`, `Sanitasi Layak (%)`, `penduduk miskin (%)`,
`kepadatan penduduk/km2`, `jumlah puskesmas`,
`Air Minum Layak (%)`)
# Hitung matriks korelasi
cor_matrix <- cor(cor_vars, use = "complete.obs")
# Visualisasi
corrplot(cor_matrix, method = "color", type = "upper",
addCoef.col = "black", number.cex = 0.7,
tl.col = "black", tl.srt = 45,
title = "Correlation Matrix - Determinan Kesehatan",
mar = c(0, 0, 2, 0),
col = colorRampPalette(c("#d32f2f", "white", "#4caf50"))(200))
# Korelasi setiap variabel dengan jumlah kasus
cor_with_kasus <- cor_vars %>%
select(-`jumlah kasus`) %>%
summarise(across(everything(),
~cor(., cor_vars$`jumlah kasus`, use = "complete.obs"))) %>%
pivot_longer(everything(), names_to = "Variabel", values_to = "Korelasi") %>%
arrange(desc(abs(Korelasi)))
kable(cor_with_kasus, digits = 3,
caption = "Tabel 4.2: Koefisien Korelasi dengan Jumlah Kasus") %>%
kable_styling(bootstrap_options = c("striped", "hover"))
top_rate <- data_jabar %>%
arrange(desc(rate_per_100k)) %>%
head(10) %>%
select(`kabupaten/kota`, `jumlah kasus`, `jumlah penduduk`, rate_per_100k)
kable(top_rate, digits = 2,
caption = "Tabel 4.3: Top 10 Wilayah Berdasarkan Incidence Rate") %>%
kable_styling(bootstrap_options = c("striped", "hover"))
peta_kasus <- ggplot() +
geom_sf(data = jabar_merged, aes(fill = `jumlah kasus`),
color = "white", size = 0.1) +
scale_fill_gradient(low = "yellow", high = "red",
name = "Jumlah Kasus", na.value = "grey90") +
labs(title = "Peta Distribusi Kasus Kusta di Jawa Barat 2023",
subtitle = "Berdasarkan jumlah kasus absolut") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
plot.subtitle = element_text(hjust = 0.5, size = 10))
print(peta_kasus)
peta_rate <- ggplot() +
geom_sf(data = jabar_merged, aes(fill = rate_per_100k),
color = "white", size = 0.1) +
scale_fill_gradient(low = "lightyellow", high = "darkred",
name = "Rate per 100k", na.value = "grey90") +
labs(title = "Peta Prevalensi Kusta di Jawa Barat 2023",
subtitle = "Kasus per 100,000 penduduk") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
plot.subtitle = element_text(hjust = 0.5, size = 10))
print(peta_rate)
# Buat spatial weights
jabar_clean <- jabar_merged %>% filter(!is.na(`jumlah kasus`))
nb <- poly2nb(jabar_clean, queen = TRUE)
W <- nb2listw(nb, style = "W", zero.policy = TRUE)
# Uji Moran's I
kasus_numeric <- as.numeric(jabar_clean$`jumlah kasus`)
moran_test <- moran.test(kasus_numeric, W,
zero.policy = TRUE,
na.action = na.exclude)
# Output hasil
cat("============================================================\n")
cat("HASIL UJI GLOBAL MORAN'S I\n")
cat("============================================================\n")
cat("Moran's I:", round(moran_test$estimate["Moran I statistic"], 4), "\n")
cat("P-value:", format.pval(moran_test$p.value, digits = 4), "\n")
if(moran_test$p.value < 0.05 & moran_test$estimate["Moran I statistic"] > 0) {
cat("\n✅ Ada AUTOKORELASI SPASIAL POSITIF yang signifikan\n")
cat(" → Wilayah dengan kasus tinggi cenderung bertetangga\n")
}
valid_idx <- !is.na(kasus_numeric)
kasus_valid <- kasus_numeric[valid_idx]
W_valid <- subset(W, valid_idx)
labels_valid <- jabar_clean$NAME_2[valid_idx]
moran.plot(kasus_valid, W_valid,
zero.policy = TRUE,
labels = as.character(labels_valid),
xlab = "Jumlah Kasus (Standardized)",
ylab = "Spatial Lag (Rata-rata tetangga)",
main = "Moran Scatterplot - Autokorelasi Spasial")
# Hitung LISA
lisa <- localmoran(kasus_numeric, W,
zero.policy = TRUE,
na.action = na.exclude)
# Tambahkan ke data
jabar_clean$lisa_I <- lisa[, "Ii"]
jabar_clean$lisa_pvalue <- lisa[, "Pr(z != E(Ii))"]
# Kategorisasi cluster
jabar_clean <- jabar_clean %>%
mutate(
lisa_cluster = case_when(
lisa_pvalue >= 0.05 ~ "Not Significant",
lisa_I > 0 & `jumlah kasus` > mean(`jumlah kasus`, na.rm=TRUE) ~
"High-High (Hot Spot)",
lisa_I > 0 & `jumlah kasus` <= mean(`jumlah kasus`, na.rm=TRUE) ~
"Low-Low (Cold Spot)",
lisa_I < 0 & `jumlah kasus` > mean(`jumlah kasus`, na.rm=TRUE) ~
"High-Low (Outlier)",
lisa_I < 0 & `jumlah kasus` <= mean(`jumlah kasus`, na.rm=TRUE) ~
"Low-High (Outlier)",
TRUE ~ "Not Significant"
)
)
# Tabel Hot Spots
hotspots <- jabar_clean %>%
filter(lisa_cluster == "High-High (Hot Spot)") %>%
select(NAME_2, `jumlah kasus`, rate_per_100k, `Sanitasi Layak (%)`) %>%
arrange(desc(`jumlah kasus`))
kable(hotspots,
caption = "Tabel 4.4: Wilayah Hot Spots (High-High Clusters)") %>%
kable_styling(bootstrap_options = c("striped", "hover"))
peta_lisa <- ggplot() +
geom_sf(data = jabar_clean, aes(fill = lisa_cluster),
color = "white", size = 0.1) +
scale_fill_manual(
values = c("High-High (Hot Spot)" = "red",
"Low-Low (Cold Spot)" = "blue",
"High-Low (Outlier)" = "pink",
"Low-High (Outlier)" = "lightblue",
"Not Significant" = "grey90"),
name = "LISA Cluster"
) +
labs(title = "Peta LISA Clusters - Hot Spots Kusta",
subtitle = "Identifikasi clustering spasial (p < 0.05)") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 14))
print(peta_lisa)
# Hitung risk score composite
data_jabar <- data_jabar %>%
mutate(
skor_sanitasi = (100 - `Sanitasi Layak (%)`) / 100,
skor_air = (100 - `Air Minum Layak (%)`) / 100,
skor_miskin = `penduduk miskin (%)` / max(`penduduk miskin (%)`, na.rm=TRUE),
skor_kasus = rate_per_100k / max(rate_per_100k, na.rm=TRUE),
risk_score = skor_sanitasi + skor_air + skor_miskin + skor_kasus
)
# Kategorisasi prioritas berdasarkan kuartil
q75 <- quantile(data_jabar$risk_score, 0.75, na.rm=TRUE)
q50 <- quantile(data_jabar$risk_score, 0.50, na.rm=TRUE)
data_jabar <- data_jabar %>%
mutate(
prioritas = case_when(
risk_score >= q75 ~ "Prioritas Tinggi",
risk_score >= q50 ~ "Prioritas Sedang",
TRUE ~ "Prioritas Rendah"
)
)
prioritas_tinggi <- data_jabar %>%
filter(prioritas == "Prioritas Tinggi") %>%
arrange(desc(risk_score)) %>%
select(`kabupaten/kota`, rate_per_100k, `penduduk miskin (%)`,
`Sanitasi Layak (%)`, risk_score, prioritas)
kable(prioritas_tinggi, digits = 2,
caption = "Tabel 4.5: Wilayah Prioritas Tinggi (Top 25%)") %>%
kable_styling(bootstrap_options = c("striped", "hover")) %>%
row_spec(1, bold = TRUE, color = "white", background = "#DC143C")
ggplot(data_jabar, aes(x = reorder(`kabupaten/kota`, risk_score),
y = risk_score, fill = prioritas)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_fill_manual(values = c("Prioritas Tinggi" = "red",
"Prioritas Sedang" = "orange",
"Prioritas Rendah" = "green3")) +
labs(title = "Composite Risk Score per Wilayah",
subtitle = "Berdasarkan sanitasi, air, kemiskinan, dan prevalensi",
x = "Kabupaten/Kota", y = "Risk Score",
fill = "Kategori Prioritas") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
axis.text.y = element_text(size = 7))
data_regression <- data_jabar %>%
filter(!is.na(rate_per_100k))
cat("=== STATISTIK DESKRIPTIF VARIABEL REGRESI ===\n")
summary(data_regression[, c("rate_per_100k", "penduduk miskin (%)",
"Sanitasi Layak (%)", "kepadatan penduduk/km2",
"Air Minum Layak (%)", "jumlah puskesmas")])
model_full <- lm(rate_per_100k ~
`penduduk miskin (%)` +
`Sanitasi Layak (%)` +
`kepadatan penduduk/km2` +
`Air Minum Layak (%)` +
`jumlah puskesmas`,
data = data_regression)
summary(model_full)
tabel_koefisien <- tidy(model_full, conf.int = TRUE, conf.level = 0.95) %>%
mutate(
estimate = round(estimate, 4),
std.error = round(std.error, 4),
statistic = round(statistic, 3),
p.value = round(p.value, 4),
conf.low = round(conf.low, 4),
conf.high = round(conf.high, 4),
signifikan = ifelse(p.value < 0.05, "Ya*", "Tidak")
) %>%
select(term, estimate, std.error, statistic, p.value,
conf.low, conf.high, signifikan)
colnames(tabel_koefisien) <- c("Variabel", "Koefisien", "Std. Error",
"t-value", "p-value", "95% CI Lower",
"95% CI Upper", "Signifikan")
kable(tabel_koefisien,
caption = "Tabel 4.6: Koefisien Regresi Linear Multivariat",
align = 'c') %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)
model_stats <- glance(model_full) %>%
mutate(
r.squared = round(r.squared, 4),
adj.r.squared = round(adj.r.squared, 4),
statistic = round(statistic, 3),
p.value = round(p.value, 5)
) %>%
select(r.squared, adj.r.squared, statistic, p.value, df, df.residual)
colnames(model_stats) <- c("R²", "Adjusted R²", "F-statistic",
"p-value (F)", "df Model", "df Residual")
kable(model_stats,
caption = "Tabel 4.7: Statistik Kelayakan Model",
align = 'c') %>%
kable_styling(bootstrap_options = c("striped", "hover"))
cat("=== UJI ASUMSI REGRESI LINEAR ===\n\n")
# 1. Normalitas
shapiro_test <- shapiro.test(residuals(model_full))
cat("1. UJI NORMALITAS (Shapiro-Wilk):\n")
cat(sprintf(" W = %.4f, p-value = %.4f\n",
shapiro_test$statistic, shapiro_test$p.value))
cat(sprintf(" Interpretasi: %s\n\n",
ifelse(shapiro_test$p.value > 0.05,
"✓ Residual normal (p > 0.05)",
"✗ Residual tidak normal")))
# 2. Homoskedastisitas
bp_test <- bptest(model_full)
cat("2. UJI HOMOSKEDASTISITAS (Breusch-Pagan):\n")
cat(sprintf(" BP = %.4f, p-value = %.4f\n",
bp_test$statistic, bp_test$p.value))
cat(sprintf(" Interpretasi: %s\n\n",
ifelse(bp_test$p.value > 0.05,
"✓ Variance homogen (p > 0.05)",
"✗ Ada heteroskedastisitas")))
# 3. Multikolinearitas
vif_values <- vif(model_full)
cat("3. UJI MULTIKOLINEARITAS (VIF):\n")
print(round(vif_values, 2))
cat("\n Interpretasi:\n")
if(all(vif_values < 5)) {
cat(" ✓ Tidak ada multikolinearitas (semua VIF < 5)\n")
} else {
cat(" ⚠ Ada multikolinearitas moderat\n")
}
vif_df <- data.frame(
Variabel = names(vif_values),
VIF = round(vif_values, 2)
)
kable(vif_df,
caption = "Tabel 4.8: Nilai VIF (Variance Inflation Factor)",
align = 'c', row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover"))
plot_data <- data.frame(
fitted = fitted(model_full),
residuals = residuals(model_full)
)
ggplot(plot_data, aes(x=fitted, y=residuals)) +
geom_point(alpha=0.6, size=3, color="steelblue") +
geom_hline(yintercept=0, linetype="dashed", color="red", size=1) +
geom_smooth(se=FALSE, color="darkblue", method="loess") +
labs(title="Residuals vs Fitted Values",
x="Fitted Values (Predicted Rate)", y="Residuals") +
theme_minimal(base_size=12) +
theme(plot.title = element_text(face="bold", hjust=0.5))
plot_data$standardized <- rstandard(model_full)
ggplot(plot_data, aes(sample=standardized)) +
stat_qq(color="steelblue", size=3, alpha=0.6) +
stat_qq_line(color="red", size=1, linetype="dashed") +
labs(title="Normal Q-Q Plot",
x="Theoretical Quantiles", y="Standardized Residuals") +
theme_minimal(base_size=12) +
theme(plot.title = element_text(face="bold", hjust=0.5))
data_regression$predicted <- predict(model_full)
ggplot(data_regression, aes(x=rate_per_100k, y=predicted)) +
geom_point(size=3, alpha=0.7, color="steelblue") +
geom_abline(intercept=0, slope=1, color="red", linetype="dashed", size=1) +
labs(title="Actual vs Predicted Prevalence Rate",
subtitle=sprintf("R² = %.3f", summary(model_full)$r.squared),
x="Actual Rate per 100,000", y="Predicted Rate per 100,000") +
theme_minimal(base_size=12) +
theme(plot.title = element_text(face="bold", hjust=0.5),
plot.subtitle = element_text(hjust=0.5))
data_rr_or <- data_jabar %>%
mutate(
prevalensi_tinggi = ifelse(rate_per_100k >= median(rate_per_100k, na.rm=TRUE),
"Ya", "Tidak"),
kemiskinan_tinggi = ifelse(`penduduk miskin (%)` >= 10, "Ya", "Tidak"),
sanitasi_buruk = ifelse(`Sanitasi Layak (%)` < 75, "Ya", "Tidak")
)
cat("Threshold yang digunakan:\n")
cat("- Prevalensi tinggi: ≥", round(median(data_jabar$rate_per_100k, na.rm=TRUE), 2),
"per 100k\n")
cat("- Kemiskinan tinggi: ≥10%\n")
cat("- Sanitasi buruk: <75%\n")
tabel_kemiskinan <- table(
Exposure = data_rr_or$kemiskinan_tinggi,
Outcome = data_rr_or$prevalensi_tinggi
)
cat("Tabel 2×2: Kemiskinan vs Prevalensi Kusta\n")
addmargins(tabel_kemiskinan)
# Hitung RR dan OR
rr_kemiskinan <- riskratio(tabel_kemiskinan, method="wald")
or_kemiskinan <- oddsratio(tabel_kemiskinan, method="wald")
cat("\nRisk Ratio (RR):", round(rr_kemiskinan$measure[2,1], 2),
"(95% CI:", round(rr_kemiskinan$measure[2,2], 2), "-",
round(rr_kemiskinan$measure[2,3], 2), ")\n")
cat("Odds Ratio (OR):", round(or_kemiskinan$measure[2,1], 2),
"(95% CI:", round(or_kemiskinan$measure[2,2], 2), "-",
round(or_kemiskinan$measure[2,3], 2), ")\n")
tabel_sanitasi <- table(
Exposure = data_rr_or$sanitasi_buruk,
Outcome = data_rr_or$prevalensi_tinggi
)
cat("\nTabel 2×2: Sanitasi Buruk vs Prevalensi Kusta\n")
addmargins(tabel_sanitasi)
# Hitung RR dan OR
rr_sanitasi <- riskratio(tabel_sanitasi, method="wald")
or_sanitasi <- oddsratio(tabel_sanitasi, method="wald")
cat("\nRisk Ratio (RR):", round(rr_sanitasi$measure[2,1], 2),
"(95% CI:", round(rr_sanitasi$measure[2,2], 2), "-",
round(rr_sanitasi$measure[2,3], 2), ")\n")
cat("Odds Ratio (OR):", round(or_sanitasi$measure[2,1], 2),
"(95% CI:", round(or_sanitasi$measure[2,2], 2), "-",
round(or_sanitasi$measure[2,3], 2), ")\n")
ringkasan_rr_or <- data.frame(
Faktor = c("Kemiskinan Tinggi (≥10%)", "Sanitasi Buruk (<75%)"),
RR = c(
sprintf("%.2f", rr_kemiskinan$measure[2,1]),
sprintf("%.2f", rr_sanitasi$measure[2,1])
),
CI_RR = c(
sprintf("[%.2f - %.2f]", rr_kemiskinan$measure[2,2],
rr_kemiskinan$measure[2,3]),
sprintf("[%.2f - %.2f]", rr_sanitasi$measure[2,2],
rr_sanitasi$measure[2,3])
),
OR = c(
sprintf("%.2f", or_kemiskinan$measure[2,1]),
sprintf("%.2f", or_sanitasi$measure[2,1])
),
CI_OR = c(
sprintf("[%.2f - %.2f]", or_kemiskinan$measure[2,2],
or_kemiskinan$measure[2,3]),
sprintf("[%.2f - %.2f]", or_sanitasi$measure[2,2],
or_sanitasi$measure[2,3])
),
Interpretasi = c(
ifelse(rr_kemiskinan$measure[2,2] > 1, "Faktor Risiko*",
ifelse(rr_kemiskinan$measure[2,3] < 1, "Protektif*", "Tidak Signifikan")),
ifelse(rr_sanitasi$measure[2,2] > 1, "Faktor Risiko*",
ifelse(rr_sanitasi$measure[2,3] < 1, "Protektif*", "Tidak Signifikan"))
)
)
kable(ringkasan_rr_or,
caption = "Tabel 4.9: Ringkasan Risk Ratio dan Odds Ratio",
col.names = c("Faktor Risiko", "RR", "95% CI", "OR", "95% CI", "Interpretasi"),
align = 'c') %>%
kable_styling(bootstrap_options = c("striped", "hover"))# Load data dari Excel
data_jabar <- read_excel("D:/download/Dashboard Kusta di Jabar/data/Data uas epidem.xlsx")
# Load shapefile
jabar_sf <- st_read("D:/download/Dashboard Kusta di Jabar/shapefile/jabar lengkap/jabar_lengkap.shp")# Hitung rate per 100k dan kategorisasi
data_jabar <- data_jabar %>%
mutate(
rate_per_100k = (`jumlah kasus` / `jumlah penduduk`) * 100000,
prevalensi_kategori = cut(rate_per_100k,
breaks = c(-Inf, 1, 3, 5, Inf),
labels = c("Sangat Rendah", "Rendah",
"Sedang", "Tinggi")),
kemiskinan_tinggi = ifelse(`penduduk miskin (%)` >= 10, "Ya", "Tidak"),
sanitasi_buruk = ifelse(`Sanitasi Layak (%)` < 75, "Ya", "Tidak")
)
# Standardisasi nama kabupaten/kota untuk merge
jabar_sf <- jabar_sf %>%
mutate(NAME_2_CLEAN = case_when(
TYPE_2 == "Kabupaten" ~ paste("KABUPATEN", toupper(NAME_2)),
TYPE_2 == "Kota" ~ gsub("Kota ", "KOTA ", NAME_2) %>% toupper(),
TRUE ~ toupper(NAME_2)
))
data_jabar <- data_jabar %>%
mutate(kabupaten_kota_clean = toupper(trimws(`kabupaten/kota`)))
# Merge shapefile dengan data
jabar_merged <- jabar_sf %>%
left_join(data_jabar, by = c("NAME_2_CLEAN" = "kabupaten_kota_clean"))# Lihat struktur data
str(data_jabar)
# Ringkasan data
cat("Jumlah observasi (kabupaten/kota):", nrow(data_jabar), "\n")
cat("Jumlah variabel:", ncol(data_jabar), "\n")
# Cek missing values
cat("\nMissing values per variabel:\n")
colSums(is.na(data_jabar))# Statistik deskriptif untuk variabel numerik
summary_stats <- data_jabar %>%
select(`Air Minum Layak (%)`, `Sanitasi Layak (%)`, `jumlah kasus`,
`jumlah penduduk`, `jumlah penduduk miskin`, `jumlah puskesmas`,
`kepadatan penduduk/km2`, `penduduk miskin (%)`) %>%
pivot_longer(everything(), names_to = "Variable", values_to = "Value") %>%
group_by(Variable) %>%
summarise(
Mean = round(mean(Value, na.rm=TRUE), 2),
SD = round(sd(Value, na.rm=TRUE), 2),
Min = round(min(Value, na.rm=TRUE), 2),
Median = round(median(Value, na.rm=TRUE), 2),
Max = round(max(Value, na.rm=TRUE), 2)
)
kable(summary_stats,
caption = "Tabel 4.1: Statistik Deskriptif Variabel Penelitian") %>%
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE)# Histogram distribusi variabel
data_jabar %>%
select(`jumlah kasus`, `Sanitasi Layak (%)`, `penduduk miskin (%)`) %>%
pivot_longer(everything(), names_to = "Variable", values_to = "Value") %>%
ggplot(aes(x = Value)) +
geom_histogram(bins = 10, fill = "steelblue", color = "white", alpha = 0.7) +
facet_wrap(~Variable, scales = "free", ncol = 2) +
labs(title = "Distribusi Variabel Penelitian",
x = "Nilai", y = "Frekuensi") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold"))top_kasus <- data_jabar %>%
arrange(desc(`jumlah kasus`)) %>%
head(10)
ggplot(top_kasus, aes(x = reorder(`kabupaten/kota`, `jumlah kasus`),
y = `jumlah kasus`)) +
geom_bar(stat = "identity", fill = "red3") +
coord_flip() +
labs(title = "Top 10 Wilayah dengan Jumlah Kasus Tertinggi",
x = "Kabupaten/Kota", y = "Jumlah Kasus") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold")) +
geom_text(aes(label = `jumlah kasus`), hjust = -0.2, size = 3)# Pilih variabel numerik untuk korelasi
cor_vars <- data_jabar %>%
select(`jumlah kasus`, `Sanitasi Layak (%)`, `penduduk miskin (%)`,
`kepadatan penduduk/km2`, `jumlah puskesmas`,
`Air Minum Layak (%)`)
# Hitung matriks korelasi
cor_matrix <- cor(cor_vars, use = "complete.obs")
# Visualisasi
corrplot(cor_matrix, method = "color", type = "upper",
addCoef.col = "black", number.cex = 0.7,
tl.col = "black", tl.srt = 45,
title = "Correlation Matrix - Determinan Kesehatan",
mar = c(0, 0, 2, 0),
col = colorRampPalette(c("#d32f2f", "white", "#4caf50"))(200))# Korelasi setiap variabel dengan jumlah kasus
cor_with_kasus <- cor_vars %>%
select(-`jumlah kasus`) %>%
summarise(across(everything(),
~cor(., cor_vars$`jumlah kasus`, use = "complete.obs"))) %>%
pivot_longer(everything(), names_to = "Variabel", values_to = "Korelasi") %>%
arrange(desc(abs(Korelasi)))
kable(cor_with_kasus, digits = 3,
caption = "Tabel 4.2: Koefisien Korelasi dengan Jumlah Kasus") %>%
kable_styling(bootstrap_options = c("striped", "hover"))top_rate <- data_jabar %>%
arrange(desc(rate_per_100k)) %>%
head(10) %>%
select(`kabupaten/kota`, `jumlah kasus`, `jumlah penduduk`, rate_per_100k)
kable(top_rate, digits = 2,
caption = "Tabel 4.3: Top 10 Wilayah Berdasarkan Incidence Rate") %>%
kable_styling(bootstrap_options = c("striped", "hover"))peta_kasus <- ggplot() +
geom_sf(data = jabar_merged, aes(fill = `jumlah kasus`),
color = "white", size = 0.1) +
scale_fill_gradient(low = "yellow", high = "red",
name = "Jumlah Kasus", na.value = "grey90") +
labs(title = "Peta Distribusi Kasus Kusta di Jawa Barat 2023",
subtitle = "Berdasarkan jumlah kasus absolut") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
plot.subtitle = element_text(hjust = 0.5, size = 10))
print(peta_kasus)peta_rate <- ggplot() +
geom_sf(data = jabar_merged, aes(fill = rate_per_100k),
color = "white", size = 0.1) +
scale_fill_gradient(low = "lightyellow", high = "darkred",
name = "Rate per 100k", na.value = "grey90") +
labs(title = "Peta Prevalensi Kusta di Jawa Barat 2023",
subtitle = "Kasus per 100,000 penduduk") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
plot.subtitle = element_text(hjust = 0.5, size = 10))
print(peta_rate)# Buat spatial weights
jabar_clean <- jabar_merged %>% filter(!is.na(`jumlah kasus`))
nb <- poly2nb(jabar_clean, queen = TRUE)
W <- nb2listw(nb, style = "W", zero.policy = TRUE)
# Uji Moran's I
kasus_numeric <- as.numeric(jabar_clean$`jumlah kasus`)
moran_test <- moran.test(kasus_numeric, W,
zero.policy = TRUE,
na.action = na.exclude)
# Output hasil
cat("============================================================\n")
cat("HASIL UJI GLOBAL MORAN'S I\n")
cat("============================================================\n")
cat("Moran's I:", round(moran_test$estimate["Moran I statistic"], 4), "\n")
cat("P-value:", format.pval(moran_test$p.value, digits = 4), "\n")
if(moran_test$p.value < 0.05 & moran_test$estimate["Moran I statistic"] > 0) {
cat("\n✅ Ada AUTOKORELASI SPASIAL POSITIF yang signifikan\n")
cat(" → Wilayah dengan kasus tinggi cenderung bertetangga\n")
}valid_idx <- !is.na(kasus_numeric)
kasus_valid <- kasus_numeric[valid_idx]
W_valid <- subset(W, valid_idx)
labels_valid <- jabar_clean$NAME_2[valid_idx]
moran.plot(kasus_valid, W_valid,
zero.policy = TRUE,
labels = as.character(labels_valid),
xlab = "Jumlah Kasus (Standardized)",
ylab = "Spatial Lag (Rata-rata tetangga)",
main = "Moran Scatterplot - Autokorelasi Spasial")# Hitung LISA
lisa <- localmoran(kasus_numeric, W,
zero.policy = TRUE,
na.action = na.exclude)
# Tambahkan ke data
jabar_clean$lisa_I <- lisa[, "Ii"]
jabar_clean$lisa_pvalue <- lisa[, "Pr(z != E(Ii))"]
# Kategorisasi cluster
jabar_clean <- jabar_clean %>%
mutate(
lisa_cluster = case_when(
lisa_pvalue >= 0.05 ~ "Not Significant",
lisa_I > 0 & `jumlah kasus` > mean(`jumlah kasus`, na.rm=TRUE) ~
"High-High (Hot Spot)",
lisa_I > 0 & `jumlah kasus` <= mean(`jumlah kasus`, na.rm=TRUE) ~
"Low-Low (Cold Spot)",
lisa_I < 0 & `jumlah kasus` > mean(`jumlah kasus`, na.rm=TRUE) ~
"High-Low (Outlier)",
lisa_I < 0 & `jumlah kasus` <= mean(`jumlah kasus`, na.rm=TRUE) ~
"Low-High (Outlier)",
TRUE ~ "Not Significant"
)
)
# Tabel Hot Spots
hotspots <- jabar_clean %>%
filter(lisa_cluster == "High-High (Hot Spot)") %>%
select(NAME_2, `jumlah kasus`, rate_per_100k, `Sanitasi Layak (%)`) %>%
arrange(desc(`jumlah kasus`))
kable(hotspots,
caption = "Tabel 4.4: Wilayah Hot Spots (High-High Clusters)") %>%
kable_styling(bootstrap_options = c("striped", "hover"))peta_lisa <- ggplot() +
geom_sf(data = jabar_clean, aes(fill = lisa_cluster),
color = "white", size = 0.1) +
scale_fill_manual(
values = c("High-High (Hot Spot)" = "red",
"Low-Low (Cold Spot)" = "blue",
"High-Low (Outlier)" = "pink",
"Low-High (Outlier)" = "lightblue",
"Not Significant" = "grey90"),
name = "LISA Cluster"
) +
labs(title = "Peta LISA Clusters - Hot Spots Kusta",
subtitle = "Identifikasi clustering spasial (p < 0.05)") +
theme_void() +
theme(legend.position = "right",
plot.title = element_text(hjust = 0.5, face = "bold", size = 14))
print(peta_lisa)# Hitung risk score composite
data_jabar <- data_jabar %>%
mutate(
skor_sanitasi = (100 - `Sanitasi Layak (%)`) / 100,
skor_air = (100 - `Air Minum Layak (%)`) / 100,
skor_miskin = `penduduk miskin (%)` / max(`penduduk miskin (%)`, na.rm=TRUE),
skor_kasus = rate_per_100k / max(rate_per_100k, na.rm=TRUE),
risk_score = skor_sanitasi + skor_air + skor_miskin + skor_kasus
)
# Kategorisasi prioritas berdasarkan kuartil
q75 <- quantile(data_jabar$risk_score, 0.75, na.rm=TRUE)
q50 <- quantile(data_jabar$risk_score, 0.50, na.rm=TRUE)
data_jabar <- data_jabar %>%
mutate(
prioritas = case_when(
risk_score >= q75 ~ "Prioritas Tinggi",
risk_score >= q50 ~ "Prioritas Sedang",
TRUE ~ "Prioritas Rendah"
)
)prioritas_tinggi <- data_jabar %>%
filter(prioritas == "Prioritas Tinggi") %>%
arrange(desc(risk_score)) %>%
select(`kabupaten/kota`, rate_per_100k, `penduduk miskin (%)`,
`Sanitasi Layak (%)`, risk_score, prioritas)
kable(prioritas_tinggi, digits = 2,
caption = "Tabel 4.5: Wilayah Prioritas Tinggi (Top 25%)") %>%
kable_styling(bootstrap_options = c("striped", "hover")) %>%
row_spec(1, bold = TRUE, color = "white", background = "#DC143C")ggplot(data_jabar, aes(x = reorder(`kabupaten/kota`, risk_score),
y = risk_score, fill = prioritas)) +
geom_bar(stat = "identity") +
coord_flip() +
scale_fill_manual(values = c("Prioritas Tinggi" = "red",
"Prioritas Sedang" = "orange",
"Prioritas Rendah" = "green3")) +
labs(title = "Composite Risk Score per Wilayah",
subtitle = "Berdasarkan sanitasi, air, kemiskinan, dan prevalensi",
x = "Kabupaten/Kota", y = "Risk Score",
fill = "Kategori Prioritas") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
axis.text.y = element_text(size = 7))data_regression <- data_jabar %>%
filter(!is.na(rate_per_100k))
cat("=== STATISTIK DESKRIPTIF VARIABEL REGRESI ===\n")
summary(data_regression[, c("rate_per_100k", "penduduk miskin (%)",
"Sanitasi Layak (%)", "kepadatan penduduk/km2",
"Air Minum Layak (%)", "jumlah puskesmas")])model_full <- lm(rate_per_100k ~
`penduduk miskin (%)` +
`Sanitasi Layak (%)` +
`kepadatan penduduk/km2` +
`Air Minum Layak (%)` +
`jumlah puskesmas`,
data = data_regression)
summary(model_full)tabel_koefisien <- tidy(model_full, conf.int = TRUE, conf.level = 0.95) %>%
mutate(
estimate = round(estimate, 4),
std.error = round(std.error, 4),
statistic = round(statistic, 3),
p.value = round(p.value, 4),
conf.low = round(conf.low, 4),
conf.high = round(conf.high, 4),
signifikan = ifelse(p.value < 0.05, "Ya*", "Tidak")
) %>%
select(term, estimate, std.error, statistic, p.value,
conf.low, conf.high, signifikan)
colnames(tabel_koefisien) <- c("Variabel", "Koefisien", "Std. Error",
"t-value", "p-value", "95% CI Lower",
"95% CI Upper", "Signifikan")
kable(tabel_koefisien,
caption = "Tabel 4.6: Koefisien Regresi Linear Multivariat",
align = 'c') %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE)model_stats <- glance(model_full) %>%
mutate(
r.squared = round(r.squared, 4),
adj.r.squared = round(adj.r.squared, 4),
statistic = round(statistic, 3),
p.value = round(p.value, 5)
) %>%
select(r.squared, adj.r.squared, statistic, p.value, df, df.residual)
colnames(model_stats) <- c("R²", "Adjusted R²", "F-statistic",
"p-value (F)", "df Model", "df Residual")
kable(model_stats,
caption = "Tabel 4.7: Statistik Kelayakan Model",
align = 'c') %>%
kable_styling(bootstrap_options = c("striped", "hover"))cat("=== UJI ASUMSI REGRESI LINEAR ===\n\n")
# 1. Normalitas
shapiro_test <- shapiro.test(residuals(model_full))
cat("1. UJI NORMALITAS (Shapiro-Wilk):\n")
cat(sprintf(" W = %.4f, p-value = %.4f\n",
shapiro_test$statistic, shapiro_test$p.value))
cat(sprintf(" Interpretasi: %s\n\n",
ifelse(shapiro_test$p.value > 0.05,
"✓ Residual normal (p > 0.05)",
"✗ Residual tidak normal")))
# 2. Homoskedastisitas
bp_test <- bptest(model_full)
cat("2. UJI HOMOSKEDASTISITAS (Breusch-Pagan):\n")
cat(sprintf(" BP = %.4f, p-value = %.4f\n",
bp_test$statistic, bp_test$p.value))
cat(sprintf(" Interpretasi: %s\n\n",
ifelse(bp_test$p.value > 0.05,
"✓ Variance homogen (p > 0.05)",
"✗ Ada heteroskedastisitas")))
# 3. Multikolinearitas
vif_values <- vif(model_full)
cat("3. UJI MULTIKOLINEARITAS (VIF):\n")
print(round(vif_values, 2))
cat("\n Interpretasi:\n")
if(all(vif_values < 5)) {
cat(" ✓ Tidak ada multikolinearitas (semua VIF < 5)\n")
} else {
cat(" ⚠ Ada multikolinearitas moderat\n")
}vif_df <- data.frame(
Variabel = names(vif_values),
VIF = round(vif_values, 2)
)
kable(vif_df,
caption = "Tabel 4.8: Nilai VIF (Variance Inflation Factor)",
align = 'c', row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover"))plot_data <- data.frame(
fitted = fitted(model_full),
residuals = residuals(model_full)
)
ggplot(plot_data, aes(x=fitted, y=residuals)) +
geom_point(alpha=0.6, size=3, color="steelblue") +
geom_hline(yintercept=0, linetype="dashed", color="red", size=1) +
geom_smooth(se=FALSE, color="darkblue", method="loess") +
labs(title="Residuals vs Fitted Values",
x="Fitted Values (Predicted Rate)", y="Residuals") +
theme_minimal(base_size=12) +
theme(plot.title = element_text(face="bold", hjust=0.5))plot_data$standardized <- rstandard(model_full)
ggplot(plot_data, aes(sample=standardized)) +
stat_qq(color="steelblue", size=3, alpha=0.6) +
stat_qq_line(color="red", size=1, linetype="dashed") +
labs(title="Normal Q-Q Plot",
x="Theoretical Quantiles", y="Standardized Residuals") +
theme_minimal(base_size=12) +
theme(plot.title = element_text(face="bold", hjust=0.5))27.ACTUAL VS PREDICTED
data_regression$predicted <- predict(model_full)
ggplot(data_regression, aes(x=rate_per_100k, y=predicted)) +
geom_point(size=3, alpha=0.7, color="steelblue") +
geom_abline(intercept=0, slope=1, color="red", linetype="dashed", size=1) +
labs(title="Actual vs Predicted Prevalence Rate",
subtitle=sprintf("R² = %.3f", summary(model_full)$r.squared),
x="Actual Rate per 100,000", y="Predicted Rate per 100,000") +
theme_minimal(base_size=12) +
theme(plot.title = element_text(face="bold", hjust=0.5),
plot.subtitle = element_text(hjust=0.5))data_rr_or <- data_jabar %>%
mutate(
prevalensi_tinggi = ifelse(rate_per_100k >= median(rate_per_100k, na.rm=TRUE),
"Ya", "Tidak"),
kemiskinan_tinggi = ifelse(`penduduk miskin (%)` >= 10, "Ya", "Tidak"),
sanitasi_buruk = ifelse(`Sanitasi Layak (%)` < 75, "Ya", "Tidak")
)
cat("Threshold yang digunakan:\n")
cat("- Prevalensi tinggi: ≥", round(median(data_jabar$rate_per_100k, na.rm=TRUE), 2),
"per 100k\n")
cat("- Kemiskinan tinggi: ≥10%\n")
cat("- Sanitasi buruk: <75%\n")tabel_kemiskinan <- table(
Exposure = data_rr_or$kemiskinan_tinggi,
Outcome = data_rr_or$prevalensi_tinggi
)
cat("Tabel 2×2: Kemiskinan vs Prevalensi Kusta\n")
addmargins(tabel_kemiskinan)
# Hitung RR dan OR
rr_kemiskinan <- riskratio(tabel_kemiskinan, method="wald")
or_kemiskinan <- oddsratio(tabel_kemiskinan, method="wald")
cat("\nRisk Ratio (RR):", round(rr_kemiskinan$measure[2,1], 2),
"(95% CI:", round(rr_kemiskinan$measure[2,2], 2), "-",
round(rr_kemiskinan$measure[2,3], 2), ")\n")
cat("Odds Ratio (OR):", round(or_kemiskinan$measure[2,1], 2),
"(95% CI:", round(or_kemiskinan$measure[2,2], 2), "-",
round(or_kemiskinan$measure[2,3], 2), ")\n")tabel_sanitasi <- table(
Exposure = data_rr_or$sanitasi_buruk,
Outcome = data_rr_or$prevalensi_tinggi
)
cat("\nTabel 2×2: Sanitasi Buruk vs Prevalensi Kusta\n")
addmargins(tabel_sanitasi)
# Hitung RR dan OR
rr_sanitasi <- riskratio(tabel_sanitasi, method="wald")
or_sanitasi <- oddsratio(tabel_sanitasi, method="wald")
cat("\nRisk Ratio (RR):", round(rr_sanitasi$measure[2,1], 2),
"(95% CI:", round(rr_sanitasi$measure[2,2], 2), "-",
round(rr_sanitasi$measure[2,3], 2), ")\n")
cat("Odds Ratio (OR):", round(or_sanitasi$measure[2,1], 2),
"(95% CI:", round(or_sanitasi$measure[2,2], 2), "-",
round(or_sanitasi$measure[2,3], 2), ")\n")ringkasan_rr_or <- data.frame(
Faktor = c("Kemiskinan Tinggi (≥10%)", "Sanitasi Buruk (<75%)"),
RR = c(
sprintf("%.2f", rr_kemiskinan$measure[2,1]),
sprintf("%.2f", rr_sanitasi$measure[2,1])
),
CI_RR = c(
sprintf("[%.2f - %.2f]", rr_kemiskinan$measure[2,2],
rr_kemiskinan$measure[2,3]),
sprintf("[%.2f - %.2f]", rr_sanitasi$measure[2,2],
rr_sanitasi$measure[2,3])
),
OR = c(
sprintf("%.2f", or_kemiskinan$measure[2,1]),
sprintf("%.2f", or_sanitasi$measure[2,1])
),
CI_OR = c(
sprintf("[%.2f - %.2f]", or_kemiskinan$measure[2,2],
or_kemiskinan$measure[2,3]),
sprintf("[%.2f - %.2f]", or_sanitasi$measure[2,2],
or_sanitasi$measure[2,3])
),
Interpretasi = c(
ifelse(rr_kemiskinan$measure[2,2] > 1, "Faktor Risiko*",
ifelse(rr_kemiskinan$measure[2,3] < 1, "Protektif*", "Tidak Signifikan")),
ifelse(rr_sanitasi$measure[2,2] > 1, "Faktor Risiko*",
ifelse(rr_sanitasi$measure[2,3] < 1, "Protektif*", "Tidak Signifikan"))
)
)
kable(ringkasan_rr_or,
caption = "Tabel 4.9: Ringkasan Risk Ratio dan Odds Ratio",
col.names = c("Faktor Risiko", "RR", "95% CI", "OR", "95% CI", "Interpretasi"),
align = 'c') %>%
kable_styling(bootstrap_options = c("striped", "hover"))```
Dashboard Interaktif: https://monayolaa.shinyapps.io/Dashboard_Kusta_Jabar/
Dashboard menampilkan: - Peta interaktif distribusi kusta - Filter wilayah dan variabel - Tabel data lengkap
Video YouTube: https://www.youtube.com/watch?v=-NY1rpUifp8
Durasi: 14 menit Isi: Ringkasan permasalahan, metode, temuan utama, demonstrasi dashboard
Acknowledgement:
Penulis menggunakan ChatGPT (Anthropic Claude) sebagai writing assistant
untuk: (1) optimalisasi struktur kalimat akademis, (2) debugging syntax
R pada fungsi spatial analysis, dan (3) konsistensi format tabel
menggunakan kableExtra package. Metodologi penelitian, pemilihan model
regresi, interpretasi uji statistik, dan analisis epidemiologis
dilakukan secara mandiri dengan verifikasi terhadap literatur
primer.