Rencana Pembelajaran Semester
Memuat CPL, CPMK, Sub-CPMK, bahan kajian, strategi pembelajaran, rencana 16 pertemuan, asesmen, rubrik, serta integrasi capstone project.
MAGISTER INOVASI REGIONAL · SEKOLAH PASCASARJANA · UNIVERSITAS PADJADJARAN
Sains Data untuk Inovasi Regional
E-Book Pendamping Mata Kuliah Statistics for Data Science
Outcome-Based Education · Case-Based Learning · Project-Based Learning · Responsible Generative AI
Memuat CPL, CPMK, Sub-CPMK, bahan kajian, strategi pembelajaran, rencana 16 pertemuan, asesmen, rubrik, serta integrasi capstone project.
Memuat tata tertib pembelajaran, sistem penilaian, ketentuan tugas dan project, academic integrity, penggunaan Generative AI, serta hak dan kewajiban mahasiswa.
Kata Pengantar
E-book ini disusun sebagai pendamping Statistics for Data Science / Sains Data untuk Inovasi Regional pada Program Magister Inovasi Regional, Sekolah Pascasarjana, Universitas Padjadjaran. Struktur isi mengikuti Rencana Pembelajaran Semester (RPS): problem framing → data dan provenance → wrangling → EDA dan visualisasi → inferensi/regresi → predictive modeling → machine learning/classification → clustering/PCA → analisis spasial → evaluasi model → policy/dashboard → final synthesis dan reproducibility.
Orientasi jenjang magister adalah kemampuan menganalisis, mengevaluasi, mensintesis, dan mempertahankan keputusan analitik, bukan sekadar menjalankan perangkat lunak. R digunakan sebagai computational laboratory untuk menghasilkan analisis yang dapat direproduksi. Generative AI dapat digunakan secara terbatas sebagai co-pilot, dengan kewajiban verifikasi, dokumentasi, transparansi, dan integritas akademik.
| Pertemuan | Sub-CPMK | Fokus RPS | Asesmen |
|---|---|---|---|
| 1 | S1 | Sains data dan problem framing untuk inovasi regional | Diagnostik; partisipasi berjalan |
| 2 | S2 | Ekosistem data, open data, provenance, metadata, etika | Kuis 1 (2,5%) + Project M1 (3%) |
| 3 | S3 | Data wrangling, data quality, feature construction | Tugas 1 (5%) |
| 4 | S4 | EDA dan statistika deskriptif regional | Project M2 (4%) |
| 5 | S4 | Visualisasi data dan data storytelling | Kuis 2 (2,5%) |
| 6 | S5 | Statistika inferensial dan regresi | Project M3 (5%) |
| 7 | S6 | Predictive modeling, resampling, data leakage | Partisipasi Checkpoint I (5%) |
| 8 | S1–S6 | UTS — integrated regional data case | UTS (20%) |
| 9 | S7 | Machine learning untuk data regional | Kuis 3 (2,5%) |
| 10 | S7 | Classification dan keputusan berbasis risiko | Project M4 (5%) |
| 11 | S8 | Clustering dan segmentasi wilayah | Partisipasi berjalan |
| 12 | S8 | Dimension reduction / PCA | Tugas 2 (5%) |
| 13 | S9 | Analisis data spasial dan visualisasi geospasial | Kuis 4 (2,5%) + Project M5 (4%) |
| 14 | S10 | Evaluasi model, uncertainty, robustness, fairness | Partisipasi berjalan |
| 15 | S11 | Policy insight, dashboard, responsible Generative AI | Project M6 (4%) + Partisipasi Checkpoint II (5%) |
| 16 | S12 | Final synthesis, reproducibility, presentation, defense | Project M7 (5%) + UAS (20%) |
| Komponen | Bobot | Implementasi sesuai RPS |
|---|---|---|
| Project | 30% | Tujuh milestone capstone berbasis masalah dan data regional nyata |
| Partisipasi | 10% | Case discussion, lab, peer review, dan project studio; dicatat pada dua checkpoint |
| Kuis | 10% | Empat kuis formatif (2?),5% |
| Tugas | 10% | Dua tugas individual (5?)%: Data Audit/Wrangling dan Model/Interpretation Note |
| UTS | 20% | Individual integrated regional data case |
| UAS | 20% | Individual capstone defense/synthesis |
| Total | 100% |
| Milestone | Minggu | Fokus | Deliverable minimum | Bobot |
|---|---|---|---|---|
| M1 | 2 | Problem Framing & Project Charter | Problem tree, stakeholder, decision/analytical question, outcome, unit, waktu/ruang, kandidat data, risiko etis, dan provenance awal | 3% |
| M2 | 4 | Data Dossier | Raw-source register, data dictionary, provenance card, cleaning log, analytic sample, missingness/quality audit, dan EDA awal | 4% |
| M3 | 6 | EDA & Evidence Story | Rmd/notebook dengan EDA, visualisasi utama, disparitas/tren, baseline inferensial/regresi, hypotheses, limitations, dan 3–5 evidence statements | 5% |
| M4 | 10 | Baseline + Predictive/Classification Model | Train/test/resampling workflow, baseline, model kandidat, metric, threshold bila classification, dan interpretasi awal | 5% |
| M5 | 13 | Regional Heterogeneity Module | Clustering, PCA, dan/atau spatial mapping/analysis sesuai pertanyaan; justifikasi, sensitivity, dan substantive typology | 4% |
| M6 | 15 | Policy & Dashboard Beta | Policy options, trade-off, KPI monitoring, model card, dashboard/prototype, dan AI-use log sementara | 4% |
| M7 | 16 | Final Reproducible Package | Rmd/report, code, data instructions, figures/tables, dashboard bila relevan, executive policy brief, AI declaration, dan final presentation | 5% |
| Total Project | 30% |
Urutan minimum pada setiap analisis adalah pemeriksaan data → statistik deskriptif/EDA → visualisasi → estimasi/model → diagnostik/evaluasi → interpretasi regional → implikasi keputusan. Untuk metode non-prediktif, evaluasi dapat berupa quality check, sensitivity analysis, atau pemeriksaan asumsi yang relevan.
Setiap bab mengikuti satu pertemuan pada RPS. Bagian Latihan dan Latihan Formatif digunakan untuk penguatan konsep dan tidak menambah bobot penilaian. Bagian yang memiliki bobot hanya yang secara eksplisit diberi label sesuai tabel asesmen di atas.
Setiap analisis minimal mencatat: sumber data dan tanggal akses, unit observasi, kode pembersihan, aturan missing/outlier, skema training-test atau resampling bila prediktif, seed untuk proses acak, package/dependency, serta deklarasi penggunaan Generative AI.
Contoh dapat menggunakan BPS, Open Data Jawa Barat, data.go.id, World Bank INDO-DAPOER, WHO/UNData, atau sumber resmi lain yang relevan. Dataset historis tidak boleh dipresentasikan sebagai kondisi terkini tanpa verifikasi periode dan definisi indikator.
Sains data untuk inovasi regional dimulai bukan dari algoritma, melainkan dari masalah keputusan. Ketimpangan antarwilayah, kemiskinan, akses layanan, produktivitas UMKM, mobilitas, kualitas lingkungan, dan daya inovasi memiliki mekanisme berbeda. Data science membantu menyatukan data administratif, survei, geospasial, sensor, dan sumber digital menjadi bukti yang dapat diuji. Pada jenjang magister, mahasiswa perlu bergerak dari pertanyaan “metode apa yang bisa digunakan?” ke pertanyaan “bukti apa yang dibutuhkan untuk keputusan ini, dengan asumsi dan keterbatasan apa?”. (Provost dan Fawcett 2013)
Setelah bab ini, mahasiswa mampu: membedakan analisis deskriptif, diagnostik, prediktif, dan preskriptif; merumuskan masalah regional menjadi pertanyaan analitik; menentukan unit analisis; mengidentifikasi stakeholder; dan merancang minimum viable analysis untuk capstone.
Sains data adalah praktik interdisipliner yang menggabungkan pemahaman substantif, statistika, komputasi, dan komunikasi untuk mengekstraksi informasi yang dapat digunakan dari data. Dalam konteks regional, “wilayah” bukan hanya label administratif; wilayah dapat memuat kedekatan spasial, jaringan ekonomi, arus komuter, struktur demografi, dan kapasitas kelembagaan. Karena itu, dua kabupaten dengan indikator rata-rata serupa belum tentu memiliki kebutuhan kebijakan yang sama.
Empat mode analitik yang penting adalah: deskriptif (apa yang terjadi?), diagnostik (pola apa yang menyertainya?), prediktif (apa yang mungkin terjadi pada observasi baru?), dan preskriptif (alternatif tindakan apa yang layak dipertimbangkan?). Analisis prediktif yang akurat tidak otomatis menghasilkan kesimpulan kausal. Korelasi antara internet dan kemiskinan, misalnya, belum membuktikan bahwa peningkatan internet menyebabkan penurunan kemiskinan.
Secara sederhana, data dapat ditulis sebagai matriks
di mana adalah jumlah unit observasi (misalnya kabupaten-tahun), jumlah variabel, dan nilai variabel ke- pada observasi ke-. Outcome yang ingin dijelaskan/prediksi ditulis . Sebuah model prediktif mencari fungsi
dengan vektor fitur wilayah ke- dan prediksi. Kualitas model tidak hanya ditentukan oleh kedekatan terhadap , tetapi juga relevansi fitur, kualitas data, stabilitas, fairness, serta kegunaan keputusan.
Dalam pembelajaran tingkat magister, algoritma dapat dipandang sebagai prosedur untuk memilih fungsi dari suatu kelas fungsi . Jika adalah fungsi kerugian (loss function), risiko populasi didefinisikan sebagai
Distribusi populasi tidak diketahui, sehingga pada data pelatihan kita menggunakan empirical risk
Untuk outcome kontinu, pilihan yang umum adalah squared-error loss
sedangkan untuk keputusan klasifikasi biner dapat digunakan 0–1 loss
Namun biaya kebijakan sering tidak simetris. Misalkan adalah biaya false negative (wilayah membutuhkan intervensi tetapi tidak diprioritaskan) dan biaya false positive. Kerugian keputusan dapat ditulis
Konsekuensinya penting: threshold terbaik secara kebijakan tidak harus 0,5. Nilai threshold harus mempertimbangkan biaya, kapasitas intervensi, serta konsekuensi salah klasifikasi. (James dkk. 2021; Hastie, Tibshirani, dan Friedman 2009)
Banyak persoalan regional menggunakan beberapa indikator. Jika indikator memiliki unit yang berbeda, dua transformasi umum adalah min–max scaling
dan z-score standardization
Indeks komposit berbobot dapat ditulis
Jika indikator “lebih tinggi = lebih buruk”, sedangkan indikator lain “lebih tinggi = lebih baik”, arah harus diseragamkan sebelum agregasi. Untuk skala 0–1, pembalikan sederhana adalah . Pilihan bobot adalah bagian dari desain kebijakan dan harus diuji dengan sensitivity analysis. OECD/JRC menekankan pentingnya kerangka teori, seleksi indikator, normalisasi, pembobotan, agregasi, serta analisis ketidakpastian pada indeks komposit. (OECD dan Joint Research Centre, European Commission 2008)
| Simbol | Makna |
|---|---|
| jumlah unit observasi | |
| jumlah fitur/variabel prediktor | |
| matriks fitur | |
| vektor fitur observasi/wilayah ke- | |
| outcome aktual | |
| outcome prediksi | |
| fungsi/model prediksi | |
| fungsi kerugian | |
| risiko populasi | |
| empirical risk | |
| bobot indikator ke- |
Bayangkan pemerintah daerah harus menentukan 20 kecamatan prioritas. “Memilih model” baru relevan setelah definisi prioritas disepakati: apakah berdasarkan tingkat kemiskinan, tren memburuk, kerentanan guncangan, kekurangan layanan, atau kombinasi beberapa indikator? Sains data yang baik membuat definisi tersebut eksplisit sehingga hasil dapat diaudit.
Misalkan Bappeda memiliki tiga kabupaten hipotetis A, B, dan C. Outcome yang ingin diprioritaskan adalah multiple deprivation. Tiga indikator setelah orientasi “lebih tinggi = lebih buruk” adalah kemiskinan , kekurangan internet , dan kekurangan akses kesehatan . Setelah min–max scaling diperoleh:
| Wilayah | |||
|---|---|---|---|
| A | 0.90 | 0.70 | 0.40 |
| B | 0.55 | 0.85 | 0.80 |
| C | 0.35 | 0.30 | 0.90 |
Dengan bobot ,
Ranking awal adalah A–B–C. Tetapi bila stakeholder menyatakan akses layanan dasar lebih kritis dan bobot menjadi , maka Ranking berubah menjadi B–A–C. Pelajaran: ranking bukan fakta alam; ia merupakan konsekuensi data, definisi indikator, transformasi, dan preferensi bobot. Maka laporan harus memisahkan hasil empiris dari pilihan normatif. (OECD dan Joint Research Centre, European Commission 2008)
Sebelum membuka R, isi enam kotak berikut.
| Pertanyaan | Contoh jawaban |
|---|---|
| Siapa pengambil keputusan? | Bappeda provinsi + dinas terkait |
| Keputusan apa? | memilih 10 kabupaten untuk diagnostic review lanjutan |
| Unit analisis? | kabupaten–tahun |
| Outcome? | indeks kerentanan atau TPT tahun berikutnya |
| Horizon? | alokasi program tahun anggaran berikut |
| Kesalahan paling mahal? | tidak memasukkan wilayah benar-benar rentan |
Bila jawaban “keputusan apa?” masih berupa “mengetahui kondisi”, project belum cukup tajam. Ubah menjadi keputusan yang dapat ditindaklanjuti: prioritas, alokasi, screening, evaluasi, pemantauan, atau desain inovasi.
Anggap 100 wilayah: 20 benar-benar prioritas. Model A menghasilkan FN=2 dan FP=20; model B FN=7 dan FP=5. Jika dan : Walau model B mempunyai lebih sedikit false positive, model A lebih baik menurut cost policy yang ditetapkan. Jika cost berubah, pilihan dapat berubah. Karena itu pemilihan metric dan threshold harus mengikuti konsekuensi keputusan, bukan kebiasaan default software.
set.seed(260811)
idx <- tibble::tribble(
~wilayah, ~kemiskinan, ~internet, ~akses,
"A", 19, 45, 60,
"B", 14, 35, 45,
"C", 10, 70, 40
) |>
mutate(
kemiskinan_mm = (kemiskinan-min(kemiskinan))/(max(kemiskinan)-min(kemiskinan)),
kurang_internet = 1-(internet-min(internet))/(max(internet)-min(internet)),
kurang_akses = 1-(akses-min(akses))/(max(akses)-min(akses)),
score_s1 = .50*kemiskinan_mm + .30*kurang_internet + .20*kurang_akses,
score_s2 = .35*kemiskinan_mm + .25*kurang_internet + .40*kurang_akses
)
knitr::kable(idx, digits = 3, caption = "Sensitivity of regional priority scores")| wilayah | kemiskinan | internet | akses | kemiskinan_mm | kurang_internet | kurang_akses | score_s1 | score_s2 |
|---|---|---|---|---|---|---|---|---|
| A | 19 | 45 | 60 | 1.000 | 0.714 | 0.00 | 0.714 | 0.529 |
| B | 14 | 35 | 45 | 0.444 | 1.000 | 0.75 | 0.672 | 0.706 |
| C | 10 | 70 | 40 | 0.000 | 0.000 | 1.00 | 0.200 | 0.400 |
Perhatikan bahwa kode menyimpan indikator asli dan indikator tertransformasi. Jangan menimpa kolom mentah karena audit trail akan hilang.
set.seed(260801)
contoh_wilayah <- tibble(
wilayah = paste0("W", 1:12),
kemiskinan = runif(12, 4, 20),
internet = runif(12, 35, 95),
akses_layanan = runif(12, 40, 90)
) |>
mutate(skor_prioritas = 0.6*kemiskinan + 0.25*(100-internet) + 0.15*(100-akses_layanan)) |>
arrange(desc(skor_prioritas))
knitr::kable(contoh_wilayah, digits = 2, caption = "Contoh pembentukan skor prioritas wilayah (simulasi)")| wilayah | kemiskinan | internet | akses_layanan | skor_prioritas |
|---|---|---|---|---|
| W6 | 19.53 | 44.94 | 70.63 | 29.89 |
| W5 | 17.09 | 55.12 | 49.86 | 28.99 |
| W12 | 14.64 | 43.64 | 70.98 | 27.23 |
| W3 | 10.65 | 48.82 | 52.30 | 26.34 |
| W1 | 4.49 | 36.43 | 59.87 | 24.61 |
| W8 | 15.68 | 57.89 | 69.55 | 24.50 |
| W4 | 4.01 | 40.70 | 66.96 | 22.18 |
| W2 | 16.44 | 90.05 | 56.19 | 18.92 |
| W10 | 11.79 | 90.01 | 44.67 | 17.87 |
| W7 | 6.21 | 54.16 | 83.45 | 17.67 |
| W11 | 9.46 | 91.96 | 41.85 | 16.41 |
| W9 | 5.16 | 79.46 | 84.76 | 10.52 |
contoh_wilayah |>
dplyr::slice_head(n = 8) |>
ggplot2::ggplot(ggplot2::aes(x = reorder(wilayah, skor_prioritas), y = skor_prioritas)) +
ggplot2::geom_col(fill = "#145B8C") +
ggplot2::coord_flip() +
ggplot2::labs(
title = "Skor prioritas delapan wilayah teratas — data simulasi",
subtitle = "Skor merupakan alat screening; bobot tetap harus diuji sensitivitasnya",
x = NULL, y = "Skor prioritas"
)Contoh ini menunjukkan bahwa definisi indeks adalah keputusan normatif-analitik. Bobot 0,60; 0,25; dan 0,15 bukan “ditemukan” oleh R. Bobot harus dibenarkan dengan teori, proses kebijakan, atau analisis sensitivitas.
INDO-DAPOER menyediakan indikator provinsi dan kabupaten/kota Indonesia dalam kelompok fiskal, ekonomi, sosial-demografi, dan infrastruktur, dengan cakupan historis 1976-2018. Unit observasi praktisnya adalah wilayah-tahun-indikator. Sumber aslinya antara lain BPS dan kementerian/lembaga Indonesia. Lisensinya CC BY 4.0. Kelebihannya adalah keluasan indikator dan format panel; keterbatasan utamanya adalah data tidak mutakhir dan konsistensi definisi perlu diperiksa antarperiode. (World Bank 2026)
Kartu dataset real.
SI.POV.NAPR.ZS = poverty rate (% penduduk), IDX.HDI = Human Development Index, SP.POP.TOTL = total population.# Jika INDO-DAPOER sudah diunduh, gunakan data resmi; bila belum, tampilkan
# struktur indikator dari data simulasi agar e-book tetap dapat diknit offline.
if (dir.exists("data/raw/indodapoer") && length(list.files("data/raw/indodapoer")) > 0) {
source("R/03_prepare_indodapoer.R")
indo <- load_indodapoer()
out <- indo |>
dplyr::distinct(kode_indikator, indikator) |>
dplyr::filter(stringr::str_detect(indikator, stringr::regex("poverty|unemploy|development|GDP", ignore_case = TRUE))) |>
dplyr::arrange(indikator) |>
head(15)
} else {
out <- tibble::tribble(
~kode_indikator, ~indikator,
"SIM.POV", "Kemiskinan (%) — simulasi",
"SIM.TPT", "Tingkat pengangguran terbuka (%) — simulasi",
"SIM.HDI", "Indeks pembangunan manusia — simulasi",
"SIM.GDPPC", "PDRB per kapita (juta) — simulasi"
)
}
knitr::kable(out, caption = "Output: daftar indikator yang relevan dengan problem framing")| kode_indikator | indikator |
|---|---|
| SIM.POV | Kemiskinan (%) — simulasi |
| SIM.TPT | Tingkat pengangguran terbuka (%) — simulasi |
| SIM.HDI | Indeks pembangunan manusia — simulasi |
| SIM.GDPPC | PDRB per kapita (juta) — simulasi |
Langkah pertama bukan langsung memodelkan, tetapi membaca metadata dan mengecek apakah indikator benar-benar merepresentasikan konsep yang sedang dibahas.
Jika suatu wilayah memiliki kemiskinan tinggi tetapi akses internet dan layanan dasar juga rendah, masalahnya dapat mengarah pada multiple deprivation. Sebaliknya, pengangguran tinggi di kota dengan PDRB tinggi dapat menunjukkan mismatch tenaga kerja, struktur industri, atau tekanan urbanisasi. Rekomendasi kebijakan harus mengikuti pola substantif ini, bukan sekadar ranking algoritmik.
simulasi_panel_regional.csv untuk memilih lima wilayah yang tampak paling tertinggal pada 2025 berdasarkan minimal tiga indikator.Studio problem framing (formatif menuju M1). Pilih satu dari sepuluh contoh capstone atau usulkan tema lain. Buat 1 halaman yang memuat: masalah publik; stakeholder; decision question; unit analisis; outcome; minimal 5 kandidat indikator; horizon waktu; risiko salah keputusan; serta satu kalimat yang menjelaskan mengapa analisis tersebut bukan sekadar membuat dashboard.
Rubrik (100): problem significance 20; analytical question 20; unit/outcome clarity 15; data plausibility 15; decision relevance 20; caveat/ethics 10.
Milestone awal: pilih satu masalah regional, tentukan stakeholder, unit analisis, outcome/indikator utama, dan keputusan yang hendak didukung. Hasilnya berupa one-page problem brief.
Sains data regional adalah disiplin pengambilan keputusan berbasis bukti. Algoritma penting, tetapi kualitas formulasi masalah, definisi indikator, data provenance, dan interpretasi kebijakan menentukan apakah analisis benar-benar berguna.
Analisis regional sering gagal bukan karena model, melainkan karena data berasal dari sistem yang berbeda: kode wilayah berubah, definisi indikator tidak identik, periode pencatatan tidak sinkron, dan angka proyeksi diperlakukan seperti hasil observasi. Bab ini menempatkan provenance dan metadata sebagai bagian dari metode ilmiah, bukan urusan administratif.
Mahasiswa mampu memetakan ekosistem data regional, mengevaluasi kualitas sumber, membuat data inventory, membedakan data primer/sekunder/administratif/open data, dan menyusun dokumentasi dataset (datasheet).
Data provenance adalah jejak asal-usul data: siapa produsen data, bagaimana data dikumpulkan, kapan diperbarui, transformasi apa yang dilakukan, dan lisensi apa yang berlaku. Datasheets for datasets membantu mendokumentasikan motivasi, komposisi, proses pengumpulan, preprocessing, penggunaan yang direkomendasikan, serta keterbatasan. (Gebru dkk. 2021)
Dalam analisis regional, cek minimal: unit geografis, kode wilayah, frekuensi waktu, definisi denominator, perubahan metodologi, status angka sementara/final, missingness, dan revision policy. “Jumlah penduduk miskin” tidak sama dengan “persentase penduduk miskin”; perbandingan antarkabupaten membutuhkan denominator.
Untuk indikator berbasis rasio,
di mana adalah pembilang, denominator, dan konstanta skala (misalnya 100 untuk persen atau 1.000 untuk per seribu). Membandingkan tanpa mempertimbangkan dapat menimbulkan size bias.
Missingness dapat diringkas sebagai
dengan fungsi indikator. Nilai adalah proporsi missing untuk variabel .
Mahasiswa harus membedakan tipe indikator karena operasi matematis yang sah berbeda. Count adalah jumlah kejadian/unit, rate menghubungkan kejadian dengan populasi berisiko dan periode waktu, proportion adalah bagian dari keseluruhan, sedangkan index biasanya merupakan transformasi beberapa komponen.
Proporsi:
Rate per penduduk:
Perubahan absolut dan relatif:
Jika interval lebih dari satu tahun, compound annual growth rate (CAGR) adalah
Stock diukur pada titik waktu (misalnya jumlah penduduk pada pertengahan tahun), sedangkan flow diakumulasi selama periode (misalnya investasi selama tahun). Menjumlahkan atau membagi stock dan flow tanpa memperhatikan waktu dapat menghasilkan indikator yang menyesatkan.
Untuk variabel , completeness dapat diringkas sebagai
Jika kunci yang diharapkan unik adalah kombinasi wilayah–tahun, tingkat duplikasi dapat ditulis
Ketika dua sumber digabungkan dengan kunci , match rate adalah
Nilai bukan sekadar masalah teknis. Penyebabnya dapat berupa perubahan kode wilayah, pemekaran, perbedaan kapitalisasi nama, atau cakupan unit yang tidak sama. Join harus didiagnosis sebelum baris tak cocok dihapus.
Gunakan bila teramati dan bila hilang. Secara konseptual:
Klasifikasi ini penting karena complete-case analysis dapat bias ketika missing terkait dengan karakteristik wilayah. Wilayah dengan kapasitas pelaporan rendah, misalnya, mungkin memiliki missingness lebih tinggi. (Little dan Rubin 2019)
Imputasi mean sederhana mempertahankan rata-rata tetapi cenderung mengecilkan varians dan merusak hubungan antarvariabel. Untuk analisis serius, pertimbangkan multiple imputation atau model yang secara eksplisit menangani missingness, disertai sensitivity analysis. (Little dan Rubin 2019)
Jika batas wilayah berubah, indikator historis mungkin harus dikonversi ke constant geography. Secara abstrak, jika adalah nilai pada unit lama dan matriks alokasi dari unit lama ke unit baru, maka
Elemen menyatakan proporsi unit lama yang dialokasikan ke unit baru . Untuk count, bobot dapat berbasis populasi/area sesuai konsep; untuk rate, jangan langsung mengalikan tanpa merekonstruksi numerator dan denominator jika memungkinkan.
Untuk setiap dataset, simpan minimal tuple
Prinsip ini konsisten dengan datasheets for datasets: dokumentasi harus menjelaskan motivasi, komposisi, proses pengumpulan, preprocessing, penggunaan yang direkomendasikan, dan keterbatasan. (Gebru dkk. 2021)
Data berkualitas tidak selalu berarti “tanpa missing”. Yang lebih penting adalah mengetahui mengapa missing terjadi. Wilayah terpencil mungkin lebih sering tidak melaporkan data; jika demikian, menghapus baris missing dapat secara sistematis menghilangkan wilayah yang justru paling membutuhkan kebijakan.
Dua wilayah melaporkan 5.000 dan 3.000 penganggur. Tanpa denominator, wilayah pertama tampak lebih buruk. Jika angkatan kerja masing-masing 100.000 dan 40.000: Maka cerita berubah. Untuk kebijakan tenaga kerja, count berguna untuk memperkirakan volume layanan; rate berguna untuk membandingkan tingkat masalah. Keduanya dapat diperlukan, tetapi menjawab pertanyaan berbeda.
Misalkan rate tiga kabupaten adalah 4%, 8%, 12% dengan angkatan kerja 1 juta, 100 ribu, dan 50 ribu. Mean sederhana adalah 8%. Weighted rate: Perbedaan besar terjadi karena ukuran denominator tidak sama. Agregasi rate tingkat provinsi sebaiknya direkonstruksi dari numerator/denominator yang sesuai jika tersedia, bukan selalu mean kabupaten.
Bayangkan missing rate pelaporan fasilitas kesehatan adalah 5% di perkotaan dan 35% di daerah terpencil. Jika seluruh baris missing dihapus, dataset analitik menjadi lebih “urban” daripada populasi target. Untuk mendiagnosis, modelkan indikator missing: Tujuannya bukan selalu mengestimasi mekanisme missing secara formal, tetapi melihat apakah missingness berpola. (Little dan Rubin 2019)
provenance <- tibble::tribble(
~dataset, ~producer, ~period, ~unit, ~status, ~access_date,
"TPT", "BPS / Open Data Jabar", "2007-2024", "kab/kota-tahun", "published", "2026-08-07",
"UMKM", "Dinas KUK / Open Data Jabar", "2016-2023", "kab/kota-tahun", "projection", "2026-08-07",
"INDO-DAPOER", "World Bank", "1976-2018", "subnational-year", "historical", "2026-08-07"
)
knitr::kable(provenance, caption = "Contoh minimum provenance register")| dataset | producer | period | unit | status | access_date |
|---|---|---|---|---|---|
| TPT | BPS / Open Data Jabar | 2007-2024 | kab/kota-tahun | published | 2026-08-07 |
| UMKM | Dinas KUK / Open Data Jabar | 2016-2023 | kab/kota-tahun | projection | 2026-08-07 |
| INDO-DAPOER | World Bank | 1976-2018 | subnational-year | historical | 2026-08-07 |
Sebelum data dimodelkan, jawab ya/tidak:
Jika beberapa jawaban “tidak”, masalah tersebut harus masuk limitation dan dapat mengubah metode. Sumber data yang kredibel tidak berarti setiap field otomatis siap dipakai.
set.seed(260802)
dq <- tibble(
wilayah = sprintf("W%02d", 1:40),
populasi = round(runif(40, 100000, 3000000)),
kasus = rpois(40, lambda = 200),
akses_data = runif(40)
) |>
mutate(
kasus = if_else(akses_data < .12, NA_integer_, kasus),
rate_per_100k = kasus/populasi*100000
)
dq |>
summarise(n = n(), missing_kasus = mean(is.na(kasus)), median_rate = median(rate_per_100k, na.rm = TRUE)) |>
knitr::kable(digits = 3, caption = "Audit kualitas data sederhana")| n | missing_kasus | median_rate |
|---|---|---|
| 40 | 0.125 | 12.573 |
tibble::tibble(
status = ifelse(is.na(dq$kasus), "Missing", "Tersedia")
) |>
dplyr::count(status) |>
ggplot2::ggplot(ggplot2::aes(status, n, fill = status)) +
ggplot2::geom_col(show.legend = FALSE) +
ggplot2::scale_fill_manual(values = c("Missing" = "#C99A17", "Tersedia" = "#145B8C")) +
ggplot2::labs(title = "Ketersediaan data kasus — simulasi", x = NULL, y = "Jumlah observasi")Open Data Jawa Barat menyediakan dataset mentah dari perangkat daerah dan BPS, dengan pilihan CSV/Excel/API. Contoh yang relevan adalah TPT kabupaten/kota 2007-2024, jumlah penduduk miskin 2002-2025, dan proyeksi UMKM 2016-2023. Perhatikan bahwa dataset UMKM secara eksplisit berstatus proyeksi, sehingga tidak boleh ditafsirkan identik dengan sensus usaha aktual. (Pemerintah Provinsi Jawa Barat 2026)
Kartu dataset real.
tingkat_pengangguran_terbuka = persen TPT; jumlah_penduduk_miskin = ribu jiwa; proyeksi_jumlah_umkm = proyeksi jumlah unit UMKM; satuan; tahun.katalog <- read_csv("data/katalog_data_real.csv", show_col_types = FALSE)
knitr::kable(katalog[, c("dataset","sumber","cakupan_tahun","unit_observasi")],
caption = "Katalog sumber data nyata untuk mata kuliah")| dataset | sumber | cakupan_tahun | unit_observasi |
|---|---|---|---|
| Tingkat Pengangguran Terbuka berdasarkan Kabupaten/Kota di Jawa Barat | Open Data Jawa Barat / BPS | 2007-2024 | Kabupaten/kota-tahun |
| Jumlah Penduduk Miskin berdasarkan Kabupaten/Kota di Jawa Barat | Open Data Jawa Barat / BPS | 2002-2025 | Kabupaten/kota-tahun |
| Proyeksi Jumlah UMKM berdasarkan Kabupaten/Kota di Jawa Barat | Open Data Jawa Barat / Dinas Koperasi dan Usaha Kecil | 2016-2023 | Kabupaten/kota-tahun |
| Jumlah Penduduk berdasarkan Kabupaten/Kota di Jawa Barat | Open Data Jawa Barat / BPS | 2010-2025 | Kabupaten/kota-tahun |
| Indonesia Database for Policy and Economic Research (INDO-DAPOER) | World Bank Data Catalog; sumber indikator terutama BPS dan kementerian/lembaga Indonesia | 1976-2018 | Provinsi/kabupaten/kota-tahun-indikator |
| World Bank Official Boundaries | World Bank Data Catalog | diperbarui berkala | Geometri admin 0/1/2 |
if (dir.exists("data/raw/indodapoer") && length(list.files("data/raw/indodapoer")) > 0) {
source("R/03_prepare_indodapoer.R")
indo <- load_indodapoer()
quality <- indo |>
dplyr::group_by(kode_indikator, indikator) |>
dplyr::summarise(
prop_missing = mean(is.na(nilai)),
tahun_min = min(tahun[!is.na(nilai)], na.rm = TRUE),
tahun_max = max(tahun[!is.na(nilai)], na.rm = TRUE),
.groups = "drop"
) |>
dplyr::arrange(prop_missing) |>
head(20)
} else {
demo <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE)
quality <- tibble::tibble(
variabel = names(demo),
prop_missing = purrr::map_dbl(demo, ~mean(is.na(.x))),
kelas = purrr::map_chr(demo, ~class(.x)[1])
)
}
knitr::kable(quality, digits = 3, caption = "Output: audit kelengkapan dan struktur data")| variabel | prop_missing | kelas |
|---|---|---|
| wilayah | 0 | character |
| tahun | 0 | numeric |
| urban | 0 | numeric |
| longitude | 0 | numeric |
| latitude | 0 | numeric |
| pdrb_perkapita_juta | 0 | numeric |
| kemiskinan_persen | 0 | numeric |
| tpt_persen | 0 | numeric |
| ipm | 0 | numeric |
| internet_persen | 0 | numeric |
| umkm_per_1000 | 0 | numeric |
| indeks_pendidikan | 0 | numeric |
| akses_kesehatan | 0 | numeric |
| indeks_inovasi | 0 | numeric |
Audit metadata dapat mengubah keputusan analitik. Jika data pengangguran tersedia tahunan tetapi indikator inovasi hanya tersedia pada tahun tertentu, memaksakan model panel tahunan dapat menghasilkan banyak imputasi dan asumsi. Pilihan yang lebih defensible mungkin mengubah unit waktu atau membatasi pertanyaan pada cross-section tertentu.
Lengkapi project charter dan buat data dossier awal untuk tiga sumber data calon capstone. Setiap sumber harus memuat producer, URL, access date, periode, unit observasi, definisi variabel, status angka (final/sementara/proyeksi), lisensi, update frequency, missingness yang terlihat, dan risiko integrasi. Pilih satu sumber yang tidak jadi digunakan dan jelaskan alasan penolakannya.
Project M1 diselesaikan pada pertemuan ini. Mahasiswa menautkan problem framing dengan sumber data yang dapat diaudit, lalu menyiapkan provenance awal sebagai dasar M2 Data Dossier.
Model yang canggih tidak dapat memperbaiki provenance yang tidak jelas. Metadata, denominator, definisi indikator, dan perubahan metodologi adalah bagian inti dari validitas analisis regional.
Data kebijakan hampir selalu memerlukan penataan: nama wilayah tidak konsisten, angka tersimpan sebagai teks, struktur wide/long bercampur, dan indikator harus dinormalisasi. Bab ini memperlakukan data wrangling sebagai proses analitik yang terdokumentasi.
Mahasiswa mampu melakukan import, tipe data, reshape, join, deduplikasi, penanganan missing, deteksi outlier, serta konstruksi indikator yang sesuai unit dan denominator.
Data tidy memiliki satu variabel per kolom, satu observasi per baris, dan satu jenis unit observasi per tabel. (Wickham, Çetinkaya-Rundel, dan Grolemund 2023) Kunci join harus mencerminkan identitas observasi; untuk panel kabupaten/kota biasanya kombinasi kode_wilayah + tahun, bukan hanya nama wilayah.
Feature construction harus mempunyai makna substantif. UMKM per 1.000 penduduk sering lebih dapat dibandingkan antardaerah daripada jumlah UMKM mentah. Transformasi log dapat mengurangi skewness pada nilai ekonomi yang sangat lebar, tetapi interpretasinya berubah.
Standardisasi z-score:
dengan mean dan simpangan baku variabel . Transformasi log yang sering digunakan:
terutama bila dan distribusi sangat skewed. Penambahan 1 mencegah masalah , tetapi harus dinyatakan secara eksplisit.
Dalam tidy data, setiap variabel berada pada kolom, setiap observasi pada baris, dan setiap jenis unit observasi pada tabel tersendiri. Struktur ini mengurangi ambiguitas saat agregasi dan pemodelan. (Wickham 2014; Wickham, Çetinkaya-Rundel, dan Grolemund 2023)
Jika adalah nilai mentah, transformasi log sering dipakai untuk distribusi sangat menceng: dengan ketika nol mungkin muncul. Perubahan unit harus dinyatakan: koefisien pada skala log tidak identik dengan koefisien skala asli.
Z-score:
Robust z-score berbasis median dan MAD:
di mana
Konstanta 1,4826 membuat MAD mendekati simpangan baku untuk data normal. Robust scaling berguna ketika terdapat outlier yang valid secara substantif—misalnya kota metropolitan memang ekstrem dibanding kabupaten rural—dan kita tidak ingin ekstrem tersebut otomatis dianggap kesalahan.
IQR:
Aturan boxplot menandai observasi potensial di luar
Outlier tidak boleh langsung dihapus. Klasifikasikan: (a) data entry error, (b) definisi unit berbeda, (c) kejadian ekstrem nyata, atau (d) perubahan metodologi. Dalam data regional, ekstrem yang nyata sering justru menjadi objek analisis.
Beberapa fitur yang sering lebih bermakna daripada count mentah:
Per kapita
Density dengan luas wilayah.
Share
Lag temporal
Growth
Difference
Location quotient (LQ) untuk konsentrasi sektor di wilayah : menunjukkan konsentrasi relatif di atas rata-rata wilayah pembanding. Interpretasi bergantung pada definisi variabel—tenaga kerja, output, atau unit usaha.
Jika parameter preprocessing (mean, SD, imputation value, PCA loading) dihitung dari seluruh data sebelum train/test split, informasi test set bocor ke proses training. Secara benar, parameter transformasi harus dihitung hanya dari training:
Framework recipes pada tidymodels membantu menerapkan prinsip ini secara sistematis. (Kuhn dan Silge 2022)
Jika Kabupaten A memiliki 200 ribu UMKM dan Kabupaten B 80 ribu UMKM, belum tentu A lebih “entrepreneurial”. Setelah dibagi populasi usia kerja, ranking dapat berubah. Feature engineering yang baik mengubah data menjadi ukuran yang lebih dekat dengan konsep kebijakan.
Jika UMKM suatu wilayah meningkat dari 10.000 menjadi 11.500 unit, Jika baseline , growth rate tidak terdefinisi. Jangan mengganti denominator nol dengan angka kecil tanpa justifikasi karena dapat menciptakan pertumbuhan ekstrem artifisial. Gunakan perubahan absolut atau definisi alternatif.
Wilayah A memiliki 20.000 pekerja manufaktur dari total 100.000 pekerja; provinsi memiliki 300.000 pekerja manufaktur dari 3.000.000 pekerja. Artinya konsentrasi tenaga kerja manufaktur dua kali share provinsi. Bukan berarti produktivitas dua kali lebih tinggi, dan bukan bukti sektor tersebut “lebih baik”.
Jika tabel A memiliki 27 kabupaten/kota × 10 tahun = 270 key dan tabel B setelah join hanya match 258 key: 12 key yang tidak match harus diperiksa. Contoh R:
a <- tibble(wilayah=c("A","B","C"), tahun=2024, x=1:3)
b <- tibble(wilayah=c("A","B","D"), tahun=2024, y=11:13)
anti_join(a,b,by=c("wilayah","tahun"))#> # A tibble: 1 × 3
#> wilayah tahun x
#> <chr> <dbl> <int>
#> 1 C 2024 3
#> # A tibble: 1 × 3
#> wilayah tahun y
#> <chr> <dbl> <int>
#> 1 D 2024 13
anti_join() sering lebih penting daripada left_join() karena mengungkap observasi yang hilang akibat perbedaan key.
Gunakan kategori keputusan berikut:
| Temuan | Diagnosis | Tindakan |
|---|---|---|
| nilai negatif pada jumlah penduduk | impossible | cek source/parse; jangan imputasi diam-diam |
| PDRB per kapita sangat tinggi | plausible structural extreme | pertahankan; pertimbangkan log/robust scaling |
| TPT 850 | kemungkinan decimal/unit error | cek metadata/satuan |
| lon/lat di luar Indonesia | coordinate error | koreksi dari sumber atau exclude terdocumentasi |
set.seed(260813)
dat <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::filter(tahun == 2025) |>
dplyr::select(kemiskinan_persen, pdrb_perkapita_juta, internet_persen, tpt_persen, ipm)
split <- initial_split(dat, prop = .8, strata = kemiskinan_persen)
train <- training(split); test <- testing(split)
rec <- recipe(kemiskinan_persen ~ ., data = train) |>
step_impute_median(all_numeric_predictors()) |>
step_zv(all_predictors()) |>
step_normalize(all_numeric_predictors())
prep_rec <- prep(rec, training = train)
train_baked <- bake(prep_rec, new_data = NULL)
test_baked <- bake(prep_rec, new_data = test)
knitr::kable(head(train_baked, 6), digits = 3, caption = "Output: data training setelah preprocessing leakage-safe")| pdrb_perkapita_juta | internet_persen | tpt_persen | ipm | kemiskinan_persen |
|---|---|---|---|---|
| -1.476 | -0.628 | -0.719 | -0.328 | 9.992 |
| 0.459 | 0.524 | 1.979 | 0.718 | 6.006 |
| 0.643 | 0.396 | -0.477 | -0.561 | 8.570 |
| -0.070 | 0.398 | 0.303 | 0.000 | 10.076 |
| -0.391 | 0.275 | -0.596 | -0.468 | 11.637 |
| -0.546 | -1.018 | -0.758 | -0.899 | 8.979 |
Mean/median dan SD dipelajari dari training. Inilah alasan workflow modeling sebaiknya menyatukan preprocessing dan model. (Kuhn dan Silge 2022)
Setiap fitur baru harus memiliki: formula; denominator; unit; temporal alignment; rationale; potential leakage; dan interpretasi. Fitur growth_2024 tidak boleh digunakan untuk memprediksi outcome 2023; fitur “jumlah penerima program” dapat menjadi post-treatment variable bila digunakan untuk menjelaskan outcome setelah program.
set.seed(260803)
raw <- tibble(
kab_kota = c("Kab. A", "kab a ", "KOTA B", "Kota C"),
tahun = c("2024", "2024", "2024", "2024"),
penduduk = c("1,200,000", "1,200,000", "850,000", NA),
umkm = c(85000, 85000, 62000, 21000)
)
clean <- raw |>
clean_names() |>
mutate(
kab_kota = str_to_title(str_squish(kab_kota)),
tahun = as.integer(tahun),
penduduk = parse_number(penduduk),
umkm_per_1000 = umkm/penduduk*1000
) |>
distinct(kab_kota, tahun, .keep_all = TRUE)
knitr::kable(clean, digits = 2, caption = "Contoh cleaning dan konstruksi rate")| kab_kota | tahun | penduduk | umkm | umkm_per_1000 |
|---|---|---|---|---|
| Kab. A | 2024 | 1200000 | 85000 | 70.83 |
| Kab A | 2024 | 1200000 | 85000 | 70.83 |
| Kota B | 2024 | 850000 | 62000 | 72.94 |
| Kota C | 2024 | NA | 21000 | NA |
Dataset TPT Open Data Jawa Barat memuat kode provinsi, nama provinsi, kode kabupaten/kota, nama kabupaten/kota, TPT (%), satuan, dan tahun. Kode wilayah sebaiknya dijadikan kunci utama saat menggabungkannya dengan data penduduk atau kemiskinan. Periksa apakah standar kode wilayah konsisten antarversi dataset. (Pemerintah Provinsi Jawa Barat 2026)
Kartu dataset real.
kode_provinsi, nama_provinsi, kode_kabupaten_kota, nama_kabupaten_kota, tingkat_pengangguran_terbuka = persentase TPT, satuan = persen, tahun.panel <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE)
panel_2025 <- panel |>
filter(tahun == 2025) |>
mutate(
pdrb_log = log1p(pdrb_perkapita_juta),
kemiskinan_z = as.numeric(scale(kemiskinan_persen))
)
panel_2025 |>
select(wilayah, pdrb_perkapita_juta, pdrb_log, kemiskinan_persen, kemiskinan_z) |>
head() |>
knitr::kable(digits = 3)| wilayah | pdrb_perkapita_juta | pdrb_log | kemiskinan_persen | kemiskinan_z |
|---|---|---|---|---|
| Wilayah_01 | 31.612 | 3.485 | 9.992 | 0.061 |
| Wilayah_02 | 65.249 | 4.193 | 7.681 | -1.257 |
| Wilayah_03 | 52.521 | 3.980 | 6.006 | -2.212 |
| Wilayah_04 | 54.513 | 4.017 | 8.570 | -0.750 |
| Wilayah_05 | 46.803 | 3.867 | 10.076 | 0.109 |
| Wilayah_06 | 43.338 | 3.792 | 11.637 | 0.999 |
panel_2025 |>
ggplot2::ggplot(ggplot2::aes(pdrb_perkapita_juta, pdrb_log)) +
ggplot2::geom_point(size = 2.2, colour = "#145B8C") +
ggplot2::labs(
title = "Transformasi log pada PDRB per kapita — simulasi",
subtitle = "Transformasi mengompresi nilai besar dan dapat membantu stabilisasi skala",
x = "PDRB per kapita (juta)", y = "log(1 + PDRB per kapita)"
)if (file.exists("data/raw/tpt_jabar.csv") && file.exists("data/raw/penduduk_jabar.csv")) {
tpt <- readr::read_csv("data/raw/tpt_jabar.csv", show_col_types = FALSE) |> janitor::clean_names()
penduduk <- readr::read_csv("data/raw/penduduk_jabar.csv", show_col_types = FALSE) |> janitor::clean_names()
regional <- tpt |>
dplyr::inner_join(penduduk, by = c("kode_kabupaten_kota", "tahun"), suffix = c("_tpt", "_pop"))
out <- head(regional, 8)
} else {
out <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::select(wilayah, tahun, tpt_persen, pdrb_perkapita_juta, kemiskinan_persen) |>
head(8)
}
knitr::kable(out, digits = 2, caption = "Output: hasil integrasi data; gunakan data simulasi bila raw data resmi belum tersedia")| wilayah | tahun | tpt_persen | pdrb_perkapita_juta | kemiskinan_persen |
|---|---|---|---|---|
| Wilayah_01 | 2019 | 7.01 | 17.25 | 17.55 |
| Wilayah_01 | 2020 | 9.29 | 18.82 | 16.01 |
| Wilayah_01 | 2021 | 8.16 | 32.33 | 15.19 |
| Wilayah_01 | 2022 | 7.82 | 29.36 | 15.32 |
| Wilayah_01 | 2023 | 7.89 | 23.84 | 15.52 |
| Wilayah_01 | 2024 | 6.99 | 28.46 | 12.75 |
| Wilayah_01 | 2025 | 7.12 | 31.61 | 9.99 |
| Wilayah_02 | 2019 | 9.07 | 44.30 | 13.41 |
Cleaning adalah bagian dari argumentasi. Menghapus duplikat tanpa memahami penyebabnya dapat menghapus kategori yang sebenarnya berbeda. Mengimputasi missing dengan mean provinsi dapat meratakan disparitas dan membuat wilayah ekstrem tampak “normal”. Setiap keputusan cleaning perlu log perubahan.
simulasi_panel_regional.csv dan tambahkan unit pada nama variabel.Susun audit dan pipeline wrangling pada dataset regional yang berbeda dari capstone. Fokus pada provenance, diagnosis kualitas data, aturan cleaning yang dapat dijustifikasi, joining/reshaping/feature construction, dan reproducibility. Luaran berupa R Markdown/PDF atau notebook yang dapat dijalankan ulang, disertai data dictionary, cleaning log, quality report, dan daftar sumber.
Rubrik sesuai RPS: correctness pipeline 35%; reproducibility 25%; quality diagnosis 25%; documentation/source 15%.
Kuis 10–15 soal campuran konsep dan potongan kode. Kisi-kisi: unit analisis; denominator; provenance; tidy data; missingness; scaling; outlier; feature engineering; leakage preprocessing.
Mahasiswa menyerahkan data cleaning log: input, transformasi, alasan, jumlah baris sebelum/sesudah, dan isu yang belum terselesaikan.
Wrangling bukan kosmetik. Kesalahan unit, denominator, kode wilayah, dan join dapat menghasilkan kesimpulan kebijakan yang salah meskipun model dihitung dengan benar.
EDA adalah proses menguji struktur data sebelum memaksakan model. Untuk data regional, EDA harus melihat distribusi, tren, heterogenitas antardaerah, hubungan antarindikator, missingness, dan kemungkinan struktur spasial/temporal. (Tukey 1977)
Mahasiswa mampu menyusun ringkasan numerik dan grafis, membandingkan distribusi antarwilayah/waktu, mendeteksi pola nonlinier/outlier, dan merumuskan hipotesis analitik dari EDA.
Ukuran pemusatan (mean, median), penyebaran (SD, IQR), quantile, dan korelasi harus dipilih sesuai distribusi dan tujuan. Untuk data skewed, median sering lebih stabil daripada mean. Korelasi Pearson mengukur asosiasi linear, sedangkan Spearman berbasis ranking dan lebih robust terhadap nonnormalitas tertentu.
Mean dan variance sampel:
Korelasi Pearson:
Rata-rata aritmetik:
Rata-rata tertimbang—misalnya rata-rata provinsi dari rate kabupaten dengan bobot populasi yang relevan:
Varians sampel dan simpangan baku:
Coefficient of variation: berguna untuk membandingkan dispersi relatif pada variabel dengan skala berbeda ketika mean positif dan bermakna.
Pearson correlation mengukur hubungan linear, bukan hubungan kausal. Spearman correlation adalah Pearson correlation pada ranks dan lebih sesuai ketika hubungan monotonic tetapi tidak linear atau ketika robust terhadap skala ordinal dibutuhkan.
Untuk nilai non-negatif yang diurutkan , salah satu bentuk koefisien Gini adalah
menunjukkan kesetaraan sempurna; nilai lebih tinggi menunjukkan konsentrasi lebih besar. Pada indikator regional, jelaskan apa yang didistribusikan—pendapatan, PDRB per kapita, kapasitas layanan, atau investasi—karena makna normatifnya berbeda.
Theil index:
Keunggulan Theil adalah dekomposabilitas antar dan dalam kelompok, bermanfaat saat membedakan ketimpangan antarkawasan metropolitan/nonmetropolitan atau antar koridor pembangunan.
Quantile memenuhi secara konseptual . Median adalah . Untuk distribusi menceng, laporkan median dan IQR selain mean dan SD. Perbedaan mean–median sendiri dapat memberi sinyal konsentrasi ekstrem.
EDA bukan “membuat banyak grafik”, tetapi siklus
Tukey menekankan EDA sebagai eksplorasi yang membuka struktur data sebelum pemodelan konfirmatori. (Tukey 1977) Untuk konteks regional, minimal bedakan variasi antarwilayah, antarwaktu, dan interaksi wilayah–waktu.
Untuk indikator , dekomposisi konseptual memisahkan rata-rata umum , efek wilayah , efek waktu , dan residual. Walaupun belum menjadi model panel formal, struktur ini membantu mahasiswa bertanya apakah perbedaan didominasi karakteristik persisten wilayah atau shock waktu bersama.
Dua provinsi dapat memiliki mean kemiskinan sama tetapi distribusi kabupaten sangat berbeda. Salah satu homogen, yang lain memiliki beberapa kantong kemiskinan ekstrem. Kebijakan yang hanya melihat mean provinsi akan kehilangan informasi target.
Pendapatan per kapita hipotetis lima wilayah: 20, 22, 24, 26, 100. Mean: median = 24. Satu wilayah ekstrem menggeser mean jauh dari mayoritas. Tidak ada statistik yang “lebih benar” secara universal: mean relevan untuk total/expectation; median lebih representatif untuk typical region saat skew tinggi.
Jika indikator A=60 dengan populasi 1 juta dan B=80 dengan populasi 100 ribu, mean sederhana 70, tetapi Pertanyaan substantif menentukan bobot: populasi, rumah tangga, angkatan kerja, atau bobot sampling.
Untuk tiga nilai yang sudah diurutkan: Gini sensitif pada keseluruhan distribusi. Jika satu wilayah melonjak menjadi 100, Gini meningkat. Tetapi Gini tidak memberi tahu wilayah mana yang tertinggal; selalu kombinasikan dengan distribusi/ranking/peta.
Theil memberi nol ketika semua . Karena term bertambah untuk nilai yang menyimpang, indeks meningkat dengan ketimpangan. Kelebihan untuk regional analytics adalah dekomposisi: sehingga kita dapat bertanya apakah ketimpangan provinsi terutama berasal dari perbedaan antar-kawasan atau variasi di dalam kawasan.
Untuk capstone, minimal isi matriks berikut.
| Perspektif | Pertanyaan | Statistik/grafik |
|---|---|---|
| cross-section | wilayah mana ekstrem? | boxplot, rank, map |
| temporal | membaik/memburuk? | line, growth, slope |
| bivariate | variabel bergerak bersama? | scatter/correlation |
| multivariate | pola gabungan? | pairwise, PCA/cluster kemudian |
| uncertainty | seberapa stabil? | CI, sensitivity, missing analysis |
panel <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types=FALSE)
panel_2025 <- panel |> filter(tahun==2025)
panel_2025 |>
summarise(
n=n(),
mean_pov=mean(kemiskinan_persen),
median_pov=median(kemiskinan_persen),
sd_pov=sd(kemiskinan_persen),
iqr_pov=IQR(kemiskinan_persen),
cv_pov=sd_pov/mean_pov
) |> knitr::kable(digits=3)| n | mean_pov | median_pov | sd_pov | iqr_pov | cv_pov |
|---|---|---|---|---|---|
| 27 | 9.886 | 9.837 | 1.753 | 2.329 | 0.177 |
Setelah statistik keluar, tugas mahasiswa bukan membaca angka satu per satu, tetapi menghubungkan: apakah mean–median berbeda? apakah CV besar? apakah outlier valid? apakah tahun 2025 representatif atau shock?
panel <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE)
latest <- panel |> filter(tahun == max(tahun))
latest |>
summarise(across(c(kemiskinan_persen, tpt_persen, ipm, internet_persen),
list(mean = mean, median = median, sd = sd))) |>
pivot_longer(everything()) |>
knitr::kable(digits = 2, caption = "Ringkasan indikator regional 2025 (simulasi)")| name | value |
|---|---|
| kemiskinan_persen_mean | 9.89 |
| kemiskinan_persen_median | 9.84 |
| kemiskinan_persen_sd | 1.75 |
| tpt_persen_mean | 8.07 |
| tpt_persen_median | 7.75 |
| tpt_persen_sd | 1.10 |
| ipm_mean | 70.74 |
| ipm_median | 70.68 |
| ipm_sd | 1.18 |
| internet_persen_mean | 83.44 |
| internet_persen_median | 85.60 |
| internet_persen_sd | 8.19 |
latest |>
ggplot(aes(internet_persen, kemiskinan_persen)) +
geom_point() +
geom_smooth(method = "lm", se = TRUE) +
labs(x = "Akses internet (%)", y = "Kemiskinan (%)",
title = "EDA: hubungan internet dan kemiskinan - data simulasi")Gunakan Poverty Rate (SI.POV.NAPR.ZS), HDI (IDX.HDI), populasi (SP.POP.TOTL), dan literacy rate (SE.LITR.15UP.ZS) dari INDO-DAPOER. Metadata World Bank menyatakan sumber indikator tersebut terutama BPS/SUSENAS. Data historis dapat digunakan untuk mengamati disparitas, tetapi batas periode harus dicantumkan. (World Bank 2026)
Kartu dataset real.
SI.POV.NAPR.ZS = poverty rate (%), IDX.HDI = HDI, SP.POP.TOTL = total population, SE.LITR.15UP.ZS = literacy rate usia 15+.if (dir.exists("data/raw/indodapoer") && length(list.files("data/raw/indodapoer")) > 0) {
source("R/03_prepare_indodapoer.R")
indo <- load_indodapoer()
eda <- indo |>
dplyr::filter(kode_indikator %in% c("SI.POV.NAPR.ZS", "IDX.HDI"), tahun == 2018) |>
dplyr::select(wilayah, kode_indikator, nilai) |>
tidyr::pivot_wider(names_from = kode_indikator, values_from = nilai)
ggplot2::ggplot(eda, ggplot2::aes(IDX.HDI, SI.POV.NAPR.ZS)) +
ggplot2::geom_point(alpha = .65) + ggplot2::geom_smooth(method = "lm") +
ggplot2::labs(x = "HDI", y = "Poverty rate (%)", title = "EDA data INDO-DAPOER 2018")
} else {
eda <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |> dplyr::filter(tahun == 2025)
ggplot2::ggplot(eda, ggplot2::aes(ipm, kemiskinan_persen)) +
ggplot2::geom_point(alpha = .7) + ggplot2::geom_smooth(method = "lm") +
ggplot2::labs(x = "IPM", y = "Kemiskinan (%)", title = "Output fallback: EDA data simulasi")
}eda4 <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::filter(tahun == 2025)
vars4 <- c("pdrb_perkapita_juta", "kemiskinan_persen", "tpt_persen", "ipm", "internet_persen", "indeks_inovasi")
summary4 <- eda4 |>
dplyr::summarise(dplyr::across(dplyr::all_of(vars4), list(mean=mean, median=median, sd=sd, min=min, q1=~quantile(.x,.25), q3=~quantile(.x,.75), max=max))) |>
tidyr::pivot_longer(dplyr::everything(), names_to=c("indikator","stat"), names_pattern="(.*)_(mean|median|sd|min|q1|q3|max)") |>
tidyr::pivot_wider(names_from=stat, values_from=value)
knitr::kable(summary4, digits=2, caption="Ringkasan lengkap indikator regional tahun 2025")| indikator | mean | median | sd | min | q1 | q3 | max |
|---|---|---|---|---|---|---|---|
| pdrb_perkapita_juta | 49.22 | 50.90 | 10.86 | 24.04 | 41.56 | 56.10 | 66.15 |
| kemiskinan_persen | 9.89 | 9.84 | 1.75 | 6.01 | 8.77 | 11.10 | 13.05 |
| tpt_persen | 8.07 | 7.75 | 1.10 | 6.69 | 7.19 | 8.72 | 10.35 |
| ipm | 70.74 | 70.68 | 1.18 | 67.78 | 70.02 | 71.50 | 73.42 |
| internet_persen | 83.44 | 85.60 | 8.19 | 65.66 | 76.90 | 88.74 | 96.99 |
| indeks_inovasi | 68.25 | 69.00 | 4.12 | 60.29 | 65.42 | 71.06 | 76.82 |
ggplot2::ggplot(eda4, ggplot2::aes(kemiskinan_persen)) +
ggplot2::geom_histogram(ggplot2::aes(y=ggplot2::after_stat(density)), bins=10) +
ggplot2::geom_density(linewidth=1) +
ggplot2::geom_vline(xintercept=median(eda4$kemiskinan_persen), linetype=2) +
ggplot2::labs(title="Distribusi kemiskinan regional", subtitle="Histogram, density, dan median", x="Kemiskinan (%)", y="Density")ggplot2::ggplot(eda4, ggplot2::aes(pdrb_perkapita_juta, kemiskinan_persen, shape=factor(urban))) +
ggplot2::geom_point(size=2.7, alpha=.8) +
ggplot2::geom_smooth(method="lm", se=TRUE) +
ggplot2::labs(title="PDRB per kapita dan kemiskinan", x="PDRB per kapita (juta)", y="Kemiskinan (%)", shape="Urban")cor4 <- cor(eda4 |> dplyr::select(dplyr::all_of(vars4)), use="pairwise.complete.obs")
cor_long4 <- as.data.frame(as.table(cor4))
ggplot2::ggplot(cor_long4, ggplot2::aes(Var1,Var2,fill=Freq)) +
ggplot2::geom_tile() + ggplot2::geom_text(ggplot2::aes(label=sprintf("%.2f",Freq)), size=3) +
ggplot2::scale_fill_gradient2(limits=c(-1,1), midpoint=0) +
ggplot2::coord_equal() + ggplot2::labs(title="Matriks korelasi indikator regional",x=NULL,y=NULL,fill="r") +
ggplot2::theme(axis.text.x=ggplot2::element_text(angle=45,hjust=1))Jika hubungan HDI-kemiskinan negatif tetapi terdapat wilayah yang jauh dari pola umum, outlier tersebut justru menarik untuk case tracing: apakah ada struktur ekonomi khusus, kualitas layanan, urbanisasi, atau masalah measurement? EDA menghasilkan pertanyaan baru, bukan hanya grafik.
Susun regional disparity profile untuk satu indikator utama dan minimal dua indikator penjelas. Wajib menyajikan mean/median/SD/IQR, CV atau ukuran ketimpangan, top–bottom regions, trend, serta dua hipotesis substantif yang belum diklaim sebagai kausal.
Project M2 menghasilkan data dossier yang dapat diaudit dan EDA awal dengan 3–5 temuan yang relevan. Setiap grafik harus menjawab pertanyaan tertentu dan menaut pada kualitas data.
EDA adalah mekanisme quality control dan pembentuk hipotesis. Untuk konteks regional, selalu lihat distribusi, waktu, dan heterogenitas antarwilayah sebelum membangun model.
Visualisasi kebijakan harus cepat dipahami, tetapi tidak boleh mengorbankan ketepatan. Grafik yang baik mengarahkan perhatian pada pesan substantif sekaligus menyediakan konteks: unit, baseline, skala, denominator, dan ketidakpastian. Grammar of Graphics menyediakan kerangka sistematis untuk memetakan data ke estetika visual. (Wilkinson 2005; Tufte 2001)
Mahasiswa mampu memilih bentuk grafik sesuai pertanyaan, menghindari visual yang menyesatkan, membangun data story, dan merancang prototipe dashboard regional.
Data storytelling menggabungkan evidence, narrative, dan visual design. Narasi kebijakan umumnya mengikuti: konteks → gap/disparitas → siapa/di mana → faktor terkait → implikasi → opsi tindakan. Dashboard berbeda dari laporan: dashboard membantu monitoring/eksplorasi, sedangkan laporan dapat memuat argumentasi lebih panjang.
Perubahan absolut dan relatif:
Keduanya dapat menghasilkan pesan berbeda. Kenaikan 2 poin persentase dari 4% ke 6% adalah +2 pp tetapi +50% secara relatif.
Jika grafik menggunakan log scale, hubungan visual berubah. Untuk , Perbedaan pada skala log berhubungan dengan rasio pada skala asli: Karena itu, setiap transformasi sumbu harus disebutkan dan dipahami, bukan dianggap dekorasi.
Indeks dengan tahun dasar : Nilai berarti 25% di atas level tahun dasar, bukan “naik 125%”. Untuk membandingkan trajectory kabupaten dengan skala absolut sangat berbeda, indeks dapat lebih informatif daripada plot count.
Untuk dua titik waktu, Jika model tren linear , maka adalah perubahan rata-rata per unit waktu, dengan asumsi tren linear memadai.
Dalam Grammar of Graphics, grafik adalah pemetaan data ke aesthetics—position, length, color, shape, size—plus geometric objects dan coordinate system. (Wilkinson 2005) Untuk perbandingan presisi, posisi pada skala bersama umumnya lebih mudah dibaca dibanding area/volume. Karena itu bubble chart yang menarik secara visual belum tentu tepat untuk membandingkan perbedaan kecil.
Untuk choropleth, klasifikasi nilai dapat menggunakan quantile. Jika kelas, batas kuantil adalah . Namun klasifikasi quantile membuat tiap kelas berisi jumlah wilayah relatif sama dan dapat menyembunyikan gap substantif; equal interval dan natural breaks memberi pesan berbeda. Metode klasifikasi wajib dilaporkan.
Jika estimasi memiliki standard error , interval aproksimasi 95% adalah untuk kondisi asimtotik yang memadai. Menampilkan ribbon/interval membantu mencegah pembaca memperlakukan estimasi sebagai angka pasti.
Satu evidence story yang kuat memiliki struktur:
“Pengangguran turun” adalah claim; grafik trend adalah evidence; perubahan definisi atau shock pandemi adalah context; interval atau sensitivitas adalah uncertainty; implikasi target program adalah decision implication. Visualisasi yang indah tanpa lima komponen ini berisiko menjadi poster, bukan alat kebijakan. (Tufte 2001)
Grafik bar cocok untuk membandingkan kategori; line chart untuk tren waktu; scatterplot untuk hubungan; peta untuk pola geografis. Peta bukan default untuk semua indikator regional. Jika tujuan hanya ranking 27 kabupaten, sorted dot plot sering lebih mudah dibaca daripada choropleth.
Jika TPT wilayah A adalah 10% pada 2020 dan 7% pada 2024, indeks basis 2020: Artinya level 2024 adalah 70% dari level 2020 atau turun 30% relatif terhadap baseline. Jangan menulis “TPT menjadi 70%” tanpa menyebut bahwa 70 adalah indeks, bukan rate aktual.
Dari 10% menjadi 7% selama 4 tahun: Perubahan relatif: “Turun 3 percentage points” berbeda dari “turun 30 persen”. Bahasa kebijakan harus membedakan percentage point dan percent change.
Sebelum menggunakan grafik, cek:
Peta sebaiknya tidak digunakan hanya karena data memiliki nama wilayah. Jika pertanyaan adalah tren 20 tahun, line chart sering lebih efektif; peta membantu ketika spatial pattern substantif.
sel <- panel |> filter(wilayah %in% unique(wilayah)[1:5])
ggplot(sel, aes(tahun, kemiskinan_persen, group=wilayah, color=wilayah)) +
geom_line(linewidth=.8) + geom_point(size=1.5) +
labs(title="Perubahan kemiskinan lima wilayah simulasi",
subtitle="Bandingkan arah dan kecepatan perubahan, bukan hanya ranking tahun terakhir",
x=NULL, y="Kemiskinan (%)", color="Wilayah") +
theme(legend.position="bottom")Setelah grafik, tulis tiga jenis kalimat: pattern (“semua turun tetapi kecepatannya berbeda”), exception (“wilayah X stagnan”), dan implication (“intervensi seragam mungkin kurang tepat”).
Caption seharusnya menjawab: apa yang diukur; unit; periode; denominator; sumber; dan caveat. Contoh: “TPT kabupaten/kota Jawa Barat, persen angkatan kerja, 2007–2024; sumber BPS melalui Open Data Jawa Barat. Perubahan seri perlu dibaca bersama metadata dan kondisi pasar kerja.” (Badan Pusat Statistik dan Pemerintah Provinsi Jawa Barat 2026b)
latest <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
filter(tahun == 2025) |>
arrange(desc(kemiskinan_persen)) |>
slice_head(n = 12)
ggplot(latest, aes(x = reorder(wilayah, kemiskinan_persen), y = kemiskinan_persen)) +
geom_col() +
coord_flip() +
labs(x = NULL, y = "Kemiskinan (%)",
title = "12 wilayah dengan kemiskinan tertinggi (simulasi)",
subtitle = "Ranking digunakan untuk screening awal, bukan otomatis penetapan prioritas")TPT Open Data Jawa Barat memiliki seri tahunan 2007-2024, sehingga cocok untuk visualisasi tren dan perbandingan kabupaten/kota. Dataset menghasilkan persentase TPT, bukan jumlah penganggur; untuk beban absolut perlu sumber jumlah angkatan kerja atau jumlah penganggur. (Pemerintah Provinsi Jawa Barat 2026)
Kartu dataset real.
tingkat_pengangguran_terbuka = persentase angkatan kerja yang menganggur menurut definisi statistik produsen; satuan = persen; tahun.if (file.exists("data/raw/tpt_jabar.csv")) {
tpt <- readr::read_csv("data/raw/tpt_jabar.csv", show_col_types = FALSE) |> janitor::clean_names()
dat_plot <- tpt |> dplyr::group_by(nama_kabupaten_kota) |> dplyr::filter(dplyr::n() >= 3) |> dplyr::ungroup() |> dplyr::slice_head(n = 80)
ggplot2::ggplot(dat_plot, ggplot2::aes(tahun, tingkat_pengangguran_terbuka, group = nama_kabupaten_kota)) +
ggplot2::geom_line(alpha=.55) + ggplot2::labs(y="TPT (%)", title="Tren TPT — data resmi yang tersedia")
} else {
dat_plot <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::filter(wilayah %in% unique(wilayah)[1:5])
ggplot2::ggplot(dat_plot, ggplot2::aes(tahun, tpt_persen, group=wilayah, color=wilayah)) +
ggplot2::geom_line(linewidth=.9) + ggplot2::geom_point() +
ggplot2::labs(y="TPT (%)", title="Output fallback: tren TPT lima wilayah simulasi", color="Wilayah")
}vis5 <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE)
sel5 <- unique(vis5$wilayah)[1:6]
ggplot2::ggplot(vis5 |> dplyr::filter(wilayah %in% sel5), ggplot2::aes(tahun, kemiskinan_persen, group=wilayah, colour=wilayah)) +
ggplot2::geom_line(linewidth=.9) + ggplot2::geom_point(size=1.8) +
ggplot2::labs(title="Perubahan kemiskinan: contoh enam wilayah", y="Kemiskinan (%)", colour="Wilayah")rank5 <- vis5 |> dplyr::filter(tahun==max(tahun)) |> dplyr::arrange(dplyr::desc(kemiskinan_persen)) |>
dplyr::select(wilayah, kemiskinan_persen, tpt_persen, ipm, internet_persen)
knitr::kable(rank5, digits=2, caption="Evidence table untuk mendampingi visual ranking")| wilayah | kemiskinan_persen | tpt_persen | ipm | internet_persen |
|---|---|---|---|---|
| Wilayah_23 | 13.05 | 7.05 | 69.78 | 72.33 |
| Wilayah_07 | 12.94 | 8.68 | 71.95 | 78.72 |
| Wilayah_15 | 12.64 | 7.56 | 69.35 | 75.14 |
| Wilayah_19 | 11.81 | 7.54 | 70.19 | 76.92 |
| Wilayah_25 | 11.67 | 6.69 | 71.38 | 69.83 |
| Wilayah_06 | 11.64 | 7.25 | 69.97 | 84.58 |
| Wilayah_21 | 11.24 | 6.74 | 67.78 | 65.66 |
| Wilayah_09 | 10.97 | 9.63 | 70.38 | 85.60 |
| Wilayah_17 | 10.55 | 7.31 | 70.99 | 79.71 |
| Wilayah_27 | 10.10 | 7.65 | 69.34 | 90.37 |
| Wilayah_05 | 10.08 | 8.20 | 70.43 | 85.62 |
| Wilayah_24 | 10.06 | 8.67 | 71.73 | 88.05 |
| Wilayah_01 | 9.99 | 7.12 | 70.11 | 76.88 |
| Wilayah_18 | 9.84 | 7.75 | 70.68 | 84.59 |
| Wilayah_20 | 9.66 | 6.79 | 70.86 | 93.39 |
| Wilayah_26 | 9.61 | 9.63 | 71.71 | 75.11 |
| Wilayah_16 | 9.53 | 9.09 | 70.26 | 87.40 |
| Wilayah_22 | 9.44 | 8.76 | 71.33 | 89.43 |
| Wilayah_13 | 8.99 | 7.88 | 70.08 | 82.50 |
| Wilayah_08 | 8.98 | 7.08 | 69.54 | 73.56 |
| Wilayah_04 | 8.57 | 7.38 | 69.88 | 85.61 |
| Wilayah_10 | 8.52 | 8.09 | 71.62 | 96.99 |
| Wilayah_14 | 8.19 | 10.03 | 72.54 | 95.23 |
| Wilayah_12 | 7.98 | 10.35 | 71.12 | 93.96 |
| Wilayah_02 | 7.68 | 7.01 | 73.42 | 91.38 |
| Wilayah_11 | 7.16 | 7.94 | 72.38 | 87.64 |
| Wilayah_03 | 6.01 | 9.96 | 71.13 | 86.70 |
ggplot2::ggplot(rank5, ggplot2::aes(reorder(wilayah, kemiskinan_persen), kemiskinan_persen)) +
ggplot2::geom_col() + ggplot2::coord_flip() +
ggplot2::labs(title="Ranking kemiskinan pada tahun terakhir", x=NULL, y="Kemiskinan (%)")Visualisasi harus membedakan “nilai tinggi” dan “masalah besar”. Kota kecil dengan TPT tinggi mungkin memiliki jumlah penganggur absolut lebih sedikit daripada kabupaten besar dengan TPT sedang. Dashboard yang baik memungkinkan pembaca melihat rate dan count secara berdampingan.
before-after untuk dua tahun pada data simulasi.Buat satu halaman policy evidence story berisi maksimal empat grafik. Setiap grafik harus memiliki: pertanyaan, caption substantif, sumber, unit/satuan, periode, dan satu kalimat caveat. Sertakan satu grafik yang sengaja buruk, kemudian revisi dan jelaskan mengapa versi kedua lebih tepat.
Fokus: transformasi log; indeks tahun dasar; slope; pilihan visual encoding; masalah dual-axis; choropleth classification; uncertainty; claim–evidence–context–decision implication.
Mahasiswa membuat storyboard 5 panel: masalah, disparitas, driver/pola, model/evidence, dan rekomendasi. Ini menjadi kerangka dashboard dan presentasi akhir.
Visualisasi kebijakan adalah alat penalaran dan komunikasi. Pilih bentuk grafik berdasarkan pertanyaan, bukan karena efek visualnya menarik.
Regresi menghubungkan outcome dengan satu atau lebih prediktor dan menyediakan kerangka untuk estimasi, ketidakpastian, dan prediksi. Pada data regional, regresi sangat berguna, tetapi interpretasi harus membedakan asosiasi dari efek kausal.
Mahasiswa mampu merumuskan model regresi, menginterpretasi koefisien dan interval kepercayaan, mengecek residual secara dasar, mengenali multikolinearitas, dan menjelaskan keterbatasan inferensi observasional.
Model linear berganda menaksir hubungan kondisional: perubahan ekspektasi outcome ketika satu prediktor berubah, dengan prediktor lain ditahan konstan. Asumsi penting meliputi spesifikasi mean yang memadai, independensi/struktur error yang sesuai, serta stabilitas hubungan. Data panel dan spasial sering melanggar independensi sederhana sehingga regresi OLS harus dilihat sebagai baseline, bukan akhir analisis.
dengan outcome, prediktor, koefisien, dan error. Estimator OLS dalam notasi matriks:
Interval kepercayaan koefisien secara umum:
Misalkan i.i.d. dengan mean dan varians . Rata-rata sampel memiliki Standard error diestimasi oleh Untuk populasi normal atau sampel yang memadai, CI mean dengan adalah Interpretasi frequentist: prosedur interval tersebut memiliki coverage pada repeated sampling; bukan probabilitas posterior bahwa berada di interval tertentu.
Untuk , -value adalah probabilitas memperoleh statistik uji setidaknya se-ekstrem yang teramati jika dan asumsi model benar. -value bukan ukuran besar efek, bukan probabilitas benar, dan bukan pengganti relevansi kebijakan.
Model: Dalam bentuk matriks: OLS memilih yang, jika invertibel, memiliki solusi Residual: Estimator varians error: Varian koefisien di bawah homoskedastisitas:
Adjusted : tinggi tidak menjamin model memiliki error prediksi kecil pada data baru atau memiliki interpretasi kausal yang valid. (Harrell 2015)
Untuk prediktor , regresikan terhadap prediktor lain dan peroleh . Variance Inflation Factor: VIF menunjukkan inflasi varians koefisien akibat hubungan linear antarfitur; threshold seperti 5 atau 10 hanyalah rule-of-thumb, bukan hukum universal.
Model interaksi: Efek marginal adalah Artinya efek bergantung pada . Dalam konteks regional, dampak asosiasional digital connectivity terhadap outcome dapat berbeda menurut tingkat urbanisasi atau kapasitas fiskal.
Koefisien OLS bersifat kausal hanya di bawah asumsi identifikasi yang kuat. Jika variabel tak teramati memengaruhi dan , maka asosiasi dapat mengalami confounding. Buku kausal modern menekankan pemisahan pertanyaan prediktif dan kausal. (Hernán dan Robins 2020) Dalam mata kuliah ini, regresi terutama digunakan untuk deskripsi kondisional dan prediksi, kecuali desain identifikasi dijelaskan eksplisit.
Koefisien internet -0,05 pada model kemiskinan berarti bahwa, dalam model dan skala yang digunakan, peningkatan 1 poin persentase internet diasosiasikan dengan penurunan rata-rata 0,05 poin kemiskinan ketika variabel lain tetap. Ini bukan bukti efek kausal jika faktor confounding tidak ditangani.
Model hipotetis: Jika internet diukur persen, koefisien berarti pada data/model tersebut, kenaikan 1 percentage point internet berasosiasi dengan penurunan rata-rata 0,08 percentage point poverty, conditional on PDRBpc dan TPT. Kenaikan 10 points berasosiasi dengan 0,8 points lebih rendah. Kata “menyebabkan” tidak dibenarkan tanpa desain kausal.
Untuk model tanpa intercept yang sangat sederhana dengan Maka Prediksi . Contoh ini membantu melihat bahwa formula matriks adalah generalisasi prosedur minimisasi squared residual.
Untuk mean response pada : Untuk observasi baru: Prediction interval lebih lebar karena mencakup irreducible individual error selain uncertainty mean. Ini penting saat memberi range outcome satu wilayah, bukan hanya expected mean.
Empat pertanyaan minimum:
Pada panel regional, asumsi independence sering paling rapuh. Jika observasi wilayah berulang, standard error OLS biasa dapat tidak memadai. Mata kuliah ini mengenalkan diagnosis; model panel/spatial formal dapat menjadi studi lanjut.
d <- panel |> filter(tahun==2025)
fit6 <- lm(kemiskinan_persen ~ internet_persen + pdrb_perkapita_juta + tpt_persen,
data=d)
broom::tidy(fit6, conf.int=TRUE) |> knitr::kable(digits=3)| term | estimate | std.error | statistic | p.value | conf.low | conf.high |
|---|---|---|---|---|---|---|
| (Intercept) | 17.477 | 3.581 | 4.880 | 0.000 | 10.068 | 24.886 |
| internet_persen | -0.020 | 0.064 | -0.309 | 0.760 | -0.152 | 0.113 |
| pdrb_perkapita_juta | -0.086 | 0.047 | -1.834 | 0.080 | -0.184 | 0.011 |
| tpt_persen | -0.209 | 0.271 | -0.771 | 0.449 | -0.771 | 0.352 |
| r.squared | adj.r.squared | sigma | AIC |
|---|---|---|---|
| 0.464 | 0.394 | 1.365 | 99.102 |
Gunakan broom::augment() untuk residual/fitted. Setelah output, tulis effect scale, uncertainty, dan limitation. Koefisien kecil belum tentu tidak substantif bila satu unit perubahan variabel sangat besar; sebaliknya koefisien “signifikan” dapat tidak relevan secara kebijakan.
panel <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
filter(tahun == 2025)
m1 <- lm(kemiskinan_persen ~ pdrb_perkapita_juta + internet_persen + ipm + tpt_persen,
data = panel)
broom::tidy(m1, conf.int = TRUE) |>
knitr::kable(digits = 3, caption = "Regresi kemiskinan pada data simulasi")| term | estimate | std.error | statistic | p.value | conf.low | conf.high |
|---|---|---|---|---|---|---|
| (Intercept) | 7.522 | 23.830 | 0.316 | 0.755 | -41.897 | 56.941 |
| pdrb_perkapita_juta | -0.102 | 0.060 | -1.697 | 0.104 | -0.226 | 0.023 |
| internet_persen | -0.012 | 0.068 | -0.180 | 0.859 | -0.152 | 0.128 |
| ipm | 0.145 | 0.343 | 0.423 | 0.677 | -0.567 | 0.857 |
| tpt_persen | -0.233 | 0.282 | -0.826 | 0.417 | -0.818 | 0.352 |
augment(m1) |>
ggplot(aes(.fitted, .resid)) +
geom_hline(yintercept = 0, linetype = 2) +
geom_point() +
labs(x = "Fitted", y = "Residual", title = "Pemeriksaan residual dasar")INDO-DAPOER memiliki poverty rate (SI.POV.NAPR.ZS), HDI (IDX.HDI), literacy (SE.LITR.15UP.ZS), populasi (SP.POP.TOTL), unemployment counts (SL.UEM.TOTL) dan labor force (SL.TLF). TPT dapat dikonstruksi dari SL.UEM.TOTL/SL.TLF*100 jika definisi dan periode kompatibel. (World Bank 2026)
Kartu dataset real.
unemployed/labor_force*100 bila definisinya kompatibel.if (dir.exists("data/raw/indodapoer") && length(list.files("data/raw/indodapoer")) > 0) {
source("R/03_prepare_indodapoer.R")
indo <- load_indodapoer()
sel <- indo |>
dplyr::filter(kode_indikator %in% c("SI.POV.NAPR.ZS", "IDX.HDI", "SE.LITR.15UP.ZS", "SL.UEM.TOTL", "SL.TLF"), tahun == 2018) |>
dplyr::select(wilayah, kode_indikator, nilai) |>
tidyr::pivot_wider(names_from = kode_indikator, values_from = nilai) |>
dplyr::mutate(tpt_constructed = 100 * SL.UEM.TOTL / SL.TLF)
fit_real <- lm(SI.POV.NAPR.ZS ~ IDX.HDI + SE.LITR.15UP.ZS + tpt_constructed, data = sel)
} else {
sel <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |> dplyr::filter(tahun == 2025)
fit_real <- lm(kemiskinan_persen ~ ipm + indeks_pendidikan + tpt_persen, data = sel)
}
broom::tidy(fit_real, conf.int = TRUE) |> knitr::kable(digits = 3, caption = "Output: estimasi model dan interval kepercayaan")| term | estimate | std.error | statistic | p.value | conf.low | conf.high |
|---|---|---|---|---|---|---|
| (Intercept) | 17.875 | 22.593 | 0.791 | 0.437 | -28.863 | 64.612 |
| ipm | 0.146 | 0.392 | 0.372 | 0.714 | -0.665 | 0.957 |
| indeks_pendidikan | -0.187 | 0.084 | -2.212 | 0.037 | -0.361 | -0.012 |
| tpt_persen | -0.640 | 0.299 | -2.138 | 0.043 | -1.259 | -0.021 |
reg6 <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::filter(tahun == 2025)
fit6 <- stats::lm(kemiskinan_persen ~ pdrb_perkapita_juta + tpt_persen + internet_persen + ipm + urban, data=reg6)
coef6 <- broom::tidy(fit6, conf.int=TRUE)
knitr::kable(coef6, digits=3, caption="Koefisien OLS, standard error, p-value, dan 95% CI")| term | estimate | std.error | statistic | p.value | conf.low | conf.high |
|---|---|---|---|---|---|---|
| (Intercept) | 2.866 | 24.361 | 0.118 | 0.907 | -47.796 | 53.528 |
| pdrb_perkapita_juta | -0.125 | 0.065 | -1.929 | 0.067 | -0.259 | 0.010 |
| tpt_persen | -0.434 | 0.352 | -1.234 | 0.231 | -1.165 | 0.297 |
| internet_persen | -0.017 | 0.068 | -0.254 | 0.802 | -0.158 | 0.124 |
| ipm | 0.248 | 0.360 | 0.689 | 0.498 | -0.501 | 0.997 |
| urban | 0.888 | 0.926 | 0.959 | 0.348 | -1.038 | 2.815 |
glance6 <- broom::glance(fit6) |> dplyr::select(r.squared, adj.r.squared, sigma, statistic, p.value, AIC, BIC, df.residual)
knitr::kable(glance6, digits=3, caption="Ringkasan goodness-of-fit model regresi")| r.squared | adj.r.squared | sigma | statistic | p.value | AIC | BIC | df.residual |
|---|---|---|---|---|---|---|---|
| 0.49 | 0.369 | 1.393 | 4.043 | 0.01 | 101.726 | 110.797 | 21 |
aug6 <- broom::augment(fit6)
metric6 <- tibble::tibble(
RMSE = rmse_manual(reg6$kemiskinan_persen, aug6$.fitted),
MAE = mae_manual(reg6$kemiskinan_persen, aug6$.fitted),
mean_residual = mean(aug6$.resid),
max_cooks_d = max(aug6$.cooksd)
)
knitr::kable(metric6, digits=3, caption="Ukuran error dan influence pada data estimasi")| RMSE | MAE | mean_residual | max_cooks_d |
|---|---|---|---|
| 1.228 | 0.942 | 0 | 0.256 |
ggplot2::ggplot(aug6, ggplot2::aes(.fitted, .resid)) +
ggplot2::geom_hline(yintercept=0, linetype=2) + ggplot2::geom_point(alpha=.8) +
ggplot2::geom_smooth(se=FALSE) + ggplot2::labs(title="Residual versus fitted", x="Fitted", y="Residual")ggplot2::ggplot(aug6, ggplot2::aes(sample=.std.resid)) +
ggplot2::stat_qq() + ggplot2::stat_qq_line() +
ggplot2::labs(title="Normal Q–Q plot standardized residual")ggplot2::ggplot(aug6, ggplot2::aes(kemiskinan_persen, .fitted)) +
ggplot2::geom_abline(slope=1,intercept=0,linetype=2) + ggplot2::geom_point(size=2.5) +
ggplot2::labs(title="Aktual versus fitted OLS", x="Aktual (%)", y="Fitted (%)")Koefisien harus dibaca bersama skala, interval ketidakpastian, dan plausibilitas substantif. Jika model menunjukkan HDI dan literacy sama-sama kuat tetapi sangat berkorelasi, koefisien individual dapat menjadi tidak stabil. Untuk kebijakan, fokus pada evidence pattern dan ketidakpastian, bukan pada signifikansi p-value saja.
Bangun baseline regression untuk outcome regional. Laporkan model equation, coefficient table, CI, residual diagnostics, VIF, satu interaction term yang punya justifikasi, dan interpretasi substantif. Tuliskan satu paragraf berjudul “Apa yang tidak dapat saya simpulkan secara kausal dari model ini.”
Project M3 mengintegrasikan EDA/evidence story dengan baseline statistical model dan dokumentasi asumsi. Baseline ini menjadi pembanding yang bermakna untuk model prediktif berikutnya.
Regresi adalah alat dasar yang sangat kuat untuk regional analytics jika digunakan dengan disiplin interpretasi, diagnostik, dan kesadaran terhadap confounding serta struktur data.
Prediksi menilai kemampuan model untuk bekerja pada data yang tidak digunakan saat fitting. Kesalahan umum dalam proyek regional adalah mengevaluasi model pada data training atau melakukan preprocessing menggunakan seluruh data sebelum split, sehingga kinerja terlihat terlalu baik.
Mahasiswa mampu membangun workflow train/test, cross-validation, baseline, feature preprocessing, serta mendeteksi leakage temporal dan geografis.
Generalization error adalah error pada observasi baru. Data leakage terjadi ketika informasi yang seharusnya tidak tersedia saat prediksi masuk ke proses training. Untuk forecast atau panel waktu, random split dapat membocorkan informasi masa depan. Untuk wilayah, random split juga dapat terlalu optimistis bila wilayah tetangga sangat serupa.
MSE dan RMSE:
MAE:
Dalam -fold cross-validation,
dengan loss pada fold ke-.
Tujuan prediksi bukan meminimalkan training error, tetapi error pada data baru: Test error adalah estimator praktis dari kuantitas ini ketika test set benar-benar independen dari proses training/tuning.
Data training dibagi menjadi fold . Model dilatih tanpa fold . Estimator CV risk: Untuk panel regional, random CV dapat terlalu optimistis bila observasi wilayah yang sama muncul di train dan validation. Gunakan grouped CV, spatial blocking, atau rolling/temporal split sesuai target deployment. (Kuhn dan Silge 2022)
MAPE bermasalah saat dekat nol. Untuk indikator seperti growth yang dapat nol/negatif, MAE/RMSE atau scaled errors biasanya lebih aman.
Untuk squared error pada titik , Model sangat fleksibel dapat menurunkan bias tetapi meningkatkan variance. Resampling membantu memilih kompleksitas yang memberi trade-off generalization terbaik. (Hastie, Tibshirani, dan Friedman 2009)
Ridge: Lasso: Ridge mengecilkan koefisien; lasso dapat menghasilkan beberapa koefisien tepat nol. Prediktor sebaiknya distandardisasi sebelum regularisasi. (Hoerl dan Kennard 1970; Tibshirani 1996)
Misalkan transformasi preprocessing memiliki parameter . Leakage terjadi jika ketika seharusnya Contoh: standardisasi, imputasi, feature selection, PCA, atau tuning threshold menggunakan test set. Test set baru “dibuka” setelah seluruh keputusan model selesai.
RMSE lebih memberi penalti pada error besar. Jika kebijakan sangat sensitif terhadap kegagalan memprediksi wilayah ekstrem, RMSE bisa lebih relevan daripada MAE. Tetapi metric harus terkait keputusan, bukan dipilih hanya karena umum digunakan.
Tujuan: memprediksi indikator 2025 menggunakan informasi hingga 2024. Maka split random yang memasukkan observasi 2025 ke training melanggar deployment. Gunakan Validation dipakai tuning; test hanya evaluasi final.
Error model A: . MAE=, RMSE=. Error ekstrem mendapat penalti lebih kuat pada RMSE. Jika kebijakan sangat sensitif terhadap miss besar, RMSE mungkin lebih sesuai; jika robust typical absolute error lebih penting, MAE informatif.
Untuk 5-fold CV, setiap observasi menjadi validation tepat sekali. Jika fold RMSE = 2.1, 2.4, 1.9, 2.6, 2.2: Laporkan distribusi, bukan hanya mean. Variability tinggi berarti model sensitif terhadap sample composition.
Jika dua prediktor sangat berkorelasi, OLS dapat menghasilkan koefisien besar dengan tanda tidak stabil. Ridge menambah , sehingga solusi menerima sedikit bias untuk mengurangi variance. lambda bukan dipilih dari test set; gunakan resampling training.
set.seed(260817)
dat <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::select(kemiskinan_persen, pdrb_perkapita_juta, tpt_persen, internet_persen, ipm, umkm_per_1000)
spl <- initial_split(dat, prop = .8)
tr <- training(spl)
folds <- vfold_cv(tr, v = 5)
rec <- recipe(kemiskinan_persen ~ ., data = tr) |> step_normalize(all_numeric_predictors())
mod <- linear_reg() |> set_engine("lm")
wf <- workflow() |> add_recipe(rec) |> add_model(mod)
res <- fit_resamples(wf, resamples = folds, metrics = metric_set(rmse, mae, rsq))
collect_metrics(res) |> knitr::kable(digits = 3, caption = "Output: 5-fold cross-validation baseline")| .metric | .estimator | mean | n | std_err | .config |
|---|---|---|---|---|---|
| mae | standard | 1.024 | 5 | 0.030 | pre0_mod0_post0 |
| rmse | standard | 1.313 | 5 | 0.050 | pre0_mod0_post0 |
| rsq | standard | 0.711 | 5 | 0.027 | pre0_mod0_post0 |
| Komponen | Fit hanya pada train/resample? | Risiko jika tidak |
|---|---|---|
| median imputation | ya | test distribution bocor |
| normalization | ya | mean/SD test bocor |
| feature selection | ya | selection optimism |
| PCA | ya | loading memakai test |
| hyperparameter tuning | ya | overfit test |
| threshold selection | validation | inflated test metric |
Pertanyaan validasi bukan “split mana yang paling mudah”, tetapi “data apa yang akan tersedia saat model benar-benar dipakai?”. Untuk prediksi wilayah baru, group split by region mungkin tepat. Untuk masa depan, temporal split. Untuk generalisasi geografis, spatial block. (Kuhn dan Silge 2022)
panel <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE)
train <- panel |> filter(tahun <= 2023)
test <- panel |> filter(tahun >= 2024)
fit <- lm(kemiskinan_persen ~ pdrb_perkapita_juta + tpt_persen + internet_persen + ipm,
data = train)
pred <- test |> mutate(.pred = predict(fit, newdata = test))
pred |>
summarise(RMSE = rmse_manual(kemiskinan_persen, .pred),
MAE = mae_manual(kemiskinan_persen, .pred)) |>
knitr::kable(digits = 3)| RMSE | MAE |
|---|---|
| 1.413 | 1.096 |
pred |>
ggplot2::ggplot(ggplot2::aes(kemiskinan_persen, .pred)) +
ggplot2::geom_abline(slope = 1, intercept = 0, linetype = 2, colour = "#C99A17") +
ggplot2::geom_point(alpha = .7, colour = "#145B8C") +
ggplot2::labs(
title = "Evaluasi out-of-time: aktual versus prediksi",
x = "Kemiskinan aktual (%)", y = "Kemiskinan prediksi (%)"
)Data panel INDO-DAPOER dapat dibagi berdasarkan waktu, misalnya training sampai 2015 dan test 2016-2018, selama indikator memiliki kelengkapan memadai. Karena data historis, tujuan latihan adalah mengevaluasi pipeline, bukan memberi rekomendasi kebijakan terkini.
Kartu dataset real.
library(tidymodels)
set.seed(260807)
reg <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |> filter(tahun == 2025)
split <- initial_split(reg, prop = .8, strata = kemiskinan_persen)
tr <- training(split); te <- testing(split)
rec <- recipe(kemiskinan_persen ~ pdrb_perkapita_juta + tpt_persen + internet_persen + ipm + umkm_per_1000,
data = tr) |>
step_normalize(all_numeric_predictors())
mod <- linear_reg() |> set_engine("lm")
wf <- workflow() |> add_recipe(rec) |> add_model(mod) |> fit(tr)
p <- predict(wf, te) |> bind_cols(te |> select(kemiskinan_persen))
yardstick::metrics(p, truth = kemiskinan_persen, estimate = .pred)#> # A tibble: 3 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 rmse standard 1.66
#> 2 rsq standard 0.369
#> 3 mae standard 1.42
set.seed(260817)
dat7 <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::select(kemiskinan_persen, pdrb_perkapita_juta, tpt_persen, internet_persen, ipm, umkm_per_1000)
split7 <- rsample::initial_split(dat7, prop=.8)
tr7 <- rsample::training(split7); te7 <- rsample::testing(split7)
folds7 <- rsample::vfold_cv(tr7, v=5)
wf7 <- workflows::workflow() |>
workflows::add_recipe(recipes::recipe(kemiskinan_persen ~ ., data=tr7) |> recipes::step_normalize(recipes::all_numeric_predictors())) |>
workflows::add_model(parsnip::linear_reg() |> parsnip::set_engine("lm"))
res7 <- tune::fit_resamples(wf7, resamples=folds7, metrics=yardstick::metric_set(yardstick::rmse, yardstick::mae, yardstick::rsq))
fold_metric7 <- tune::collect_metrics(res7, summarize=FALSE)
knitr::kable(fold_metric7, digits=3, caption="Metric setiap fold — bukan hanya rata-rata")| id | .metric | .estimator | .estimate | .config |
|---|---|---|---|---|
| Fold1 | rmse | standard | 1.123 | pre0_mod0_post0 |
| Fold1 | mae | standard | 0.926 | pre0_mod0_post0 |
| Fold1 | rsq | standard | 0.802 | pre0_mod0_post0 |
| Fold2 | rmse | standard | 1.346 | pre0_mod0_post0 |
| Fold2 | mae | standard | 1.086 | pre0_mod0_post0 |
| Fold2 | rsq | standard | 0.647 | pre0_mod0_post0 |
| Fold3 | rmse | standard | 1.328 | pre0_mod0_post0 |
| Fold3 | mae | standard | 1.084 | pre0_mod0_post0 |
| Fold3 | rsq | standard | 0.667 | pre0_mod0_post0 |
| Fold4 | rmse | standard | 1.356 | pre0_mod0_post0 |
| Fold4 | mae | standard | 1.016 | pre0_mod0_post0 |
| Fold4 | rsq | standard | 0.724 | pre0_mod0_post0 |
| Fold5 | rmse | standard | 1.414 | pre0_mod0_post0 |
| Fold5 | mae | standard | 1.007 | pre0_mod0_post0 |
| Fold5 | rsq | standard | 0.714 | pre0_mod0_post0 |
ggplot2::ggplot(fold_metric7 |> dplyr::filter(.metric %in% c("rmse","mae")), ggplot2::aes(.metric,.estimate)) +
ggplot2::geom_boxplot(width=.45) + ggplot2::geom_jitter(width=.08, size=2) +
ggplot2::labs(title="Variabilitas metric antar-fold", x=NULL, y="Nilai metric")fit7 <- generics::fit(wf7, data = tr7)
pred7 <- predict(fit7, te7) |> dplyr::bind_cols(te7 |> dplyr::select(kemiskinan_persen))
yardstick::metrics(pred7, truth=kemiskinan_persen, estimate=.pred) |>
knitr::kable(digits=3, caption="Final test metrics setelah resampling selesai")| .metric | .estimator | .estimate |
|---|---|---|
| rmse | standard | 1.096 |
| rsq | standard | 0.719 |
| mae | standard | 0.870 |
Model dengan RMSE 1,2 poin kemiskinan berarti error tipikal berada pada skala sekitar satu poin persentase, tetapi implikasinya berbeda bagi wilayah 3% dan 20%. Evaluasi perlu melihat error menurut kelompok: urban/rural, wilayah miskin/nonmiskin, dan wilayah dengan data terbatas.
Bandingkan minimal dua model pada split yang sesuai dengan deployment (random/group/time). Laporkan baseline, CV metric distribution, final test metric, dan tabel leakage audit. Setiap transformasi harus dikerjakan hanya pada training/resample yang relevan.
Kisi-kisi: summary/inequality; visualisasi; OLS; CI; interaction; RMSE/MAE; cross-validation; bias–variance; ridge/lasso; leakage; baseline comparison.
Kelompok harus menetapkan evaluation protocol sebelum mencoba banyak model: unit split, metric utama, metric sekunder, baseline, dan subgroup check.
Evaluasi yang jujur lebih penting daripada skor spektakuler. Leakage dapat membuat model tampak hebat namun gagal saat digunakan untuk keputusan nyata.
UTS menguji integrasi kompetensi minggu 1-7. Fokusnya bukan menghafal sintaks, melainkan membuat keputusan analitik yang dapat dipertanggungjawabkan.
Mahasiswa mampu mengaudit dataset, merumuskan pertanyaan, melakukan EDA, membangun baseline model, mengevaluasi, dan menulis interpretasi kebijakan singkat secara individual.
UTS menggunakan open-book analytical case. Mahasiswa dapat melihat dokumentasi R, tetapi harus menjelaskan alasan pilihan metode dan interpretasi. Data dapat berupa potongan indikator kabupaten/kota dengan masalah kualitas yang sengaja disisipkan.
Formula yang diujikan berasal dari bab 1-7: rate, standardisasi, mean/variance, korelasi, regresi, RMSE, dan MAE. Mahasiswa tidak dinilai karena menghafal formula, tetapi karena memilih formula yang sesuai dan menjelaskan simbol serta unitnya.
UTS mengintegrasikan materi minggu 1–7. Mahasiswa harus dapat menjelaskan kapan setiap rumus relevan dan asumsi apa yang menyertainya.
Rate dan growth
Z-score
Correlation
OLS
RMSE/MAE
CV risk
UTS bukan ujian “mengetik kode tercepat”. Sebuah jawaban lengkap memiliki empat lapis:
| Dimensi RPS | Proporsi skor UTS | Fokus |
|---|---|---|
| Problem framing & pertanyaan analitik | 15% | unit analisis, outcome, pertanyaan, provenance, dan batas klaim |
| Data quality/EDA dan pemilihan bukti | 20% | audit data, cleaning, EDA, visualisasi, dan kualitas evidence |
| Metode statistik/model dasar | 25% | pemilihan dan penerapan metode, formulasi, asumsi, serta interpretasi |
| Evaluasi/asumsi/validation reasoning | 15% | diagnostic, split/resampling bila relevan, metric, leakage, dan keterbatasan |
| Interpretasi regional dan policy implication | 15% | makna substantif, caveat, dan rekomendasi terbatas |
| Reproducibility, sumber, dan komunikasi | 10% | Rmd/PDF, sumber, dokumentasi, dan keterlacakan analisis |
UTS mensimulasikan situasi analis: data belum sempurna, waktu terbatas, dan stakeholder membutuhkan ringkasan yang akurat. Jawaban terbaik bukan yang memakai model paling kompleks, tetapi yang menjaga validitas dari awal sampai interpretasi.
Kasus: dataset 27 kabupaten/kota × 2016–2024 berisi TPT, kemiskinan, pertumbuhan PDRB, internet, dan pendidikan. Ada duplikasi 6 key, missing internet 2020 untuk 4 wilayah, dan satu nilai TPT=82 akibat salah decimal.
Langkah 1 — audit. Jangan langsung drop_na(). Identifikasi duplicate key dan nilai impossible. Verifikasi dari source sebelum koreksi.
Langkah 2 — feature. Untuk memprediksi TPT 2024, fitur yang berasal dari outcome 2024 tidak boleh digunakan. Gunakan lag 2023 atau indikator yang tersedia sebelum keputusan.
Langkah 3 — EDA. Minimal satu grafik trend, satu cross-sectional relationship, satu regional ranking/map. Setiap grafik punya source/unit.
Langkah 4 — baseline. Fit model linear pada ≤2022, validasi 2023, test 2024. Interpretasikan conditional associations.
Langkah 5 — metric. Jika RMSE 1.4 percentage points, terjemahkan: “typical squared-error scale sekitar 1.4 poin TPT”, bukan “akurasi 98.6%”.
Langkah 6 — policy memo. Pisahkan observation, hypothesis, dan recommendation.
Jawaban dengan kode sempurna tetapi menggunakan data 2024 untuk feature yang memprediksi 2024 dapat kehilangan skor besar karena target leakage. Sebaliknya syntax kecil yang tidak memengaruhi kesimpulan dapat mendapat penalti lebih ringan. Ini menegaskan prioritas validitas dibanding kosmetika.
Mahasiswa seharusnya mampu menghitung dan menjelaskan makna tiap hasil.
File harus dapat di-knit dari awal. Gunakan path relatif; jangan menggunakan setwd("/Users/nama/Desktop"); jangan menyunting angka output secara manual; dan catat package yang dipakai. Bila data ujian disediakan lokal, gunakan here atau struktur folder sederhana.
set.seed(260808)
uts_case <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
filter(tahun %in% c(2023, 2024, 2025)) |>
sample_n(60) |>
mutate(internet_persen = if_else(row_number() %% 13 == 0, NA_real_, internet_persen))
knitr::kable(head(uts_case, 8), digits = 2, caption = "Contoh struktur data case UTS")| wilayah | tahun | urban | longitude | latitude | pdrb_perkapita_juta | kemiskinan_persen | tpt_persen | ipm | internet_persen | umkm_per_1000 | indeks_pendidikan | akses_kesehatan | indeks_inovasi |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Wilayah_23 | 2025 | 0 | 106.92 | -6.89 | 41.20 | 13.05 | 7.05 | 69.78 | 72.33 | 35.41 | 65.93 | 70.35 | 70.57 |
| Wilayah_27 | 2023 | 1 | 107.67 | -6.04 | 42.78 | 12.10 | 8.44 | 67.63 | 77.99 | 31.82 | 65.90 | 59.45 | 66.14 |
| Wilayah_08 | 2023 | 0 | 106.96 | -6.76 | 32.64 | 12.09 | 6.92 | 68.94 | 64.86 | 30.16 | 70.45 | 60.78 | 59.17 |
| Wilayah_18 | 2025 | 1 | 107.84 | -7.68 | 53.71 | 9.84 | 7.75 | 70.68 | 84.59 | 40.48 | 64.91 | 63.78 | 67.93 |
| Wilayah_24 | 2024 | 1 | 108.35 | -6.50 | 52.89 | 11.27 | 7.99 | 68.66 | 82.10 | 38.27 | 62.40 | 60.52 | 63.88 |
| Wilayah_16 | 2023 | 1 | 107.54 | -7.54 | 46.36 | 9.45 | 9.43 | 65.87 | 77.38 | 32.02 | 59.58 | 55.15 | 64.34 |
| Wilayah_21 | 2025 | 0 | 107.06 | -6.75 | 24.04 | 11.24 | 6.74 | 67.78 | 65.66 | 31.20 | 60.43 | 64.54 | 60.84 |
| Wilayah_10 | 2025 | 1 | 107.47 | -7.51 | 66.15 | 8.52 | 8.09 | 71.62 | 96.99 | 46.95 | 77.19 | 76.32 | 70.22 |
uts_case |>
dplyr::summarise(dplyr::across(dplyr::everything(), ~mean(is.na(.x)))) |>
tidyr::pivot_longer(dplyr::everything(), names_to = "variabel", values_to = "prop_missing") |>
dplyr::filter(prop_missing > 0) |>
ggplot2::ggplot(ggplot2::aes(reorder(variabel, prop_missing), prop_missing)) +
ggplot2::geom_col(fill = "#C99A17") +
ggplot2::coord_flip() +
ggplot2::scale_y_continuous(labels = scales::percent) +
ggplot2::labs(title = "Proporsi missing pada data kasus UTS", x = NULL, y = "Proporsi missing")Dosen dapat mengganti case dengan subset Open Data Jabar yang diunduh sebelum ujian. Dataset dan metadata diberikan bersama agar ujian mengukur analisis, bukan kemampuan mencari URL.
Kartu dataset real untuk UTS.
Template minimum jawaban:
dat <- uts_case |> tidyr::drop_na()
fit <- lm(kemiskinan_persen ~ internet_persen + pdrb_perkapita_juta + tpt_persen, data = dat)
broom::glance(fit) |>
dplyr::select(r.squared, adj.r.squared, sigma, AIC) |>
knitr::kable(digits = 3, caption = "Output contoh UTS: ringkasan baseline regression")| r.squared | adj.r.squared | sigma | AIC |
|---|---|---|---|
| 0.573 | 0.549 | 1.246 | 189.426 |
Nilai tinggi diberikan untuk interpretasi yang mengenali trade-off dan ketidakpastian. Mahasiswa harus menghindari kalimat kausal jika desain data hanya observasional.
Kerjakan satu mock case 90 menit: data kabupaten–tahun dengan dua masalah kualitas, satu missing mechanism yang perlu didiskusikan, satu visualisasi yang salah, dan satu baseline regression. Jawaban harus memuat kode serta policy interpretation.
Mahasiswa harus dapat menjelaskan tanpa membuka catatan: unit analisis; denominator; z-score; correlation; OLS objective; arti CI; RMSE vs MAE; K-fold CV; data leakage; dan mengapa prediksi tidak identik dengan kausalitas.
UTS menjadi quality gate: kelemahan individu yang muncul pada UTS harus diperbaiki sebelum tim masuk ke model ML capstone.
UTS menilai integrasi, bukan potongan teknik. Kemampuan mendokumentasikan keputusan analitik sama pentingnya dengan mendapatkan output model.
Machine learning berguna ketika hubungan antarvariabel kompleks, interaksi banyak, atau tujuan utama adalah prediksi. Namun model harus dibandingkan dengan baseline yang sederhana dan dipilih berdasarkan generalisasi, interpretabilitas, biaya kesalahan, serta konteks implementasi. (James dkk. 2021; Kuhn dan Silge 2022)
Mahasiswa mampu menjelaskan bias-variance trade-off, membangun workflow ML dengan resampling, menggunakan tree-based model, dan membandingkan kinerja dengan regresi baseline.
Bias adalah error sistematis dari model yang terlalu sederhana; variance adalah sensitivitas model terhadap perubahan sampel. Random forest menggabungkan banyak pohon dengan bootstrap dan random feature selection sehingga variance berkurang. (Breiman 2001)
Dekomposisi error prediksi secara konseptual:
Untuk random forest regresi, prediksi adalah rata-rata pohon:
dengan jumlah pohon.
Pada node , prediksi konstan terbaik untuk squared error adalah mean
Split dipilih untuk meminimalkan
Tree yang terlalu dalam cenderung overfit; hyperparameter seperti min_n, depth, atau cost complexity mengendalikan kompleksitas. (James dkk. 2021)
Jika node memiliki proporsi kelas , Entropy: Split dicari untuk menurunkan impurity tertimbang.
Untuk bootstrap sample , fit tree . Prediksi regresi bagging: Random forest menambahkan random subset fitur pada setiap split untuk mengurangi korelasi antar-tree; prinsip ini dapat menurunkan variance ensemble. (Breiman 2001)
Untuk klasifikasi, probabilitas dapat diperkirakan dari rata-rata probabilitas tree atau proporsi votes:
Boosting membangun model aditif dengan weak learner , step size , dan learning rate . Pada setiap iterasi, learner baru diarahkan untuk mengurangi loss melalui negative gradient. (Friedman 2001)
XGBoost menambahkan regularization pada objective: dengan penalti kompleksitas tree . (Chen dan Guestrin 2016)
Permutation importance untuk fitur dapat diringkas sebagai kenaikan error setelah nilai fitur tersebut diacak: Jika dua prediktor sangat berkorelasi, importance dapat tersebar/tidak stabil. Importance menunjukkan kontribusi prediktif dalam model dan distribusi data tertentu, bukan efek intervensi. Untuk kebijakan, gunakan sebagai alat diagnosis model, bukan klaim kausal.
Model kompleks harus dibandingkan dengan baseline . Perbaikan relatif error: Jika perbaikan sangat kecil tetapi kompleksitas, biaya komputasi, dan kesulitan interpretasi meningkat tajam, baseline dapat lebih layak untuk sistem kebijakan.
Satu pohon mudah dijelaskan tetapi tidak stabil. Random forest membuat banyak pohon yang berbeda dan merata-ratakan keputusan. Kinerja dapat meningkat, tetapi interpretasi kebijakan menjadi lebih tidak langsung; gunakan variable importance atau partial dependence secara hati-hati, bukan sebagai bukti kausal.
Node memiliki outcome dan satu fitur yang memungkinkan split setelah observasi ke-3. Mean kiri =4, mean kanan =11.667. SSE split: Total 6.667. Tree membandingkan candidate split lain dan memilih penurunan impurity terbesar.
Node memiliki 8 prioritas dan 2 non-prioritas: Node pure 10/0 memiliki Gini=0. Split yang menghasilkan child lebih pure menurunkan weighted impurity.
Jika estimator individual memiliki variance dan pairwise correlation , variance rata-rata kira-kira Menambah mengurangi komponen kedua, tetapi tidak menghilangkan komponen korelasi. Random feature selection pada random forest bertujuan menurunkan correlation antartree. (Breiman 2001)
Learning rate kecil memerlukan lebih banyak trees tetapi sering memberi regularization lebih baik. Ada trade-off antara trees, tree_depth, dan learn_rate. Tuning harus dilakukan pada resamples training; jangan memilih parameter karena satu test metric terlihat paling baik.
Untuk model project, buat tabel:
| Elemen | Isi |
|---|---|
| Intended use | screening wilayah untuk review |
| Not intended | menentukan penerima individu |
| Training period | contoh 2015–2022 |
| Target | TPT 2023 atau prioritas biner |
| Metrics | RMSE/MAE atau PR-AUC/calibration |
| Key limitations | historical coverage, spatial dependence |
| Fairness slices | urban/rural atau kawasan bila justified |
Dokumentasi model semacam ini sejalan dengan gagasan model cards. (Mitchell dkk. 2019)
models <- tibble::tribble(
~model, ~kompleksitas, ~kekuatan, ~risiko,
"Linear regression", "Rendah", "Interpretabel; baseline kuat", "Nonlinearitas tidak tertangkap",
"Decision tree", "Sedang", "Aturan keputusan mudah dijelaskan", "Tidak stabil; mudah overfit",
"Random forest", "Tinggi", "Menangkap nonlinearitas/interaksi", "Interpretasi lebih sulit"
)
knitr::kable(models, caption = "Output: model comparison matrix sebelum tuning")| model | kompleksitas | kekuatan | risiko |
|---|---|---|---|
| Linear regression | Rendah | Interpretabel; baseline kuat | Nonlinearitas tidak tertangkap |
| Decision tree | Sedang | Aturan keputusan mudah dijelaskan | Tidak stabil; mudah overfit |
| Random forest | Tinggi | Menangkap nonlinearitas/interaksi | Interpretasi lebih sulit |
Gunakan tiga lapis: (1) global performance, (2) global structure/importance, (3) local prediction explanation. Jangan meloncat ke local explanation bila model global tidak tervalidasi. Penjelasan model tidak memperbaiki model yang salah atau data yang tidak relevan.
library(tidymodels)
set.seed(260809)
dat <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |> filter(tahun == 2025)
s <- initial_split(dat, prop = .8)
tr <- training(s); te <- testing(s)
rf_spec <- rand_forest(trees = 500, mtry = 4, min_n = 3) |>
set_engine("ranger", importance = "permutation") |>
set_mode("regression")
rf_fit <- workflow() |>
add_formula(kemiskinan_persen ~ pdrb_perkapita_juta + tpt_persen + ipm + internet_persen + umkm_per_1000 + akses_kesehatan) |>
add_model(rf_spec) |>
fit(tr)
predict(rf_fit, te) |>
bind_cols(te |> select(kemiskinan_persen)) |>
yardstick::metrics(truth = kemiskinan_persen, estimate = .pred)#> # A tibble: 3 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 rmse standard 1.90
#> 2 rsq standard 0.00147
#> 3 mae standard 1.51
INDO-DAPOER dapat menyediakan fitur sosial-ekonomi lintas kabupaten. Karena jumlah indikator sangat banyak dan missingness bervariasi, pemilihan fitur harus mengikuti teori dan data availability; memasukkan semua indikator tanpa screening dapat meningkatkan leakage dan instability.
Kartu dataset real.
# Bandingkan model sederhana dan RF pada split yang sama.
lm_fit <- linear_reg() |> set_engine("lm") |>
fit(kemiskinan_persen ~ pdrb_perkapita_juta + tpt_persen + ipm + internet_persen + umkm_per_1000 + akses_kesehatan,
data = tr)
lm_pred <- predict(lm_fit, te) |> bind_cols(te |> select(kemiskinan_persen))
rf_pred <- predict(rf_fit, te) |> bind_cols(te |> select(kemiskinan_persen))
bind_rows(
yardstick::metrics(lm_pred, kemiskinan_persen, .pred) |> mutate(model = "Linear"),
yardstick::metrics(rf_pred, kemiskinan_persen, .pred) |> mutate(model = "Random forest")
) |>
filter(.metric %in% c("rmse", "mae")) |>
select(model, .metric, .estimate) |>
knitr::kable(digits = 3)| model | .metric | .estimate |
|---|---|---|
| Linear | rmse | 2.114 |
| Linear | mae | 1.797 |
| Random forest | rmse | 1.896 |
| Random forest | mae | 1.510 |
vis_compare <- dplyr::bind_rows(
lm_pred |> dplyr::transmute(actual = kemiskinan_persen, pred = .pred, model = "Linear regression"),
rf_pred |> dplyr::transmute(actual = kemiskinan_persen, pred = .pred, model = "Random forest")
)
ggplot2::ggplot(vis_compare, ggplot2::aes(actual, pred)) +
ggplot2::geom_abline(slope = 1, intercept = 0, linetype = 2, colour = "#C99A17") +
ggplot2::geom_point(alpha = .7, colour = "#145B8C") +
ggplot2::facet_wrap(~model) +
ggplot2::labs(title = "Aktual versus prediksi pada split yang sama", x = "Aktual", y = "Prediksi")rf_engine9 <- workflows::extract_fit_engine(rf_fit)
imp9 <- tibble::enframe(rf_engine9$variable.importance, name="feature", value="importance") |>
dplyr::arrange(dplyr::desc(importance))
knitr::kable(imp9, digits=3, caption="Permutation variable importance Random Forest")| feature | importance |
|---|---|
| pdrb_perkapita_juta | 2.214 |
| internet_persen | 0.132 |
| umkm_per_1000 | 0.032 |
| akses_kesehatan | 0.014 |
| tpt_persen | -0.060 |
| ipm | -0.071 |
ggplot2::ggplot(imp9, ggplot2::aes(reorder(feature, importance), importance)) +
ggplot2::geom_col() + ggplot2::coord_flip() +
ggplot2::labs(title="Variable importance Random Forest", x=NULL, y="Permutation importance")error9 <- dplyr::bind_rows(
lm_pred |> dplyr::mutate(model="Linear"),
rf_pred |> dplyr::mutate(model="Random forest")
) |> dplyr::mutate(error=.pred-kemiskinan_persen)
err_summary9 <- error9 |> dplyr::group_by(model) |>
dplyr::summarise(RMSE=sqrt(mean(error^2)), MAE=mean(abs(error)), Bias=mean(error), MaxAbs=max(abs(error)), .groups="drop")
knitr::kable(err_summary9, digits=3, caption="Perbandingan distribusi error model")| model | RMSE | MAE | Bias | MaxAbs |
|---|---|---|---|---|
| Linear | 2.114 | 1.797 | 0.401 | 3.534 |
| Random forest | 1.896 | 1.510 | 0.464 | 3.876 |
ggplot2::ggplot(error9, ggplot2::aes(.pred, error)) +
ggplot2::geom_hline(yintercept=0,linetype=2) + ggplot2::geom_point(alpha=.75) +
ggplot2::facet_wrap(~model) + ggplot2::labs(title="Residual diagnostic pada holdout", x="Prediksi", y="Error prediksi")Jika random forest hanya memperbaiki RMSE sedikit tetapi jauh lebih sulit dijelaskan, model linear mungkin lebih berguna untuk dialog kebijakan. Sebaliknya, jika tujuan operasional adalah screening ribuan unit dan RF mengurangi false negatives secara substansial, kompleksitas tambahan dapat dibenarkan.
mtry dan min_n lalu bandingkan kinerja.Gunakan dataset yang sama untuk baseline linear model, regression tree, dan random forest. Pastikan split sama. Bandingkan RMSE/MAE, training time secara sederhana, dan interpretability. Beri rekomendasi model untuk deployment pemerintah daerah—boleh memilih model yang bukan paling akurat bila alasannya kuat.
Milestone model dimulai: minimal satu baseline interpretable dan satu model alternatif. Tim harus mendokumentasikan alasan perbandingan, bukan sekadar menambah algoritma.
Machine learning memberi fleksibilitas, bukan otomatis validitas. Keunggulannya harus dibuktikan pada data holdout dan dikaitkan dengan keputusan kebijakan.
Classification relevan saat outcome bersifat kategori: desa prioritas/nonprioritas, risiko tinggi/rendah, UMKM potensial/tidak, atau keberhasilan program. Namun threshold classification adalah keputusan yang membawa konsekuensi alokasi sumber daya.
Mahasiswa mampu menerapkan logistic regression dan classifier, membaca confusion matrix, precision, recall, specificity, F1, ROC-AUC, dan memilih threshold berdasarkan biaya kesalahan.
False negative dapat lebih mahal daripada false positive jika model digunakan untuk mendeteksi wilayah yang sangat rentan. Karena itu, accuracy saja tidak cukup, terutama bila kelas tidak seimbang.
Logistic regression:
dengan .
Precision dan recall:
F1:
Untuk , Logit model: Sehingga Odds ratio untuk kenaikan satu unit adalah , dengan prediktor lain tetap. Interpretasi odds ratio bukan perubahan probabilitas absolut yang konstan.
Likelihood Bernoulli: Negative log-likelihood / binary cross-entropy:
Dengan TP, TN, FP, FN:
Balanced accuracy: Untuk kelas prioritas yang jarang, accuracy dapat tinggi walaupun seluruh kasus prioritas gagal ditemukan.
Jika tindakan diberikan saat , expected classification cost pada validation data: Pilih yang meminimalkan biaya atau memenuhi kapasitas intervensi. Jika pemerintah hanya mampu menangani 15% wilayah, threshold dapat dikaitkan dengan kuantil risk score, tetapi keputusan itu harus transparan.
ROC memplot TPR vs FPR dengan AUC dapat dipahami sebagai probabilitas satu observasi positif acak memperoleh score lebih tinggi daripada observasi negatif acak. (Fawcett 2006)
AUC mengukur ranking discrimination, bukan calibration dan bukan manfaat kebijakan. Untuk kelas sangat imbalanced, precision–recall curve sering lebih informatif.
Prediksi terkalibrasi berarti di antara unit dengan , sekitar 20% benar-benar positif pada data serupa. Calibration intercept/slope dapat diperiksa melalui model Idealnya dan . Calibration penting jika probabilitas dipakai untuk alokasi sumber daya, bukan hanya ranking.
Threshold 0,5 bukan hukum alam. Jika anggaran hanya mampu mengintervensi 15% desa, threshold dapat ditetapkan berdasarkan kapasitas program dan tujuan, lalu kinerja serta fairness dinilai pada threshold itu.
Dari 200 wilayah/desa: TP=30, FN=10, FP=40, TN=120. Interpretasi: model menemukan 75% kasus prioritas, tetapi hanya 43% dari unit yang ditandai benar-benar prioritas berdasarkan label. Jika verifikasi lapangan murah, precision ini mungkin dapat diterima; jika intervensi mahal, threshold perlu ditinjau.
Jika threshold turun, secara umum sensitivity naik dan specificity turun. Pilih threshold dari validation, bukan test. Bila , : Bandingkan beberapa , lalu lakukan sanity check apakah jumlah unit terpilih sesuai kapasitas program.
Jika , odds ratio=2. Bila baseline probability 0.10, odds=0.111; setelah dua kali odds=0.222, probability=0.182. Kenaikan probability hanya 8.2 points. Bila baseline probability 0.50, odds=1 →2, probability=0.667, naik 16.7 points. Efek probability bergantung baseline.
Bagi prediksi menjadi deciles/bin. Untuk bin : Plot vs ; garis ideal . Untuk kebijakan risk-based, calibration dapat lebih penting daripada sedikit perbedaan AUC.
set.seed(260820)
prob <- runif(200)
y <- rbinom(200,1,prob)
thresholds <- c(.2,.3,.4,.5,.6)
threshold_table <- purrr::map_dfr(thresholds, function(t){
pred <- as.integer(prob>=t)
TP <- sum(pred==1 & y==1); FN <- sum(pred==0 & y==1)
FP <- sum(pred==1 & y==0); TN <- sum(pred==0 & y==0)
tibble(threshold=t,
sensitivity=TP/(TP+FN), specificity=TN/(TN+FP),
precision=ifelse(TP+FP==0,NA,TP/(TP+FP)),
selected=TP+FP, cost=4*FN+FP)
})
knitr::kable(threshold_table, digits=3)| threshold | sensitivity | specificity | precision | selected | cost |
|---|---|---|---|---|---|
| 0.2 | 0.980 | 0.314 | 0.578 | 166 | 78 |
| 0.3 | 0.939 | 0.500 | 0.643 | 143 | 75 |
| 0.4 | 0.898 | 0.588 | 0.677 | 130 | 82 |
| 0.5 | 0.827 | 0.735 | 0.750 | 108 | 95 |
| 0.6 | 0.724 | 0.833 | 0.807 | 88 | 125 |
Tidak ada “metric terbaik” tanpa decision context. (Fawcett 2006)
library(tidymodels)
set.seed(260810)
# Membaca data simulasi dan menstandarkan label kelas.
# "prioritas" sengaja ditempatkan sebagai level pertama karena dalam yardstick
# level pertama adalah event class secara default.
desa <- read_csv("data/simulasi_klasifikasi_desa.csv", show_col_types = FALSE) |>
mutate(
.label_raw = tolower(trimws(as.character(prioritas_intervensi))),
prioritas_intervensi = case_when(
.label_raw %in% c("1", "prioritas", "ya", "yes", "true") ~ "prioritas",
.label_raw %in% c("0", "non", "non-prioritas", "tidak", "no", "false") ~ "non",
TRUE ~ NA_character_
)
) |>
select(-.label_raw)
# Guardrail pedagogis: ROC hanya terdefinisi jika kedua kelas tersedia.
# Jika file simulasi lama memiliki kelas yang terlalu timpang atau labelnya tidak
# dikenali, label simulasi dibentuk ulang dari skor kerentanan regional.
zscore_safe <- function(x) {
sx <- stats::sd(x, na.rm = TRUE)
mx <- mean(x, na.rm = TRUE)
if (!is.finite(sx) || sx == 0) return(rep(0, length(x)))
(x - mx) / sx
}
class_count <- desa |>
filter(!is.na(prioritas_intervensi)) |>
count(prioritas_intervensi, name = "n")
if (nrow(class_count) < 2 || min(class_count$n) < 8 || anyNA(desa$prioritas_intervensi)) {
skor_kerentanan <- with(
desa,
1.00 * zscore_safe(kemiskinan_persen) +
0.55 * zscore_safe(jarak_pusat_km) -
0.45 * zscore_safe(akses_kesehatan) -
0.40 * zscore_safe(kualitas_jalan) -
0.50 * zscore_safe(internet_persen)
)
batas_prioritas <- as.numeric(stats::quantile(
skor_kerentanan, probs = 0.70, na.rm = TRUE, names = FALSE
))
desa <- desa |>
mutate(
prioritas_intervensi = if_else(
skor_kerentanan >= batas_prioritas, "prioritas", "non"
)
)
}
desa <- desa |>
mutate(
prioritas_intervensi = factor(
prioritas_intervensi,
levels = c("prioritas", "non")
)
)
# Tampilkan keseimbangan kelas sebelum pemodelan.
class_count <- desa |>
count(prioritas_intervensi, name = "n") |>
mutate(proporsi = n / sum(n))
knitr::kable(
class_count, digits = 3,
caption = "Distribusi kelas sebelum train-test split"
)| prioritas_intervensi | n | proporsi |
|---|---|---|
| prioritas | 240 | 0.3 |
| non | 560 | 0.7 |
# Stratified split mempertahankan proporsi kelas pada training dan testing.
sp <- initial_split(desa, prop = .8, strata = prioritas_intervensi)
trc <- training(sp)
tec <- testing(sp)
# Pemeriksaan eksplisit agar evaluasi classification tidak berjalan pada test set
# yang hanya berisi satu kelas.
if (dplyr::n_distinct(tec$prioritas_intervensi) < 2) {
stop(
"Testing set hanya memiliki satu kelas. Periksa distribusi prioritas_intervensi ",
"atau gunakan data simulasi yang telah diperbarui."
)
}
knitr::kable(
tec |> count(prioritas_intervensi, name = "n_test"),
caption = "Distribusi kelas pada testing set"
)| prioritas_intervensi | n_test |
|---|---|
| prioritas | 48 |
| non | 112 |
logit <- logistic_reg() |>
set_engine("glm") |>
fit(
prioritas_intervensi ~ kemiskinan_persen + jarak_pusat_km +
akses_kesehatan + kualitas_jalan + internet_persen,
data = trc
)
pr <- predict(logit, tec, type = "prob") |>
bind_cols(predict(logit, tec, type = "class")) |>
bind_cols(tec |> select(prioritas_intervensi))
conf_mat(pr, truth = prioritas_intervensi, estimate = .pred_class)#> Truth
#> Prediction prioritas non
#> prioritas 47 0
#> non 1 112
metric_set(accuracy, sens, spec, precision, recall, f_meas)(
pr,
truth = prioritas_intervensi,
estimate = .pred_class
)#> # A tibble: 6 × 3
#> .metric .estimator .estimate
#> <chr> <chr> <dbl>
#> 1 accuracy binary 0.994
#> 2 sens binary 0.979
#> 3 spec binary 1
#> 4 precision binary 1
#> 5 recall binary 0.979
#> 6 f_meas binary 0.989
# AUC dan ROC menggunakan "prioritas" sebagai event class.
auc_out <- yardstick::roc_auc(
pr,
truth = prioritas_intervensi,
.pred_prioritas,
event_level = "first"
)
knitr::kable(auc_out, digits = 3, caption = "ROC AUC pada testing set")| .metric | .estimator | .estimate |
|---|---|---|
| roc_auc | binary | 1 |
roc_out <- yardstick::roc_curve(
pr,
truth = prioritas_intervensi,
.pred_prioritas,
event_level = "first"
)
autoplot(roc_out) +
ggplot2::geom_abline(linetype = 2, alpha = .6) +
ggplot2::labs(
title = "ROC Curve — Klasifikasi Prioritas Intervensi",
subtitle = "Event class: prioritas; data simulasi",
x = "1 - Specificity",
y = "Sensitivity"
)Classification dapat dibentuk dari data nyata dengan mendefinisikan label kebijakan, misalnya kabupaten dengan poverty rate di atas quantile 75 sebagai screening target. Tetapi label berbasis cut-off statistik bukan ground truth kebijakan; mahasiswa wajib menjelaskan bahwa label dibuat untuk latihan dan tidak otomatis valid untuk penetapan program.
Kartu dataset real.
SI.POV.NAPR.ZS = poverty rate; label latihan prioritas=1 dibuat dari cut-off eksplisit (mis. kuantil 75), sementara predictors dipilih dari indikator yang tersedia sebelum keputusan.# Threshold 0.30 untuk meningkatkan sensitivitas terhadap kelas prioritas.
pr2 <- pr |>
mutate(.pred_30 = factor(if_else(.pred_prioritas >= .30, "prioritas", "non"),
levels = c("prioritas", "non")))
conf_mat(pr2, truth = prioritas_intervensi, estimate = .pred_30)#> Truth
#> Prediction prioritas non
#> prioritas 47 0
#> non 1 112
class10 <- pr |>
dplyr::mutate(.pred_class = factor(ifelse(.pred_prioritas >= .5, "prioritas", "non"), levels=levels(prioritas_intervensi)))
cm10 <- yardstick::conf_mat(class10, truth=prioritas_intervensi, estimate=.pred_class)
cm10#> Truth
#> Prediction prioritas non
#> prioritas 47 0
#> non 1 112
yardstick::metric_set(yardstick::accuracy, yardstick::sens, yardstick::spec, yardstick::ppv, yardstick::npv, yardstick::f_meas)(
class10, truth=prioritas_intervensi, estimate=.pred_class, event_level="first"
) |> knitr::kable(digits=3, caption="Metric klasifikasi pada threshold 0,50")| .metric | .estimator | .estimate |
|---|---|---|
| accuracy | binary | 0.994 |
| sens | binary | 0.979 |
| spec | binary | 1.000 |
| ppv | binary | 1.000 |
| npv | binary | 0.991 |
| f_meas | binary | 0.989 |
ggplot2::ggplot(pr, ggplot2::aes(.pred_prioritas, fill=prioritas_intervensi)) +
ggplot2::geom_histogram(position="identity", alpha=.55, bins=12) +
ggplot2::labs(title="Distribusi probabilitas prediksi menurut kelas aktual", x="Predicted probability: prioritas", fill="Aktual")cal10 <- pr |>
dplyr::mutate(bin=dplyr::ntile(.pred_prioritas, 5), y=as.integer(prioritas_intervensi=="prioritas")) |>
dplyr::group_by(bin) |>
dplyr::summarise(mean_pred=mean(.pred_prioritas), observed_rate=mean(y), n=dplyr::n(), .groups="drop")
knitr::kable(cal10, digits=3, caption="Calibration table per kuintil probabilitas")| bin | mean_pred | observed_rate | n |
|---|---|---|---|
| 1 | 0.000 | 0.0 | 32 |
| 2 | 0.000 | 0.0 | 32 |
| 3 | 0.000 | 0.0 | 32 |
| 4 | 0.469 | 0.5 | 32 |
| 5 | 1.000 | 1.0 | 32 |
ggplot2::ggplot(cal10, ggplot2::aes(mean_pred, observed_rate)) +
ggplot2::geom_abline(slope=1,intercept=0,linetype=2) + ggplot2::geom_point(size=3) + ggplot2::geom_line() +
ggplot2::coord_equal(xlim=c(0,1),ylim=c(0,1)) +
ggplot2::labs(title="Calibration plot", x="Mean predicted probability", y="Observed event rate")Jika recall meningkat dari 0,60 menjadi 0,82 setelah threshold diturunkan, lebih banyak wilayah rentan berhasil terdeteksi, tetapi false positives juga naik. Implikasinya adalah kebutuhan verifikasi lapangan lebih besar. Pilihan threshold harus dibahas bersama kapasitas program.
Definisikan binary priority outcome dari kasus regional secara transparan. Fit logistic regression dan satu model non-linear. Bandingkan ROC-AUC, PR behavior, sensitivity, precision, calibration, dan minimal tiga threshold. Pilih threshold dengan alasan kapasitas/biaya kebijakan.
Kisi-kisi: tree impurity; random forest; boosting; logistic probability/odds; confusion matrix; sensitivity/specificity; precision/F1; ROC-AUC; calibration; threshold berbasis cost.
Jika proyek menggunakan classification, tim harus menyertakan cost-of-error statement: siapa yang dirugikan oleh FP/FN dan bagaimana threshold dipilih.
Classification adalah mekanisme keputusan. Metric dan threshold harus dikaitkan dengan kapasitas program, risiko, fairness, dan prosedur verifikasi manusia.
Clustering digunakan untuk menyusun tipologi wilayah berdasarkan kemiripan profil indikator, bukan untuk menentukan peringkat “baik–buruk”. Dalam inovasi regional, segmentasi dapat membantu pemerintah merancang paket intervensi yang berbeda untuk kelompok daerah dengan kebutuhan berbeda. Karena hasil cluster sensitif terhadap pemilihan indikator, skala, distance metric, jumlah cluster, dan initialization, analisis harus menampilkan proses pemilihan cluster dan profil akhirnya secara transparan. (Kaufman dan Rousseeuw 1990; Hastie, Tibshirani, dan Friedman 2009; James dkk. 2021)
Setelah pertemuan ini mahasiswa mampu:
Untuk wilayah dengan indikator, tulis vektor fitur sebagai . Karena indikator memiliki unit berbeda, fitur umumnya distandardisasi:
dengan rata-rata indikator dan simpangan bakunya.
K-means membagi observasi ke cluster dengan meminimumkan within-cluster sum of squares:
di mana adalah centroid cluster .
Untuk observasi , silhouette didefinisikan sebagai
dengan rata-rata jarak ke anggota cluster sendiri dan rata-rata jarak minimum ke cluster lain. Nilai mendekati 1 menunjukkan pemisahan yang baik, mendekati 0 menunjukkan observasi berada di perbatasan, dan negatif mengindikasikan kemungkinan salah pengelompokan. (Rousseeuw 1987)
Hierarchical clustering dengan Ward meminimumkan kenaikan variasi dalam-cluster ketika dua kelompok digabung. Untuk dua cluster dan , perubahan error sum of squares dapat ditulis secara intuitif sebagai fungsi jarak centroid dan ukuran kedua cluster. Karena itu Ward cocok sebagai pembanding K-means ketika tujuan utamanya adalah cluster kompak.
Cluster merupakan ringkasan geometri data yang dipilih analis. Jika fitur hanya ekonomi, hasilnya terutama tipologi ekonomi; jika ditambah pendidikan, kesehatan, digitalisasi, dan UMKM, definisi “kemiripan wilayah” berubah. Karena itu pemilihan fitur adalah keputusan substantif, bukan sekadar teknis.
reg11 <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
dplyr::filter(tahun == 2025) |>
dplyr::select(
wilayah, pdrb_perkapita_juta, kemiskinan_persen, tpt_persen,
ipm, internet_persen, umkm_per_1000, indeks_inovasi
) |>
tidyr::drop_na()
vars11 <- c("pdrb_perkapita_juta", "kemiskinan_persen", "tpt_persen",
"ipm", "internet_persen", "umkm_per_1000", "indeks_inovasi")
ringkas11 <- reg11 |>
dplyr::summarise(dplyr::across(
dplyr::all_of(vars11),
list(mean = mean, sd = sd, min = min, median = median, max = max)
)) |>
tidyr::pivot_longer(dplyr::everything(), names_to = c("indikator", ".value"), names_pattern = "(.*)_(mean|sd|min|median|max)$")
knitr::kable(ringkas11, digits = 2, caption = "Statistik deskriptif indikator sebelum clustering")| indikator | mean | sd | min | median | max |
|---|---|---|---|---|---|
| pdrb_perkapita_juta | 49.22 | 10.86 | 24.04 | 50.90 | 66.15 |
| kemiskinan_persen | 9.89 | 1.75 | 6.01 | 9.84 | 13.05 |
| tpt_persen | 8.07 | 1.10 | 6.69 | 7.75 | 10.35 |
| ipm | 70.74 | 1.18 | 67.78 | 70.68 | 73.42 |
| internet_persen | 83.44 | 8.19 | 65.66 | 85.60 | 96.99 |
| umkm_per_1000 | 38.60 | 5.12 | 29.37 | 39.66 | 48.99 |
| indeks_inovasi | 68.25 | 4.12 | 60.29 | 69.00 | 76.82 |
Output ini wajib dibaca sebelum standardisasi. Perbedaan rentang yang besar menjelaskan mengapa Euclidean distance pada skala asli dapat didominasi variabel tertentu.
cor11 <- cor(reg11 |> dplyr::select(dplyr::all_of(vars11)), use = "pairwise.complete.obs")
cor_long11 <- as.data.frame(as.table(cor11))
ggplot2::ggplot(cor_long11, ggplot2::aes(Var1, Var2, fill = Freq)) +
ggplot2::geom_tile() +
ggplot2::geom_text(ggplot2::aes(label = sprintf("%.2f", Freq)), size = 3) +
ggplot2::scale_fill_gradient2(limits = c(-1, 1), midpoint = 0) +
ggplot2::coord_equal() +
ggplot2::labs(title = "Korelasi antarindikator sebelum clustering", x = NULL, y = NULL, fill = "r") +
ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))Korelasi tinggi tidak otomatis membuat indikator harus dibuang, tetapi fitur yang sangat redundan dapat memberi bobot geometris berlebih pada satu dimensi substantif.
X11 <- scale(reg11 |> dplyr::select(dplyr::all_of(vars11)))
scale_check11 <- tibble::tibble(
indikator = colnames(X11),
mean_z = apply(X11, 2, mean),
sd_z = apply(X11, 2, sd)
)
knitr::kable(scale_check11, digits = 4, caption = "Pemeriksaan hasil standardisasi")| indikator | mean_z | sd_z |
|---|---|---|
| pdrb_perkapita_juta | 0 | 1 |
| kemiskinan_persen | 0 | 1 |
| tpt_persen | 0 | 1 |
| ipm | 0 | 1 |
| internet_persen | 0 | 1 |
| umkm_per_1000 | 0 | 1 |
| indeks_inovasi | 0 | 1 |
Secara numerik, setiap kolom hasil z-score seharusnya memiliki rata-rata mendekati 0 dan simpangan baku mendekati 1.
set.seed(260811)
d11 <- stats::dist(X11)
eval_k11 <- purrr::map_dfr(2:6, function(k) {
km_tmp <- stats::kmeans(X11, centers = k, nstart = 100)
sil_tmp <- cluster::silhouette(km_tmp$cluster, d11)
tibble::tibble(
K = k,
total_WSS = km_tmp$tot.withinss,
avg_silhouette = mean(sil_tmp[, "sil_width"]),
betweenSS_ratio = km_tmp$betweenss / km_tmp$totss
)
})
knitr::kable(eval_k11, digits = 3, caption = "Perbandingan kandidat jumlah cluster")| K | total_WSS | avg_silhouette | betweenSS_ratio |
|---|---|---|---|
| 2 | 97.396 | 0.372 | 0.465 |
| 3 | 72.859 | 0.290 | 0.600 |
| 4 | 62.985 | 0.265 | 0.654 |
| 5 | 54.639 | 0.202 | 0.700 |
| 6 | 47.707 | 0.196 | 0.738 |
ggplot2::ggplot(eval_k11, ggplot2::aes(K, total_WSS)) +
ggplot2::geom_line(linewidth = 1) +
ggplot2::geom_point(size = 2.7) +
ggplot2::scale_x_continuous(breaks = 2:6) +
ggplot2::labs(title = "Elbow plot", subtitle = "WSS selalu turun; cari perubahan kemiringan yang masuk akal", y = "Total within-cluster SS")ggplot2::ggplot(eval_k11, ggplot2::aes(K, avg_silhouette)) +
ggplot2::geom_line(linewidth = 1) +
ggplot2::geom_point(size = 2.7) +
ggplot2::scale_x_continuous(breaks = 2:6) +
ggplot2::labs(title = "Rata-rata silhouette untuk beberapa nilai K", y = "Average silhouette width")Pemilihan tidak didasarkan pada satu grafik saja. Dalam contoh ini, kandidat awal dipilih dari silhouette tertinggi, lalu diperiksa kembali dari sisi interpretabilitas dan kegunaan kebijakan.
k11 <- eval_k11 |> dplyr::slice_max(avg_silhouette, n = 1, with_ties = FALSE) |> dplyr::pull(K)
set.seed(260811)
km11 <- stats::kmeans(X11, centers = k11, nstart = 200)
fit_summary11 <- tibble::tibble(
jumlah_cluster = k11,
total_SS = km11$totss,
within_SS = km11$tot.withinss,
between_SS = km11$betweenss,
proporsi_between_SS = km11$betweenss / km11$totss
)
knitr::kable(fit_summary11, digits = 3, caption = "Ringkasan fit K-means final")| jumlah_cluster | total_SS | within_SS | between_SS | proporsi_between_SS |
|---|---|---|---|---|
| 2 | 182 | 97.396 | 84.604 | 0.465 |
membership11 <- reg11 |>
dplyr::mutate(cluster = factor(km11$cluster)) |>
dplyr::arrange(cluster, dplyr::desc(kemiskinan_persen)) |>
dplyr::select(wilayah, cluster, dplyr::all_of(vars11))
knitr::kable(membership11, digits = 2, caption = "Keanggotaan cluster dan indikator setiap wilayah")| wilayah | cluster | pdrb_perkapita_juta | kemiskinan_persen | tpt_persen | ipm | internet_persen | umkm_per_1000 | indeks_inovasi |
|---|---|---|---|---|---|---|---|---|
| Wilayah_23 | 1 | 41.20 | 13.05 | 7.05 | 69.78 | 72.33 | 35.41 | 70.57 |
| Wilayah_15 | 1 | 36.80 | 12.64 | 7.56 | 69.35 | 75.14 | 30.74 | 63.42 |
| Wilayah_19 | 1 | 34.46 | 11.81 | 7.54 | 70.19 | 76.92 | 31.66 | 63.60 |
| Wilayah_25 | 1 | 41.46 | 11.67 | 6.69 | 71.38 | 69.83 | 33.05 | 64.86 |
| Wilayah_06 | 1 | 43.34 | 11.64 | 7.25 | 69.97 | 84.58 | 36.00 | 60.29 |
| Wilayah_21 | 1 | 24.04 | 11.24 | 6.74 | 67.78 | 65.66 | 31.20 | 60.84 |
| Wilayah_17 | 1 | 39.58 | 10.55 | 7.31 | 70.99 | 79.71 | 35.69 | 69.55 |
| Wilayah_01 | 1 | 31.61 | 9.99 | 7.12 | 70.11 | 76.88 | 33.97 | 63.79 |
| Wilayah_08 | 1 | 41.66 | 8.98 | 7.08 | 69.54 | 73.56 | 29.37 | 61.57 |
| Wilayah_07 | 2 | 44.19 | 12.94 | 8.68 | 71.95 | 78.72 | 43.01 | 67.37 |
| Wilayah_09 | 2 | 45.12 | 10.97 | 9.63 | 70.38 | 85.60 | 40.47 | 68.69 |
| Wilayah_27 | 2 | 52.01 | 10.10 | 7.65 | 69.34 | 90.37 | 40.48 | 69.92 |
| Wilayah_05 | 2 | 46.80 | 10.08 | 8.20 | 70.43 | 85.62 | 40.55 | 69.04 |
| Wilayah_24 | 2 | 53.89 | 10.06 | 8.67 | 71.73 | 88.05 | 36.22 | 71.50 |
| Wilayah_18 | 2 | 53.71 | 9.84 | 7.75 | 70.68 | 84.59 | 40.48 | 67.93 |
| Wilayah_20 | 2 | 62.74 | 9.66 | 6.79 | 70.86 | 93.39 | 41.84 | 71.42 |
| Wilayah_26 | 2 | 54.20 | 9.61 | 9.63 | 71.71 | 75.11 | 38.96 | 65.99 |
| Wilayah_16 | 2 | 50.13 | 9.53 | 9.09 | 70.26 | 87.40 | 40.24 | 67.09 |
| Wilayah_22 | 2 | 59.50 | 9.44 | 8.76 | 71.33 | 89.43 | 44.67 | 74.23 |
| Wilayah_13 | 2 | 50.90 | 8.99 | 7.88 | 70.08 | 82.50 | 39.66 | 69.00 |
| Wilayah_04 | 2 | 54.51 | 8.57 | 7.38 | 69.88 | 85.61 | 37.62 | 71.90 |
| Wilayah_10 | 2 | 66.15 | 8.52 | 8.09 | 71.62 | 96.99 | 46.95 | 70.22 |
| Wilayah_14 | 2 | 64.33 | 8.19 | 10.03 | 72.54 | 95.23 | 42.66 | 71.74 |
| Wilayah_12 | 2 | 57.69 | 7.98 | 10.35 | 71.12 | 93.96 | 48.99 | 72.47 |
| Wilayah_02 | 2 | 65.25 | 7.68 | 7.01 | 73.42 | 91.38 | 41.63 | 70.70 |
| Wilayah_11 | 2 | 61.14 | 7.16 | 7.94 | 72.38 | 87.64 | 45.55 | 76.82 |
| Wilayah_03 | 2 | 52.52 | 6.01 | 9.96 | 71.13 | 86.70 | 35.17 | 68.19 |
Tabel di atas sengaja ditampilkan lengkap. Pada HTML, tabel lebar dapat digeser ke kiri–kanan sehingga nama wilayah dan seluruh indikator tetap dapat diperiksa.
profile11 <- membership11 |>
dplyr::group_by(cluster) |>
dplyr::summarise(
n = dplyr::n(),
dplyr::across(dplyr::all_of(vars11), mean),
.groups = "drop"
)
knitr::kable(profile11, digits = 2, caption = "Profil rata-rata setiap cluster pada skala asli")| cluster | n | pdrb_perkapita_juta | kemiskinan_persen | tpt_persen | ipm | internet_persen | umkm_per_1000 | indeks_inovasi |
|---|---|---|---|---|---|---|---|---|
| 1 | 9 | 37.13 | 11.29 | 7.15 | 69.90 | 74.96 | 33.01 | 64.28 |
| 2 | 18 | 55.27 | 9.19 | 8.53 | 71.16 | 87.68 | 41.40 | 70.24 |
profile_z11 <- as.data.frame(X11) |>
dplyr::mutate(cluster = factor(km11$cluster)) |>
dplyr::group_by(cluster) |>
dplyr::summarise(dplyr::across(dplyr::everything(), mean), .groups = "drop") |>
tidyr::pivot_longer(-cluster, names_to = "indikator", values_to = "mean_z")
ggplot2::ggplot(profile_z11, ggplot2::aes(indikator, cluster, fill = mean_z)) +
ggplot2::geom_tile() +
ggplot2::geom_text(ggplot2::aes(label = sprintf("%.2f", mean_z)), size = 3.2) +
ggplot2::scale_fill_gradient2(midpoint = 0) +
ggplot2::labs(title = "Heatmap profil cluster", subtitle = "Nilai adalah rata-rata z-score; positif berarti di atas rata-rata keseluruhan", x = NULL, y = "Cluster", fill = "Mean z") +
ggplot2::theme(axis.text.x = ggplot2::element_text(angle = 45, hjust = 1))Heatmap lebih berguna untuk penamaan cluster daripada centroid mentah karena seluruh indikator telah berada pada skala yang sebanding.
sil11 <- cluster::silhouette(km11$cluster, d11)
sil_tbl11 <- tibble::as_tibble(as.data.frame(sil11)) |>
dplyr::mutate(wilayah = reg11$wilayah) |>
dplyr::arrange(sil_width)
knitr::kable(
sil_tbl11 |> dplyr::select(wilayah, cluster, neighbor, sil_width),
digits = 3,
caption = "Silhouette setiap wilayah; nilai rendah/negatif perlu diperiksa"
)| wilayah | cluster | neighbor | sil_width |
|---|---|---|---|
| Wilayah_07 | 2 | 1 | 0.037 |
| Wilayah_17 | 1 | 2 | 0.171 |
| Wilayah_26 | 2 | 1 | 0.213 |
| Wilayah_09 | 2 | 1 | 0.252 |
| Wilayah_27 | 2 | 1 | 0.252 |
| Wilayah_13 | 2 | 1 | 0.254 |
| Wilayah_04 | 2 | 1 | 0.278 |
| Wilayah_05 | 2 | 1 | 0.280 |
| Wilayah_18 | 2 | 1 | 0.302 |
| Wilayah_03 | 2 | 1 | 0.319 |
| Wilayah_16 | 2 | 1 | 0.344 |
| Wilayah_23 | 1 | 2 | 0.362 |
| Wilayah_06 | 1 | 2 | 0.367 |
| Wilayah_24 | 2 | 1 | 0.381 |
| Wilayah_20 | 2 | 1 | 0.389 |
| Wilayah_02 | 2 | 1 | 0.389 |
| Wilayah_25 | 1 | 2 | 0.456 |
| Wilayah_11 | 2 | 1 | 0.456 |
| Wilayah_08 | 1 | 2 | 0.456 |
| Wilayah_12 | 2 | 1 | 0.472 |
| Wilayah_21 | 1 | 2 | 0.483 |
| Wilayah_14 | 2 | 1 | 0.489 |
| Wilayah_10 | 2 | 1 | 0.494 |
| Wilayah_01 | 1 | 2 | 0.511 |
| Wilayah_22 | 2 | 1 | 0.520 |
| Wilayah_15 | 1 | 2 | 0.560 |
| Wilayah_19 | 1 | 2 | 0.568 |
ggplot2::ggplot(sil_tbl11, ggplot2::aes(reorder(wilayah, sil_width), sil_width, fill = factor(cluster))) +
ggplot2::geom_col() +
ggplot2::coord_flip() +
ggplot2::geom_hline(yintercept = 0, linetype = 2) +
ggplot2::labs(title = "Silhouette per wilayah", x = NULL, y = "Silhouette width", fill = "Cluster")Wilayah dengan silhouette dekat nol adalah kasus transisi; kebijakan sebaiknya tidak memperlakukan batas cluster sebagai kategori keras.
pca11 <- stats::prcomp(X11, center = FALSE, scale. = FALSE)
pca_score11 <- tibble::as_tibble(pca11$x[, 1:2]) |>
dplyr::mutate(wilayah = reg11$wilayah, cluster = factor(km11$cluster))
ggplot2::ggplot(pca_score11, ggplot2::aes(PC1, PC2, colour = cluster)) +
ggplot2::geom_point(size = 3, alpha = .85) +
ggplot2::labs(
title = "Visualisasi cluster pada dua komponen utama",
subtitle = paste0("PC1 + PC2 menjelaskan ", round(100 * sum(summary(pca11)$importance[2,1:2]), 1), "% variasi terstandardisasi"),
colour = "Cluster"
)Plot PCA hanya proyeksi dua dimensi; keputusan K-means tetap menggunakan seluruh indikator terstandardisasi, bukan hanya PC1–PC2.
hc11 <- stats::hclust(d11, method = "ward.D2")
plot(hc11, labels = reg11$wilayah, cex = .65,
main = "Dendrogram hierarchical clustering — Ward.D2", xlab = "", sub = "")
rect.hclust(hc11, k = k11, border = 2:(k11 + 1))hc_group11 <- stats::cutree(hc11, k = k11)
agreement11 <- table(KMeans = km11$cluster, Ward = hc_group11)
knitr::kable(as.data.frame.matrix(agreement11), caption = "Tabulasi silang K-means versus Ward")| 1 | 2 |
|---|---|
| 9 | 0 |
| 0 | 18 |
Perbedaan keanggotaan tidak selalu berarti salah. Ia menunjukkan bahwa tipologi sensitif terhadap definisi cluster dan perlu dibaca sebagai alat eksplorasi.
Interpretasi dilakukan dari tabel profil dan heatmap, bukan dari nomor cluster. Misalnya, sebuah cluster dengan kemiskinan dan TPT di atas rata-rata serta internet dan IPM di bawah rata-rata dapat diberi label “tekanan sosial-ekonomi tinggi–kapabilitas layanan lebih rendah”. Cluster dengan PDRB dan internet tinggi tetapi TPT tetap tinggi dapat menunjukkan “ekonomi kuat–mismatch pasar kerja”. Kebijakan untuk kedua kelompok tidak seharusnya sama.
Cluster tidak membuktikan mekanisme sebab-akibat. Setelah tipologi terbentuk, mahasiswa harus kembali ke data sektoral, konteks institusi, dan informasi lapangan untuk memeriksa apakah paket kebijakan yang diusulkan masuk akal.
Gunakan 5–8 indikator pada capstone project. Tampilkan statistik deskriptif, korelasi, alasan standardisasi, evaluasi , tabel membership lengkap, profil cluster, silhouette, heatmap, dan minimal satu sensitivity check. Akhiri dengan satu halaman strategi kebijakan yang berbeda untuk setiap tipologi.
Pertemuan 11 menyiapkan regional segmentation package sebagai bahan M5: fitur terpilih, evaluasi , membership, profil, visualisasi, dan sensitivity analysis. M5 baru dinilai pada pertemuan 13 setelah modul heterogenitas regional dilengkapi.
Clustering bernilai ketika ia mengubah data multivariat menjadi tipologi yang dapat dipahami dan diuji. Analisis yang hanya menghasilkan nomor cluster tanpa profil, silhouette, membership, dan sensitivity check belum cukup untuk jenjang magister.
Indikator pembangunan sering saling berkorelasi: pendidikan, kesehatan, internet, pendapatan, dan layanan dasar bergerak bersama. PCA membantu mereduksi dimensi dan mengidentifikasi kombinasi laten, tetapi komponen harus ditafsirkan dengan hati-hati.
Mahasiswa mampu melakukan PCA pada data yang distandardisasi, membaca variance explained dan loadings, serta menggunakan komponen untuk visualisasi/segmentasi tanpa kehilangan interpretasi kebijakan.
PCA mencari arah linear yang menjelaskan variasi maksimum. PC1 adalah kombinasi linear dengan variance terbesar, PC2 orthogonal terhadap PC1 dan menjelaskan variance terbesar berikutnya. PCA tidak secara otomatis menghasilkan “indeks pembangunan” yang normatif.
Untuk data terpusat , covariance matrix
PCA menyelesaikan
di mana eigenvector/loading PC ke- dan variance yang dijelaskan. Skor komponen:
Untuk data berukuran , pusatkan setiap kolom: Covariance matrix: Jika variabel memiliki unit/skala sangat berbeda, gunakan correlation PCA dengan data standardisasi .
PCA mencari arah unit yang memaksimalkan variance proyeksi: Solusinya adalah eigenvector dari : dengan .
Score principal component: Loading menunjukkan kontribusi variabel pada komponen .
Pemilihan jumlah komponen tidak boleh hanya berdasarkan threshold 80%/90%; interpretability dan tujuan project harus dipertimbangkan. (Jolliffe dan Cadima 2016)
Dengan komponen: Reconstruction error: PCA memilih subspace linear yang meminimalkan squared reconstruction error, tetapi komponen yang menjelaskan variance tinggi belum tentu paling relevan untuk outcome kebijakan tertentu.
Skor PC1 dapat dipakai sebagai data-driven index: Namun tanda eigenvector dapat terbalik tanpa mengubah solusi; orientasi indeks harus ditentukan agar “lebih tinggi” memiliki arti substantif konsisten. PCA juga menimbang berdasarkan struktur covariance, bukan prioritas normatif. Bandingkan dengan indeks berbobot teori dan lakukan sensitivity analysis. (OECD dan Joint Research Centre, European Commission 2008)
Sudut antar loading vector secara kasar berkaitan dengan korelasi: arah sejalan ≈ korelasi positif, berlawanan ≈ negatif, hampir tegak lurus ≈ korelasi kecil. Panjang dan skala biplot bergantung implementasi, jadi interpretasi harus mengikuti definisi scaling perangkat lunak.
Jika internet, IPM, pendidikan, dan akses kesehatan semuanya tinggi bersama, PC1 dapat menangkap “kapabilitas layanan/manusia” secara statistik. Tetapi penamaan tersebut harus didukung pola loading, bukan asumsi.
Misalkan covariance matrix standardized dua indikator adalah Eigenvalue memenuhi : Total variance=2, sehingga Eigenvector pertama proporsional , artinya PC1 kira-kira rata-rata standardized kedua indikator; PC2 menangkap kontras di antara keduanya.
Jika adalah eigenvector, juga eigenvector dengan eigenvalue sama. Karena itu software dapat memberikan PC1 dengan tanda berlawanan tanpa mengubah geometri. Untuk indeks, pilih orientasi agar makna substantif konsisten dan dokumentasikan pembalikan tanda.
Jika variabel berbeda unit, covariance PCA dapat didominasi variabel variance besar. Correlation PCA ekuivalen PCA pada standardized. Namun standardisasi menganggap satu SD setiap variabel comparable; jika measurement reliability berbeda, pertimbangkan hal tersebut dalam interpretasi.
Dengan komponen, prediksi data standardized: Residual reconstruction menunjukkan informasi yang tidak ditangkap komponen. Wilayah dengan reconstruction error tinggi bisa merupakan pola unik/outlier yang justru penting secara kebijakan.
xp <- panel |> filter(tahun==2025) |>
select(kemiskinan_persen, tpt_persen, internet_persen, ipm, indeks_inovasi)
pca <- prcomp(xp, center=TRUE, scale.=TRUE)
summary(pca)#> Importance of components:
#> PC1 PC2 PC3 PC4 PC5
#> Standard deviation 1.7221 0.8432 0.7656 0.6708 0.53601
#> Proportion of Variance 0.5931 0.1422 0.1172 0.0900 0.05746
#> Cumulative Proportion 0.5931 0.7353 0.8525 0.9425 1.00000
#> PC1 PC2 PC3
#> kemiskinan_persen -0.443 -0.003 -0.696
#> tpt_persen 0.367 0.893 -0.190
#> internet_persen 0.501 -0.108 0.215
#> ipm 0.439 -0.217 -0.645
#> indeks_inovasi 0.475 -0.379 -0.133
Baca sdev^2 sebagai eigenvalue (untuk covariance matrix dari data transformed sesuai prcomp), rotation sebagai loading/eigenvectors, dan x sebagai score.
Jika PC1 memberi loading besar pada internet dan IPM karena variance/correlation dominan, tetapi stakeholder menilai akses kesehatan normatif sangat penting, PC1 tidak otomatis menggantikan indeks teori. Laporkan dua pendekatan dan sensitivitas. (Jolliffe dan Cadima 2016; OECD dan Joint Research Centre, European Commission 2008)
reg <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
filter(tahun == 2025)
X <- reg |> select(ipm, internet_persen, indeks_pendidikan, akses_kesehatan, pdrb_perkapita_juta, umkm_per_1000)
pca <- prcomp(X, center = TRUE, scale. = TRUE)
summary(pca)#> Importance of components:
#> PC1 PC2 PC3 PC4 PC5 PC6
#> Standard deviation 2.0253 0.8835 0.72790 0.58744 0.39925 0.28818
#> Proportion of Variance 0.6837 0.1301 0.08831 0.05751 0.02657 0.01384
#> Cumulative Proportion 0.6837 0.8138 0.90208 0.95959 0.98616 1.00000
| PC1 | PC2 | PC3 | |
|---|---|---|---|
| ipm | 0.400 | 0.240 | 0.544 |
| internet_persen | 0.417 | -0.503 | 0.002 |
| indeks_pendidikan | 0.402 | 0.401 | 0.345 |
| akses_kesehatan | 0.347 | 0.597 | -0.633 |
| pdrb_perkapita_juta | 0.454 | -0.267 | 0.087 |
| umkm_per_1000 | 0.422 | -0.318 | -0.420 |
INDO-DAPOER menyediakan banyak indikator yang secara substantif saling terkait. Sebelum PCA, pilih satu periode dan pastikan kelengkapan data memadai. Jangan mencampur level provinsi dan kabupaten atau indikator dengan tahun berbeda tanpa justifikasi.
Kartu dataset real.
eigen12 <- pca$sdev^2
pve12 <- eigen12/sum(eigen12)
eigen_tbl12 <- tibble::tibble(
PC=paste0("PC",seq_along(eigen12)), eigenvalue=eigen12,
PVE=pve12, cumulative_PVE=cumsum(pve12)
)
knitr::kable(eigen_tbl12, digits=3, caption="Eigenvalue, proportion variance explained, dan kumulatif")| PC | eigenvalue | PVE | cumulative_PVE |
|---|---|---|---|
| PC1 | 4.102 | 0.684 | 0.684 |
| PC2 | 0.781 | 0.130 | 0.814 |
| PC3 | 0.530 | 0.088 | 0.902 |
| PC4 | 0.345 | 0.058 | 0.960 |
| PC5 | 0.159 | 0.027 | 0.986 |
| PC6 | 0.083 | 0.014 | 1.000 |
ggplot2::ggplot(eigen_tbl12, ggplot2::aes(seq_along(eigenvalue), PVE)) +
ggplot2::geom_col() + ggplot2::geom_line(ggplot2::aes(y=cumulative_PVE), linewidth=1) +
ggplot2::geom_point(ggplot2::aes(y=cumulative_PVE), size=2.5) +
ggplot2::scale_x_continuous(breaks=seq_along(eigen12), labels=eigen_tbl12$PC) +
ggplot2::labs(title="Scree dan cumulative explained variance", x="Principal component", y="Proporsi variance")load12 <- as.data.frame(pca$rotation[,1:min(4,ncol(pca$rotation)),drop=FALSE]) |>
tibble::rownames_to_column("indikator")
knitr::kable(load12, digits=3, caption="Loading komponen utama")| indikator | PC1 | PC2 | PC3 | PC4 |
|---|---|---|---|---|
| ipm | 0.400 | 0.240 | 0.544 | -0.623 |
| internet_persen | 0.417 | -0.503 | 0.002 | 0.394 |
| indeks_pendidikan | 0.402 | 0.401 | 0.345 | 0.595 |
| akses_kesehatan | 0.347 | 0.597 | -0.633 | -0.004 |
| pdrb_perkapita_juta | 0.454 | -0.267 | 0.087 | -0.042 |
| umkm_per_1000 | 0.422 | -0.318 | -0.420 | -0.318 |
load_long12 <- load12 |> tidyr::pivot_longer(-indikator, names_to="PC", values_to="loading")
ggplot2::ggplot(load_long12, ggplot2::aes(indikator, loading, fill=loading>0)) +
ggplot2::geom_col(show.legend=FALSE) + ggplot2::facet_wrap(~PC) +
ggplot2::coord_flip() + ggplot2::labs(title="Loading profile setiap principal component", x=NULL)score12 <- tibble::as_tibble(pca$x[,1:2,drop=FALSE]) |> dplyr::mutate(wilayah=reg$wilayah) |>
dplyr::select(wilayah, dplyr::everything()) |> dplyr::arrange(dplyr::desc(PC1))
knitr::kable(score12, digits=3, caption="Score PC1 dan PC2 setiap wilayah")| wilayah | PC1 | PC2 |
|---|---|---|
| Wilayah_02 | 4.146 | 2.029 |
| Wilayah_10 | 3.727 | 0.336 |
| Wilayah_11 | 3.071 | 0.842 |
| Wilayah_14 | 2.711 | -0.433 |
| Wilayah_12 | 2.306 | -0.714 |
| Wilayah_20 | 1.926 | -0.475 |
| Wilayah_22 | 1.851 | -0.243 |
| Wilayah_07 | 0.362 | 0.607 |
| Wilayah_13 | 0.087 | 0.052 |
| Wilayah_03 | 0.059 | -0.019 |
| Wilayah_24 | -0.174 | -1.209 |
| Wilayah_16 | -0.196 | -1.101 |
| Wilayah_09 | -0.214 | -0.485 |
| Wilayah_26 | -0.225 | 0.081 |
| Wilayah_18 | -0.245 | -1.078 |
| Wilayah_27 | -0.268 | -1.448 |
| Wilayah_06 | -0.550 | 0.202 |
| Wilayah_05 | -0.601 | -1.098 |
| Wilayah_04 | -0.679 | -1.347 |
| Wilayah_17 | -0.948 | 0.353 |
| Wilayah_25 | -1.483 | 1.228 |
| Wilayah_23 | -1.508 | 1.097 |
| Wilayah_19 | -1.673 | 0.919 |
| Wilayah_01 | -2.113 | 0.296 |
| Wilayah_08 | -2.237 | 0.790 |
| Wilayah_15 | -2.646 | 0.267 |
| Wilayah_21 | -4.486 | 0.551 |
Jika PC1 memberi loading positif tinggi pada IPM, internet, pendidikan, kesehatan, dan PDRB, skor PC1 tinggi dapat dibaca sebagai kombinasi kapabilitas pembangunan. Namun PCA memaksimalkan variance, bukan relevansi kebijakan; indikator penting dengan variasi kecil dapat terabaikan.
Tulis model/interpretation note individual pada kasus clustering dan/atau PCA. Jelaskan pemilihan metode, scaling/standardization, jumlah cluster/komponen, evaluasi atau stability/sensitivity check, interpretasi substantif regional, uncertainty/limitation, dan reproducibility. Untuk PCA, tampilkan minimal eigenvalues, proportion of variance explained, loading, score, dan visual utama; untuk clustering, tampilkan justifikasi , profil cluster, dan pemeriksaan stabilitas.
Rubrik sesuai RPS: metode 30%; evaluasi 25%; interpretasi 25%; uncertainty/limitation 10%; reproducibility 10%.
Fokus: covariance vs correlation PCA; eigenvalue/eigenvector; score/loading; PVE; reconstruction; tanda PC; keterbatasan PCA untuk indeks kebijakan.
PCA dapat dipakai bila proyek memiliki banyak indikator berkorelasi atau untuk membangun visual 2D sebelum clustering. Tugas 2 menilai justifikasi metode, evaluasi/sensitivity, interpretasi substantif, uncertainty/limitation, dan reproducibility.
PCA mereduksi kompleksitas statistik, bukan kompleksitas kebijakan. Komponen harus dibaca melalui loadings, variance explained, dan konteks indikator.
Analisis regional pada tingkat kabupaten/kota secara alami merupakan data areal: setiap observasi mewakili suatu polygon administratif, bukan satu titik koordinat. Karena itu pembelajaran spasial pada bab ini menggunakan batas kabupaten/kota Jawa Barat dari berkas polygon yang disediakan bersama e-book dan menggabungkannya dengan persentase penduduk miskin tahun 2024. Dataset kemiskinan kabupaten/kota Jawa Barat dipublikasikan oleh Badan Pusat Statistik dan didiseminasikan melalui Open Data Jawa Barat; seri persentase tersedia untuk 2010–2025, sedangkan publikasi resmi BPS Jawa Barat juga mendokumentasikan kemiskinan kabupaten/kota 2019–2024. (Badan Pusat Statistik dan Pemerintah Provinsi Jawa Barat 2026a; Badan Pusat Statistik Provinsi Jawa Barat 2025)
Bab ini membahas tiga lapis analisis: (1) pemetaan choropleth, (2) pembentukan struktur ketetanggaan areal, dan (3) autocorrelation global serta lokal. Peta sendiri hanya menunjukkan lokasi nilai; statistik spasial diperlukan untuk menilai apakah wilayah dengan nilai serupa cenderung berdekatan. (Moran 1950; Anselin 1995; Bivand, Pebesma, dan Gómez-Rubio 2013; Pebesma dan Bivand 2023)
Setelah pertemuan ini mahasiswa mampu:
sf;Misalkan Jawa Barat dibagi menjadi wilayah administratif. Untuk setiap polygon diamati outcome , misalnya persentase penduduk miskin. Dua wilayah disebut bertetangga bila polygon mereka memenuhi aturan tertentu.
Secara klasik, Queen contiguity menyatakan dua polygon bertetangga bila berbagi sisi atau titik sudut, sedangkan Rook contiguity mensyaratkan sisi bersama. Namun shapefile administratif dapat memiliki overlap, enclave, atau ketidaksempurnaan topologi. Karena itu pada contoh ini bobot utama dibangun dari hubungan intersection antar-polygon:
untuk . Sebagai sensitivity analysis, digunakan bobot kedua berbasis jarak minimum antar-polygon sampai 10 km. Ini tetap merupakan analisis areal karena jarak dihitung dari geometry polygon, bukan mengganti wilayah menjadi data point. Matriks bobot kemudian di-row-standardize:
sehingga spatial lag untuk wilayah adalah rata-rata tertimbang nilai tetangganya:
Definisikan deviasi dari rata-rata . Moran’s adalah
dengan
Secara umum, menunjukkan nilai serupa cenderung berdekatan, menunjukkan pola tetangga yang kontras, dan nilai dekat ekspektasi acak menunjukkan tidak ada autocorrelation yang kuat. Interpretasi tidak boleh hanya berdasarkan tanda; gunakan randomization/permutation inference. (Moran 1950)
Jika adalah Moran’s dari permutasi label wilayah, pseudo p-value dapat dihitung dari proporsi statistik permutasi yang sama atau lebih ekstrem daripada nilai observasi, dengan koreksi Monte Carlo.
Local Moran untuk wilayah dapat ditulis
dengan
Gabungan tanda dan spatial lag menghasilkan empat pola:
LISA bersifat lokal dan melibatkan banyak pengujian. Peta LISA harus dibaca sebagai screening pola lokal, bukan bukti kausal. (Anselin 1995)
Geometry. Folder data/spatial_jabar/ berasal dari ZIP batas administratif yang diberikan untuk mata kuliah. Berkas utama adalah JABAR.shp, JABAR.shx, dan JABAR.dbf. Shapefile tidak menyertakan .prj, sehingga CRS tidak tersimpan secara eksplisit. Koordinat berada pada rentang longitude–latitude Jawa Barat; dalam latihan ini CRS ditetapkan sebagai EPSG:4326 setelah pemeriksaan. Pada riset nyata, CRS wajib diverifikasi pada sumber geodata sebelum penetapan manual.
Outcome. File data/kemiskinan_jabar_2024.csv berisi persentase penduduk miskin 27 kabupaten/kota Jawa Barat tahun 2024 dan disiapkan sebagai teaching extract dari seri BPS/Open Data Jawa Barat. Portal resminya mendokumentasikan variabel kabupaten/kota, persentase penduduk miskin, satuan persen, dan tahun; publikasi BPS Jawa Barat 2019–2024 menjadi rujukan substantif tambahan untuk konteks indikator kemiskinan. (Badan Pusat Statistik dan Pemerintah Provinsi Jawa Barat 2026a; Badan Pusat Statistik Provinsi Jawa Barat 2025)
KABKOTNO, lalu nama tampilan diambil dari tabel kemiskinan. Ini menunjukkan mengapa kode wilayah lebih aman daripada fuzzy matching nama.
jabar13 <- sf::st_read("data/spatial_jabar/JABAR.shp", quiet = TRUE) |>
sf::st_make_valid() |>
dplyr::mutate(KABKOTNO = stringr::str_pad(as.character(KABKOTNO), 2, pad = "0"))
if (is.na(sf::st_crs(jabar13))) {
sf::st_crs(jabar13) <- 4326
}
geom_audit13 <- tibble::tibble(
n_polygon = nrow(jabar13),
crs_epsg = sf::st_crs(jabar13)$epsg,
geometry_valid = sum(sf::st_is_valid(jabar13)),
geometry_invalid = sum(!sf::st_is_valid(jabar13)),
type_polygon = sum(as.character(sf::st_geometry_type(jabar13)) == "POLYGON"),
type_multipolygon = sum(as.character(sf::st_geometry_type(jabar13)) == "MULTIPOLYGON")
)
knitr::kable(geom_audit13, caption = "Audit awal geometri Jawa Barat")| n_polygon | crs_epsg | geometry_valid | geometry_invalid | type_polygon | type_multipolygon |
|---|---|---|---|---|---|
| 27 | 4326 | 27 | 0 | 23 | 4 |
poverty13 <- readr::read_csv("data/kemiskinan_jabar_2024.csv", show_col_types = FALSE) |>
dplyr::mutate(KABKOTNO = stringr::str_pad(as.character(KABKOTNO), 2, pad = "0"))
jabar13 <- jabar13 |>
dplyr::select(KABKOTNO, geometry) |>
dplyr::left_join(poverty13, by = "KABKOTNO")
join_audit13 <- tibble::tibble(
polygon = nrow(jabar13),
outcome_non_missing = sum(!is.na(jabar13$kemiskinan_persen_2024)),
outcome_missing = sum(is.na(jabar13$kemiskinan_persen_2024)),
duplicate_code = sum(duplicated(jabar13$KABKOTNO))
)
knitr::kable(join_audit13, caption = "Audit spatial join geometry dan data kemiskinan")| polygon | outcome_non_missing | outcome_missing | duplicate_code |
|---|---|---|---|
| 27 | 27 | 0 | 0 |
Analisis dilanjutkan hanya jika seluruh 27 polygon memiliki outcome dan tidak ada duplikasi kode.
desc13 <- jabar13 |>
sf::st_drop_geometry() |>
dplyr::summarise(
n = dplyr::n(),
mean = mean(kemiskinan_persen_2024),
median = median(kemiskinan_persen_2024),
sd = sd(kemiskinan_persen_2024),
q1 = quantile(kemiskinan_persen_2024, .25),
q3 = quantile(kemiskinan_persen_2024, .75),
min = min(kemiskinan_persen_2024),
max = max(kemiskinan_persen_2024),
cv = sd / mean
)
knitr::kable(desc13, digits = 2, caption = "Statistik deskriptif persentase penduduk miskin, 2024")| n | mean | median | sd | q1 | q3 | min | max | cv |
|---|---|---|---|---|---|---|---|---|
| 27 | 8.01 | 8.41 | 2.65 | 6.36 | 10.19 | 2.34 | 11.93 | 0.33 |
rank13 <- jabar13 |>
sf::st_drop_geometry() |>
dplyr::arrange(dplyr::desc(kemiskinan_persen_2024)) |>
dplyr::mutate(rank = dplyr::row_number()) |>
dplyr::select(rank, nama_kabupaten_kota, kemiskinan_persen_2024)
knitr::kable(rank13, digits = 2, caption = "Ranking deskriptif kemiskinan kabupaten/kota Jawa Barat, 2024")| rank | nama_kabupaten_kota | kemiskinan_persen_2024 |
|---|---|---|
| 1 | KABUPATEN INDRAMAYU | 11.93 |
| 2 | KABUPATEN KUNINGAN | 11.88 |
| 3 | KOTA TASIKMALAYA | 11.10 |
| 4 | KABUPATEN CIREBON | 11.00 |
| 5 | KABUPATEN MAJALENGKA | 10.82 |
| 6 | KABUPATEN BANDUNG BARAT | 10.49 |
| 7 | KABUPATEN TASIKMALAYA | 10.23 |
| 8 | KABUPATEN CIANJUR | 10.14 |
| 9 | KABUPATEN GARUT | 9.68 |
| 10 | KABUPATEN SUBANG | 9.49 |
| 11 | KABUPATEN SUMEDANG | 9.10 |
| 12 | KOTA CIREBON | 9.02 |
| 13 | KABUPATEN PANGANDARAN | 8.75 |
| 14 | KABUPATEN PURWAKARTA | 8.41 |
| 15 | KABUPATEN KARAWANG | 7.86 |
| 16 | KABUPATEN CIAMIS | 7.39 |
| 17 | KOTA SUKABUMI | 7.20 |
| 18 | KABUPATEN BOGOR | 7.05 |
| 19 | KABUPATEN SUKABUMI | 6.87 |
| 20 | KOTA BOGOR | 6.53 |
| 21 | KABUPATEN BANDUNG | 6.19 |
| 22 | KOTA BANJAR | 5.85 |
| 23 | KABUPATEN BEKASI | 4.80 |
| 24 | KOTA CIMAHI | 4.39 |
| 25 | KOTA BEKASI | 4.01 |
| 26 | KOTA BANDUNG | 3.87 |
| 27 | KOTA DEPOK | 2.34 |
Ranking hanya deskriptif. Ia belum mempertimbangkan ukuran populasi, kedalaman kemiskinan, kerentanan, atau hubungan spasial.
ggplot2::ggplot(sf::st_drop_geometry(jabar13), ggplot2::aes(kemiskinan_persen_2024)) +
ggplot2::geom_histogram(bins = 8, boundary = 0) +
ggplot2::geom_vline(xintercept = mean(jabar13$kemiskinan_persen_2024), linetype = 2) +
ggplot2::labs(title = "Distribusi persentase penduduk miskin antarkabupaten/kota", x = "Penduduk miskin (%)", y = "Jumlah wilayah")ggplot2::ggplot(jabar13) +
ggplot2::geom_sf(ggplot2::aes(fill = kemiskinan_persen_2024), colour = "white", linewidth = .25) +
ggplot2::scale_fill_viridis_c(option = "C", direction = -1) +
ggplot2::labs(title = "Persentase Penduduk Miskin Kabupaten/Kota Jawa Barat, 2024", fill = "Kemiskinan (%)", caption = "Sumber indikator: BPS/Open Data Jawa Barat; batas wilayah: berkas polygon mata kuliah") +
ggplot2::theme_void() +
ggplot2::theme(plot.title = ggplot2::element_text(face = "bold"), plot.caption = ggplot2::element_text(hjust = 0))Choropleth menampilkan rate, bukan jumlah absolut. Ini penting karena polygon luas atau berpenduduk besar tidak otomatis memiliki tingkat kemiskinan tinggi.
# Bobot utama: polygon saling beririsan/bersinggungan (intersection adjacency).
rel_inter13 <- sf::st_intersects(jabar13)
n13 <- nrow(jabar13)
W_inter13 <- matrix(0, n13, n13)
for (i in seq_len(n13)) {
jj <- setdiff(rel_inter13[[i]], i)
if (length(jj) > 0) W_inter13[i, jj] <- 1
}
# Bobot alternatif: jarak minimum antar-polygon <= 10 km.
jabar13_m <- sf::st_transform(jabar13, 32748)
D13 <- units::drop_units(sf::st_distance(jabar13_m))
diag(D13) <- Inf
W_10km13 <- 1L * (D13 <= 10000)
diag(W_10km13) <- 0L
neighbor_tbl13 <- tibble::tibble(
nama_kabupaten_kota = jabar13$nama_kabupaten_kota,
intersection_neighbors = rowSums(W_inter13),
neighbors_within_10km = rowSums(W_10km13)
)
knitr::kable(neighbor_tbl13, caption = "Jumlah tetangga areal: intersection dan proximity 10 km")| nama_kabupaten_kota | intersection_neighbors | neighbors_within_10km |
|---|---|---|
| KABUPATEN BOGOR | 8 | 8 |
| KABUPATEN SUKABUMI | 3 | 4 |
| KABUPATEN CIANJUR | 6 | 8 |
| KABUPATEN BANDUNG | 7 | 7 |
| KABUPATEN GARUT | 4 | 6 |
| KABUPATEN TASIKMALAYA | 6 | 7 |
| KABUPATEN CIAMIS | 6 | 8 |
| KABUPATEN KUNINGAN | 3 | 4 |
| KABUPATEN CIREBON | 4 | 4 |
| KABUPATEN MAJALENGKA | 6 | 7 |
| KABUPATEN SUMEDANG | 6 | 9 |
| KABUPATEN INDRAMAYU | 4 | 4 |
| KABUPATEN SUBANG | 6 | 8 |
| KABUPATEN PURWAKARTA | 5 | 8 |
| KABUPATEN KARAWANG | 4 | 5 |
| KABUPATEN BEKASI | 3 | 5 |
| KABUPATEN BANDUNG BARAT | 6 | 7 |
| KABUPATEN PANGANDARAN | 2 | 3 |
| KOTA BOGOR | 1 | 3 |
| KOTA SUKABUMI | 1 | 2 |
| KOTA BANDUNG | 3 | 6 |
| KOTA CIREBON | 1 | 2 |
| KOTA BEKASI | 3 | 3 |
| KOTA DEPOK | 2 | 4 |
| KOTA CIMAHI | 3 | 5 |
| KOTA TASIKMALAYA | 2 | 2 |
| KOTA BANJAR | 1 | 3 |
ggplot2::ggplot(neighbor_tbl13, ggplot2::aes(reorder(nama_kabupaten_kota, intersection_neighbors), intersection_neighbors)) +
ggplot2::geom_col() +
ggplot2::coord_flip() +
ggplot2::labs(title = "Jumlah tetangga berdasarkan intersection polygon", x = NULL, y = "Jumlah tetangga")Perbedaan degree menunjukkan bahwa setiap wilayah memiliki jumlah tetangga berbeda. Row-standardization mencegah wilayah dengan banyak tetangga secara otomatis memiliki spatial lag yang lebih besar hanya karena jumlah koneksi.
lw_inter13 <- spdep::mat2listw(W_inter13, style = "W", zero.policy = TRUE)
y13 <- jabar13$kemiskinan_persen_2024
moran_test13 <- spdep::moran.test(y13, lw_inter13, zero.policy = TRUE, randomisation = TRUE)
set.seed(260813)
moran_mc13 <- spdep::moran.mc(y13, lw_inter13, nsim = 999, zero.policy = TRUE)
moran_out13 <- tibble::tibble(
statistic = "Moran's I — polygon intersection",
I_observed = unname(moran_test13$estimate[[1]]),
expectation = unname(moran_test13$estimate[[2]]),
variance = unname(moran_test13$estimate[[3]]),
p_asymptotic = moran_test13$p.value,
p_permutation = moran_mc13$p.value
)
knitr::kable(moran_out13, digits = 4, caption = "Autocorrelation global kemiskinan Jawa Barat")| statistic | I_observed | expectation | variance | p_asymptotic | p_permutation |
|---|---|---|---|---|---|
| Moran’s I — polygon intersection | 0.4776 | -0.0385 | 0.0199 | 0.0001 | 0.001 |
P-value permutation lebih sesuai untuk pembelajaran karena secara eksplisit membandingkan pola observasi dengan distribusi acak hasil pengacakan label wilayah.
z13 <- as.numeric(scale(y13))
lag_z13 <- spdep::lag.listw(lw_inter13, z13, zero.policy = TRUE)
scatter13 <- tibble::tibble(
wilayah = jabar13$nama_kabupaten_kota,
z = z13,
spatial_lag_z = lag_z13
)
ggplot2::ggplot(scatter13, ggplot2::aes(z, spatial_lag_z)) +
ggplot2::geom_hline(yintercept = 0, linetype = 2) +
ggplot2::geom_vline(xintercept = 0, linetype = 2) +
ggplot2::geom_smooth(method = "lm", se = FALSE) +
ggplot2::geom_point(size = 2.6) +
ggplot2::labs(title = "Moran scatterplot kemiskinan 2024", x = "Kemiskinan terstandardisasi (z)", y = "Spatial lag z")Kuadran kanan-atas dan kiri-bawah merepresentasikan kemiripan lokal (high–high dan low–low), sedangkan dua kuadran lainnya menandai kontras lokal.
local13 <- spdep::localmoran(y13, lw_inter13, zero.policy = TRUE)
jabar13$Ii <- local13[, "Ii"]
jabar13$Z_Ii <- local13[, "Z.Ii"]
pcol13 <- grep("^Pr", colnames(local13), value = TRUE)[1]
jabar13$p_local <- local13[, pcol13]
jabar13$z <- z13
jabar13$lag_z <- lag_z13
jabar13$quadrant <- dplyr::case_when(
jabar13$z >= 0 & jabar13$lag_z >= 0 ~ "High–High",
jabar13$z < 0 & jabar13$lag_z < 0 ~ "Low–Low",
jabar13$z >= 0 & jabar13$lag_z < 0 ~ "High–Low",
TRUE ~ "Low–High"
)
jabar13$lisa_class <- ifelse(jabar13$p_local <= .05, jabar13$quadrant, "Tidak signifikan")
local_tbl13 <- jabar13 |>
sf::st_drop_geometry() |>
dplyr::select(nama_kabupaten_kota, kemiskinan_persen_2024, Ii, Z_Ii, p_local, lisa_class) |>
dplyr::arrange(p_local)
knitr::kable(local_tbl13, digits = 4, caption = "Local Moran dan klasifikasi LISA")| nama_kabupaten_kota | kemiskinan_persen_2024 | Ii | Z_Ii | p_local | lisa_class |
|---|---|---|---|---|---|
| KABUPATEN CIREBON | 11.00 | 1.2809 | 2.4893 | 0.0128 | High–High |
| KABUPATEN MAJALENGKA | 10.82 | 0.9306 | 2.4846 | 0.0130 | High–High |
| KOTA BEKASI | 4.01 | 1.9470 | 2.4593 | 0.0139 | Low–Low |
| KABUPATEN BOGOR | 7.05 | 0.2348 | 2.1219 | 0.0338 | Low–Low |
| KABUPATEN INDRAMAYU | 11.93 | 1.2103 | 1.8862 | 0.0593 | Tidak signifikan |
| KABUPATEN SUMEDANG | 9.10 | 0.2746 | 1.8163 | 0.0693 | Tidak signifikan |
| KABUPATEN CIAMIS | 7.39 | -0.1624 | -1.7941 | 0.0728 | Tidak signifikan |
| KOTA DEPOK | 2.34 | 2.0870 | 1.6298 | 0.1031 | Tidak signifikan |
| KABUPATEN TASIKMALAYA | 10.23 | 0.4785 | 1.6194 | 0.1054 | Tidak signifikan |
| KABUPATEN KUNINGAN | 11.88 | 0.9855 | 1.3336 | 0.1823 | Tidak signifikan |
| KABUPATEN BEKASI | 4.80 | 0.8127 | 1.2871 | 0.1981 | Tidak signifikan |
| KOTA CIREBON | 9.02 | 0.4444 | 1.1451 | 0.2522 | Tidak signifikan |
| KABUPATEN SUBANG | 9.49 | 0.2146 | 1.0810 | 0.2797 | Tidak signifikan |
| KABUPATEN PURWAKARTA | 8.41 | 0.0581 | 0.9278 | 0.3535 | Tidak signifikan |
| KOTA CIMAHI | 4.39 | 0.6248 | 0.9242 | 0.3554 | Tidak signifikan |
| KABUPATEN BANDUNG BARAT | 10.49 | -0.3418 | -0.8816 | 0.3780 | Tidak signifikan |
| KOTA BANDUNG | 3.87 | 0.6081 | 0.8258 | 0.4089 | Tidak signifikan |
| KABUPATEN GARUT | 9.68 | 0.2220 | 0.7827 | 0.4338 | Tidak signifikan |
| KOTA TASIKMALAYA | 11.10 | 0.3634 | 0.5123 | 0.6084 | Tidak signifikan |
| KABUPATEN KARAWANG | 7.86 | 0.0132 | 0.4692 | 0.6389 | Tidak signifikan |
| KABUPATEN PANGANDARAN | 8.75 | 0.0866 | 0.4497 | 0.6530 | Tidak signifikan |
| KOTA SUKABUMI | 7.20 | 0.1380 | 0.4448 | 0.6565 | Tidak signifikan |
| KOTA BOGOR | 6.53 | 0.2119 | 0.3881 | 0.6979 | Tidak signifikan |
| KOTA BANJAR | 5.85 | 0.2001 | 0.2708 | 0.7865 | Tidak signifikan |
| KABUPATEN CIANJUR | 10.14 | 0.0316 | 0.1910 | 0.8485 | Tidak signifikan |
| KABUPATEN BANDUNG | 6.19 | -0.0409 | -0.0938 | 0.9253 | Tidak signifikan |
| KABUPATEN SUKABUMI | 6.87 | -0.0196 | -0.0490 | 0.9610 | Tidak signifikan |
ggplot2::ggplot(jabar13) +
ggplot2::geom_sf(ggplot2::aes(fill = lisa_class), colour = "white", linewidth = .25) +
ggplot2::labs(title = "Peta Local Moran (LISA) kemiskinan Jawa Barat, 2024", fill = "LISA class", caption = "p lokal ≤ 0,05 ditampilkan sebagai pola lokal; interpretasi bersifat screening") +
ggplot2::theme_void() +
ggplot2::theme(plot.title = ggplot2::element_text(face = "bold"), plot.caption = ggplot2::element_text(hjust = 0))lw_10km13 <- spdep::mat2listw(W_10km13, style = "W", zero.policy = TRUE)
set.seed(260813)
mc_inter13 <- spdep::moran.mc(y13, lw_inter13, nsim = 999, zero.policy = TRUE)
set.seed(260813)
mc_10km13 <- spdep::moran.mc(y13, lw_10km13, nsim = 999, zero.policy = TRUE)
sens13 <- tibble::tibble(
neighborhood = c("Polygon intersection", "Polygon distance <= 10 km"),
Moran_I = c(unname(mc_inter13$statistic), unname(mc_10km13$statistic)),
p_permutation = c(mc_inter13$p.value, mc_10km13$p.value),
mean_neighbors = c(mean(rowSums(W_inter13)), mean(rowSums(W_10km13)))
)
knitr::kable(sens13, digits = 4, caption = "Sensitivity Moran's I terhadap definisi neighborhood areal")| neighborhood | Moran_I | p_permutation | mean_neighbors |
|---|---|---|---|
| Polygon intersection | 0.4776 | 0.001 | 3.9259 |
| Polygon distance <= 10 km | 0.4060 | 0.001 | 5.2593 |
Jika tanda, magnitude, atau kesimpulan inferensial berubah drastis antara intersection adjacency dan proximity 10 km, hasil harus dilaporkan sebagai sensitif terhadap definisi konektivitas. Neighborhood seharusnya mewakili mekanisme regional yang masuk akal; adjacency administratif belum tentu cocok untuk mobilitas komuter, perdagangan, DAS, atau jaringan transportasi.
pal13 <- leaflet::colorNumeric("YlOrRd", domain = jabar13$kemiskinan_persen_2024)
leaflet::leaflet(jabar13) |>
leaflet::addProviderTiles("CartoDB.Positron") |>
leaflet::addPolygons(
fillColor = ~pal13(kemiskinan_persen_2024),
fillOpacity = .75,
weight = .8,
color = "white",
popup = ~paste0(
"<b>", nama_kabupaten_kota, "</b><br>",
"Kemiskinan 2024: ", round(kemiskinan_persen_2024, 2), "%<br>",
"LISA: ", lisa_class
)
) |>
leaflet::addLegend(pal = pal13, values = ~kemiskinan_persen_2024, title = "Kemiskinan (%)")Analisis areal mengubah pertanyaan dari “kabupaten mana paling tinggi?” menjadi “apakah kabupaten dengan kemiskinan tinggi berada dalam lingkungan regional yang juga memiliki nilai tinggi?”. Jika terdapat pola High–High, intervensi lintas batas dapat dipertimbangkan karena akses pekerjaan, transportasi, pasar, dan layanan publik tidak berhenti di garis administrasi. Sebaliknya, High–Low dapat menunjukkan wilayah yang berbeda tajam dari tetangganya dan layak ditelaah sebagai kasus khusus.
Namun spatial autocorrelation tidak menjelaskan penyebab. Pola dapat muncul karena struktur ekonomi yang mirip, topografi, aksesibilitas, urbanisasi, kebijakan historis, atau proses pengukuran. Untuk membuat klaim mekanisme diperlukan variabel tambahan dan model yang sesuai.
Modifiable Areal Unit Problem (MAUP) berarti hasil statistik dapat berubah bila batas atau tingkat agregasi wilayah diubah. Kabupaten/kota adalah satu pilihan agregasi administratif, bukan satu-satunya representasi proses sosial-ekonomi.
Ecological fallacy terjadi jika hubungan pada tingkat kabupaten langsung diterapkan kepada individu. Misalnya, kabupaten dengan kemiskinan tinggi tidak berarti setiap rumah tangga di kabupaten itu miskin, dan asosiasi antara internet dan kemiskinan antarkabupaten tidak sama dengan hubungan pada rumah tangga. (Pebesma dan Bivand 2023; Lovelace, Nowosad, dan Muenchow 2025)
Gunakan polygon Jawa Barat dan outcome regional dari BPS/Open Data Jabar. Tampilkan audit geometry, audit join, statistik deskriptif, ranking, choropleth, degree neighborhood, Moran’s I + permutation test, Moran scatterplot, Local Moran/LISA map, dan sensitivity intersection vs proximity polygon. Akhiri dengan memo 300–400 kata yang memisahkan temuan deskriptif, temuan spasial, hipotesis mekanisme, dan rekomendasi data lanjutan.
Project M5 menyatukan bukti heterogenitas regional dari clustering/PCA dan/atau analisis spasial sesuai pertanyaan. Jika struktur spasial relevan, minimal lakukan audit neighborhood dan satu sensitivity analysis. Peta tidak boleh menjadi dekorasi; ia harus menjawab pertanyaan substantif.
Regional data science membutuhkan areal thinking. Untuk indikator kabupaten/kota, polygon, neighborhood, spatial lag, global Moran, dan Local Moran memberi kerangka yang lebih tepat daripada sekadar plot titik. Analisis tetap harus menjaga batas inferensi: pola spasial adalah evidence tentang struktur, bukan otomatis evidence tentang sebab.
Model terbaik bukan selalu model dengan metric agregat paling kecil. Keputusan regional membutuhkan evaluasi robustness, uncertainty, subgroup performance, fairness, dan konsekuensi operasional. Model card adalah salah satu cara mendokumentasikan intended use, metric, keterbatasan, dan kelompok kinerja. (Mitchell dkk. 2019)
Mahasiswa mampu membandingkan model pada metric yang relevan, menganalisis residual/subgroup, melakukan sensitivity analysis sederhana, dan menyusun model card.
Robustness adalah kestabilan kesimpulan terhadap perubahan data/model yang wajar. Fairness di konteks regional berarti memeriksa apakah error sistematis lebih besar pada kelompok wilayah tertentu. Hal ini bukan sekadar masalah teknis; definisi fairness terkait tujuan program.
Perbedaan error antargrup:
Coverage interval prediksi:
dengan interval prediksi. Coverage nominal 95% idealnya mendekati 0,95 pada data yang relevan.
Jika adalah nilai metrik model pada resample , rata-rata dan standard error resampling: Selisih kecil dibanding variability resampling tidak layak diperlakukan sebagai bukti bahwa satu model “pasti terbaik”. Pertimbangkan kesederhanaan, interpretability, latency, fairness, dan data requirements. (Kuhn dan Silge 2022)
Ambil bootstrap samples dan hitung statistic . Bootstrap standard error: Bootstrap dapat diterapkan pada koefisien, ranking, atau metrik model, dengan resampling scheme yang menghormati struktur panel/spasial jika diperlukan.
Jika dan adalah ranking wilayah di dua skenario bobot/model, Spearman rank correlation: Jika daftar “10 wilayah prioritas” berubah drastis karena sedikit perubahan bobot, rekomendasi harus dilaporkan sebagai tidak stabil.
Untuk protected/context group :
Demographic parity difference
Equal opportunity difference
Tidak ada satu fairness metric yang selalu tepat; kriteria dapat saling bertentangan dan konteks hukum/etik menentukan apa yang relevan. Dalam regional policy, group dapat berupa urban/rural, pulau/kawasan, atau kategori kapasitas fiskal—tetapi penggunaan kategori harus punya dasar substantif dan tidak menstigmatisasi. (Hardt, Price, dan Srebro 2016)
Jika benefit intervensi dan cost berbeda, net benefit pada threshold dapat ditulis secara sederhana: Rumus berasal dari decision-analytic framing tertentu dan tidak otomatis berlaku untuk semua kebijakan; gunakan sebagai contoh bahwa threshold harus dihubungkan dengan trade-off keputusan.
Jika ada treated group dan control , sebelum () dan sesudah (), estimand DID: Regresi: Interpretasi kausal membutuhkan asumsi parallel trends dan desain yang kredibel. DID dimasukkan untuk menunjukkan perbedaan antara “memprediksi outcome” dan “mengevaluasi apakah kebijakan menyebabkan perubahan”. (Callaway dan Sant’Anna 2021; Hernán dan Robins 2020)
Model yang rata-rata bagus bisa buruk untuk daerah berpenduduk kecil atau data terbatas. Jika model digunakan untuk alokasi bantuan, error tidak merata dapat memperkuat ketimpangan.
Model A RMSE fold: 2.1,2.2,2.0,2.4,2.3 → mean 2.20. Model B: 2.05,2.18,1.98,2.36,2.28 → mean 2.17. Selisih 0.03 sangat kecil dibanding variasi antar-fold. Menyebut B “jauh lebih baik” tidak didukung. Pertimbangkan paired resample differences dan simplicity.
Untuk setiap bootstrap , hitung score/ranking wilayah. Untuk wilayah , laporkan median rank dan interval percentile: Jika wilayah ranking 8 memiliki interval 3–19, penetapan cut-off “top 10” harus hati-hati.
Group urban: TPR=0.90; rural: TPR=0.65. Equal opportunity difference urban–rural=0.25. Ini memberi sinyal model lebih sering melewatkan prioritas rural. Penyebab dapat berasal dari data quality, feature availability, label process, atau heterogeneity; fairness diagnostic bukan diagnosis penyebab.
Treated outcome: pre 60, post 75 → +15. Control: pre 58, post 65 → +7. Interpretasi kausal memerlukan parallel trends dan tidak adanya perubahan berbeda lain yang confound treatment timing. Uji/plot pre-trends penting, dan modern DID perlu memperhatikan staggered adoption. (Callaway dan Sant’Anna 2021)
| Analytic choice | Base | Alternative | Result stable? |
|---|---|---|---|
| weights index | 0.5/0.3/0.2 | equal weights | yes/no |
| split | temporal | grouped region | yes/no |
| model | RF | ridge/logit | yes/no |
| W spatial | queen | kNN | yes/no |
| missing | complete case | imputation/sensitivity | yes/no |
Capstone harus menyimpulkan bukan hanya “hasil”, tetapi set of results that survive reasonable alternatives.
Bedakan: 1. sampling uncertainty; 2. measurement error; 3. model uncertainty; 4. hyperparameter uncertainty; 5. scenario/weight uncertainty; 6. structural uncertainty tentang mekanisme regional.
CI koefisien hanya menangkap sebagian dari daftar tersebut. Kebijakan berbasis data harus menghindari false precision.
panel <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE)
train <- panel |> filter(tahun <= 2023)
test <- panel |> filter(tahun >= 2024)
fit <- lm(kemiskinan_persen ~ pdrb_perkapita_juta + tpt_persen + internet_persen + ipm, data = train)
ev <- test |> mutate(pred = predict(fit, newdata = test), abs_err = abs(kemiskinan_persen-pred))
ev |>
group_by(urban) |>
summarise(n=n(), MAE=mean(abs_err), RMSE=sqrt(mean((kemiskinan_persen-pred)^2))) |>
knitr::kable(digits=3, caption="Kinerja model menurut tipe wilayah - simulasi")| urban | n | MAE | RMSE |
|---|---|---|---|
| 0 | 22 | 1.343 | 1.611 |
| 1 | 32 | 0.927 | 1.259 |
Pada INDO-DAPOER atau Open Data Jabar, subgroup dapat dibentuk dari status kota/kabupaten, quantile populasi, zona geografis, atau kategori berbasis teori. Hindari menciptakan subgroup kecil yang membuat metric sangat tidak stabil.
Kartu dataset real.
# Sensitivitas ranking prioritas terhadap bobot indikator.
latest <- panel |> filter(tahun == 2025)
rank_a <- latest |>
mutate(score = .6*as.numeric(scale(kemiskinan_persen)) + .4*as.numeric(scale(tpt_persen))) |>
arrange(desc(score)) |>
mutate(rank_a = row_number())
rank_b <- latest |>
mutate(score = .4*as.numeric(scale(kemiskinan_persen)) + .3*as.numeric(scale(tpt_persen)) - .3*as.numeric(scale(ipm))) |>
arrange(desc(score)) |>
mutate(rank_b = row_number())
left_join(rank_a |> select(wilayah, rank_a), rank_b |> select(wilayah, rank_b), by="wilayah") |>
mutate(delta_rank = rank_b-rank_a) |>
arrange(desc(abs(delta_rank))) |>
head(10) |>
knitr::kable()| wilayah | rank_a | rank_b | delta_rank |
|---|---|---|---|
| Wilayah_21 | 15 | 3 | -12 |
| Wilayah_14 | 11 | 22 | 11 |
| Wilayah_27 | 17 | 9 | -8 |
| Wilayah_26 | 5 | 11 | 6 |
| Wilayah_25 | 13 | 19 | 6 |
| Wilayah_24 | 8 | 13 | 5 |
| Wilayah_07 | 1 | 5 | 4 |
| Wilayah_01 | 19 | 15 | -4 |
| Wilayah_10 | 21 | 25 | 4 |
| Wilayah_08 | 24 | 20 | -4 |
d14 <- readr::read_csv("data/simulasi_panel_regional.csv", show_col_types=FALSE) |>
dplyr::filter(tahun==2025)
set.seed(260814)
s14 <- rsample::initial_split(d14, prop=.8)
tr14 <- rsample::training(s14); te14 <- rsample::testing(s14)
lm14 <- stats::lm(kemiskinan_persen ~ pdrb_perkapita_juta+tpt_persen+ipm+internet_persen+umkm_per_1000, data=tr14)
rf14 <- ranger::ranger(kemiskinan_persen ~ pdrb_perkapita_juta+tpt_persen+ipm+internet_persen+umkm_per_1000, data=tr14, num.trees=500, seed=260814)
pred14 <- dplyr::bind_rows(
tibble::tibble(actual=te14$kemiskinan_persen, pred=predict(lm14,newdata=te14), model="Linear"),
tibble::tibble(actual=te14$kemiskinan_persen, pred=predict(rf14,data=te14)$predictions, model="Random forest")
) |> dplyr::mutate(error=pred-actual)
metric14 <- pred14 |> dplyr::group_by(model) |>
dplyr::summarise(RMSE=sqrt(mean(error^2)), MAE=mean(abs(error)), Bias=mean(error), P90_AbsError=quantile(abs(error),.90), .groups="drop")
knitr::kable(metric14, digits=3, caption="Perbandingan metric utama dan tail error")| model | RMSE | MAE | Bias | P90_AbsError |
|---|---|---|---|---|
| Linear | 1.171 | 1.032 | -0.993 | 1.626 |
| Random forest | 0.954 | 0.821 | -0.800 | 1.349 |
ggplot2::ggplot(pred14, ggplot2::aes(error, fill=model)) +
ggplot2::geom_density(alpha=.35) + ggplot2::geom_vline(xintercept=0,linetype=2) +
ggplot2::labs(title="Distribusi error holdout", x="Prediction error", fill="Model")worst14 <- pred14 |> dplyr::group_by(model) |> dplyr::slice_max(abs(error), n=5, with_ties=FALSE) |> dplyr::ungroup()
knitr::kable(worst14, digits=3, caption="Lima error absolut terbesar per model")| actual | pred | model | error |
|---|---|---|---|
| 11.637 | 9.856 | Linear | -1.781 |
| 10.966 | 9.495 | Linear | -1.471 |
| 10.098 | 8.929 | Linear | -1.169 |
| 11.810 | 10.715 | Linear | -1.095 |
| 9.444 | 8.887 | Linear | -0.557 |
| 11.637 | 9.994 | Random forest | -1.643 |
| 10.966 | 9.911 | Random forest | -1.055 |
| 9.444 | 8.495 | Random forest | -0.949 |
| 11.810 | 11.166 | Random forest | -0.644 |
| 10.098 | 9.528 | Random forest | -0.570 |
Jika prioritas berubah drastis hanya karena bobot sedikit berubah, sistem ranking rapuh. Kebijakan sebaiknya menampilkan tier atau range, bukan ranking presisi 1-27 yang memberi kesan kepastian palsu.
Lakukan robustness audit capstone: minimal dua skenario bobot/fitur, satu alternatif resampling/model, satu fairness slice, dan satu uncertainty summary. Buat tabel “temuan yang stabil” vs “temuan yang sensitif”.
Kisi-kisi: k-means objective; silhouette; PCA; Moran’s I; spatial weights; bootstrap SE; rank stability; fairness metric; calibration; prediction vs policy evaluation; DID intuition.
Milestone evaluasi: tim menyertakan tabel comparison, subgroup check, sensitivity analysis, dan model card 1 halaman.
Evaluasi model adalah evaluasi risiko keputusan. Metric agregat harus dilengkapi robustness, subgroup performance, uncertainty, dan keterbatasan penggunaan.
Tahap akhir analisis adalah mengubah bukti menjadi opsi kebijakan. Rekomendasi yang baik menunjukkan evidence chain: masalah → data → hasil → ketidakpastian → opsi → konsekuensi. Generative AI dapat mempercepat coding dan dokumentasi, tetapi juga dapat menghasilkan kode salah, referensi fiktif, atau interpretasi terlalu percaya diri. (Miao dan Holmes 2023; Tabassi 2023)
Mahasiswa mampu menyusun policy insight, membedakan temuan dan rekomendasi, membuat dashboard ringkas, menggunakan GenAI secara transparan, dan mendokumentasikan verifikasi.
Evidence-based policy bukan berarti keputusan dibuat oleh model. Bukti adalah input bersama nilai publik, hukum, anggaran, political feasibility, local knowledge, dan equity. AI berperan sebagai assistant, bukan otoritas epistemik.
Penggunaan GenAI yang diperbolehkan: menjelaskan dokumentasi package, menghasilkan skeleton kode, debugging, membuat alternatif visual, merapikan dokumentasi, dan brainstorming interpretasi awal. Kewajiban mahasiswa: memeriksa kode, memvalidasi output, membaca sumber asli, menguji asumsi, menghapus data sensitif, dan mendeklarasikan penggunaan AI.
Untuk keputusan berbasis expected loss, secara konseptual pilih tindakan yang meminimalkan
di mana adalah loss dari tindakan ketika keadaan sebenarnya , dan adalah bukti/data. Formula ini menekankan bahwa keputusan bergantung pada loss/konsekuensi, bukan hanya prediksi.
Jika kebijakan mempertimbangkan kriteria, score sederhana: Tetapi jika model menghasilkan risk probability , score kebijakan dapat menggabungkan risiko dan feasibility: dengan feasibility dan equity score. Persamaan ini bukan resep universal; tujuannya memperlihatkan bahwa transisi model→policy memerlukan pilihan eksplisit yang dapat diaudit.
Jika intervensi , benefit ekspektasian , biaya , anggaran : Ini adalah bentuk knapsack/optimization sederhana. Model prediksi dapat membantu memperkirakan atau risiko, tetapi alokasi akhir tetap constrained decision problem.
Jika dashboard menampilkan KPI, setiap KPI harus memiliki definisi matematis. Misalnya coverage:
Change vs target:
Percent target achievement (untuk target positif): Hindari persentase bila denominator nol/tidak stabil. Dashboard harus menampilkan sumber, periode, update time, dan status data.
Setiap keluaran AI yang memengaruhi analisis melewati empat lapis verifikasi:
di mana setiap pada checklist minimum. Jika salah satu nol, artefak belum layak dipakai. Ini bukan probabilistic score, tetapi process-control device.
UNESCO menekankan pendekatan human-centred dan validasi etis-pedagogis untuk GenAI; NIST AI RMF mendorong governance, mapping, measurement, dan management risiko AI. (Miao dan Holmes 2023; Tabassi 2023; Autio dkk. 2024)
Untuk setiap project, simpan tabel:
| Elemen | Isi minimum |
|---|---|
| Tool/model | nama layanan/model bila diketahui |
| Tanggal | kapan digunakan |
| Tujuan | dokumentasi, debugging, ide visualisasi, dsb. |
| Prompt category | ringkasan, bukan data sensitif mentah |
| Output used | bagian apa yang benar-benar digunakan |
| Verification | bagaimana kode/sumber/hasil diverifikasi |
| Human revision | perubahan substansial yang dilakukan mahasiswa |
Data personal, data rahasia, atau data dengan pembatasan lisensi tidak boleh ditempelkan ke layanan AI publik tanpa dasar dan izin yang sesuai.
Analisis yang reproducible dapat dipandang sebagai fungsi
Jika salah satu komponen tidak tersedia atau berubah tanpa dokumentasi, output tidak dapat diaudit. Catat sessionInfo(), seed, package versions, sumber data, dan semua parameter preprocessing/model.
Model dapat memberi probabilitas desa rentan 0,72. Kebijakan tetap harus menjawab: kapasitas verifikasi berapa, biaya salah sasaran berapa, data apa yang sensitif, siapa yang dapat mengajukan koreksi, dan kapan model ditinjau ulang.
Empat wilayah memiliki expected benefit dan cost juta; budget 50. Memilih dua benefit terbesar A+B membutuhkan 50 dan benefit 90. Kombinasi A+D cost 40 benefit 80; B+C cost 40 benefit 75; B+C+D cost 50 benefit 105. Maka ranking benefit individual tidak cukup; constraint menghasilkan portfolio berbeda.
Ini memperjelas transisi dari risk prediction ke decision optimization. Model dapat menghasilkan risk/benefit estimate, tetapi resource allocation membutuhkan fungsi objective dan constraints.
Gunakan lima tingkat klaim:
Jangan melompat dari tingkat 1–3 langsung ke 5 tanpa penjelasan tambahan.
Dashboard kebijakan sebaiknya memiliki empat layer: overview → comparison → drill-down → methodology. Overview menampilkan 3–5 KPI; comparison memungkinkan lintas wilayah/waktu; drill-down menampilkan profile; methodology menjelaskan source, formula, update, dan limitation.
Jika data terakhir tahun dan dashboard dibuka tahun , lag: KPI dengan lag besar harus diberi badge “historical”/“latest available”, bukan ditampilkan seolah real-time. INDO-DAPOER berhenti 2018 sehingga cocok untuk latihan historis dan bukan kondisi terkini. (World Bank 2026)
AI menyarankan scale() sebelum split. Mahasiswa harus mengoreksi karena leakage. AI mengutip dataset “BPS Innovation Index 2025” yang tidak ditemukan: source verification gagal. AI menulis interpretasi “internet menurunkan kemiskinan”: interpretation verification gagal karena model hanya asosiasional. Contoh ini menunjukkan kode yang syntactically plausible tetap dapat salah secara ilmiah.
ai_log <- tibble::tribble(
~tanggal, ~tool, ~tujuan, ~output_used, ~verification,
"2026-09-15", "Generative AI", "debug join", "saran anti_join", "dicek pada toy data dan dokumentasi dplyr",
"2026-10-01", "Generative AI", "draft caption", "struktur caption", "angka dan klaim diverifikasi dari output sendiri"
)
knitr::kable(ai_log, caption="Contoh AI-use log")| tanggal | tool | tujuan | output_used | verification |
|---|---|---|---|---|
| 2026-09-15 | Generative AI | debug join | saran anti_join | dicek pada toy data dan dokumentasi dplyr |
| 2026-10-01 | Generative AI | draft caption | struktur caption | angka dan klaim diverifikasi dari output sendiri |
Setiap recommendation harus bisa ditelusuri ke evidence. Gunakan format: Temuan → interpretasi → opsi → rekomendasi → indikator monitoring → caveat. Jika satu rekomendasi tidak memiliki evidence chain, hapus atau ubah menjadi hipotesis untuk penelitian berikutnya.
latest <- read_csv("data/simulasi_panel_regional.csv", show_col_types = FALSE) |>
filter(tahun == 2025) |>
mutate(
prioritas = case_when(
kemiskinan_persen >= quantile(kemiskinan_persen,.75) & internet_persen < median(internet_persen) ~ "Inklusi digital + perlindungan sosial",
tpt_persen >= quantile(tpt_persen,.75) & pdrb_perkapita_juta > median(pdrb_perkapita_juta) ~ "Matching tenaga kerja-industri",
TRUE ~ "Monitoring / intervensi sektoral"
)
)
latest |> count(prioritas) |> knitr::kable(caption="Contoh penerjemahan pola menjadi opsi intervensi - simulasi")| prioritas | n |
|---|---|
| Inklusi digital + perlindungan sosial | 7 |
| Matching tenaga kerja-industri | 5 |
| Monitoring / intervensi sektoral | 15 |
latest |>
dplyr::count(prioritas) |>
ggplot2::ggplot(ggplot2::aes(reorder(prioritas, n), n)) +
ggplot2::geom_col(fill = "#145B8C") +
ggplot2::coord_flip() +
ggplot2::labs(title = "Distribusi opsi intervensi — simulasi", x = NULL, y = "Jumlah wilayah")Untuk dashboard Jawa Barat, sumber data dapat berasal dari Open Data Jabar/BPS; dashboard harus menampilkan tahun data, sumber, status angka, dan definisi indikator pada tooltip/metadata. Jangan mencampur indikator 2025 dan 2022 dalam satu “snapshot 2025” tanpa label.
Kartu dataset real.
data/katalog_data_real.csv.map_policy <- latest
leaflet::leaflet(map_policy) |>
leaflet::addProviderTiles("CartoDB.Positron") |>
leaflet::addCircleMarkers(~longitude, ~latitude, radius = 6,
popup = ~paste0("<b>", wilayah, "</b><br>", prioritas))Gunakan tabel log berikut untuk project:
| Elemen | Contoh isi |
|---|---|
| Tool/model | Nama layanan/model yang digunakan |
| Tanggal | YYYY-MM-DD |
| Tujuan | Debugging pivot_longer() / ide visualisasi / dokumentasi |
| Ringkasan prompt | Bukan data rahasia; cukup ringkas tujuan |
| Output yang dipakai | Fungsi/kode/paragraf apa yang diadaptasi |
| Verifikasi | Dibandingkan dokumentasi resmi, unit test, cek hasil manual |
| Modifikasi manusia | Perubahan yang dilakukan mahasiswa |
Tidak diperbolehkan: membuat sumber/referensi fiktif, mengunggah data individual rahasia tanpa izin, menyalin interpretasi AI tanpa pemeriksaan, atau menyembunyikan penggunaan AI ketika berkontribusi substantif pada produk akhir.
Policy recommendation perlu memiliki tingkat kepastian yang sebanding dengan bukti. Gunakan bahasa “data menunjukkan asosiasi/pola”, “model memprediksi”, atau “hasil mendukung prioritas eksplorasi”, bukan klaim sebab-akibat yang tidak didukung desain.
Buat policy translation memo maksimum 2 halaman: tiga temuan, dua opsi kebijakan, satu rekomendasi, stakeholder, implementation risk, data limitation, dan indikator monitoring. Lampirkan screenshot/dashboard beta. Isi AI-use log bila AI digunakan.
Checkpoint II menilai kualitas kontribusi pada policy studio, kemampuan memberi dan menindaklanjuti peer review, serta kemampuan mempertahankan keterlacakan evidence → recommendation.
Minggu 15 adalah policy and communication gate: kelompok menyerahkan Project M6 berupa dashboard beta, policy memo 2 halaman, model card/monitoring KPI, dan AI-use log sementara.
Nilai sains data muncul ketika bukti diterjemahkan menjadi keputusan secara transparan. AI dapat mempercepat kerja, tetapi tanggung jawab ilmiah tetap berada pada analis manusia.
Pertemuan akhir menguji dua hal berbeda: produk tim melalui presentasi capstone dan penguasaan individu melalui UAS/defense. Pemisahan ini mencegah keberhasilan kelompok menutupi ketidaksiapan individu.
Mahasiswa mampu mempertahankan keputusan analitik, menjawab kritik, menunjukkan reproducibility, membedakan evidence dari asumsi, dan menyusun rekomendasi regional yang proporsional.
Reproducibility audit memeriksa apakah data, kode, seed, dependency, dan output dapat ditelusuri. Replicability lebih luas dan berkaitan dengan apakah temuan serupa diperoleh dengan data/prosedur baru. Untuk mata kuliah ini, fokus minimum adalah reproducibility.
Tidak ada formula baru. Mahasiswa harus mampu menjelaskan kembali metric/model yang digunakan pada project, termasuk unit outcome dan arti koefisien/probabilitas/cluster/metric.
Project adalah kerja kelompok, sedangkan UAS 20% mengukur penguasaan individual terhadap capstone melalui defense/synthesis. Penilaian mengikuti lima dimensi RPS berikut.
| Dimensi | Bobot di dalam UAS |
|---|---|
| Analytical reasoning & ownership | 30% |
| Justifikasi model dan validasi | 25% |
| Interpretasi substantif & policy linkage | 25% |
| Limitations, ethics, fairness, AI transparency | 10% |
| Komunikasi dan respons terhadap pertanyaan | 10% |
| Total | 100% dari UAS = 20% MK |
Gunakan checklist dengan komponen dan bobot : Komponen minimum: data provenance, raw/processed separation, executable script, fixed seed, environment information, model object/parameter, generated tables/figures, AI declaration, dan README.
Mahasiswa menerima satu mini-case atau cuplikan hasil analisis yang belum sempurna dan harus:
Cakupan kasus dapat mengintegrasikan: problem→data→model→decision; ML/classification; clustering/PCA/spatial; validation dan uncertainty; policy linkage; serta responsible AI. Bobot tetap mengikuti rubrik UAS RPS di atas dan tidak dibuat menjadi skema penilaian baru.
Folder minimum:
capstone/
README.md
data_raw/ # bila lisensi mengizinkan
data_processed/
R/
01_import.R
02_clean.R
03_eda.R
04_model.R
05_validate.R
06_visualize.R
report/
final_report.Rmd
dashboard/
output/
metadata/
data_dictionary.csv
provenance.csv
ai_use_log.csv
sessionInfo.txt
Final package dianggap berhasil jika dosen dapat mengikuti README dan meregenerasi tabel/grafik utama tanpa menebak langkah tersembunyi.
Jika sebuah angka pada slide tidak dapat ditelusuri ke kode atau tabel sumber, angka tersebut belum siap menjadi bukti kebijakan. Audit trail adalah perlindungan terhadap kesalahan analitik dan ketergantungan berlebihan pada AI.
Mahasiswa memperoleh Project=84, Partisipasi=90, Kuis=80, Tugas=88, UTS=76, UAS=82. Nilai numerik: Konversi ke huruf mengikuti ketentuan akademik program/universitas yang berlaku; e-book tidak menetapkan boundary huruf bila belum diberikan secara resmi.
Oral defense bertujuan membedakan team product dan individual understanding. Dosen dapat memilih satu grafik, satu formula, satu code chunk, dan satu recommendation secara acak. Mahasiswa harus menjelaskan: - apa input dan output; - mengapa metode dipilih; - apa asumsi; - apa alternative; - apa keterbatasan; - bagaimana hasil memengaruhi keputusan.
Dosen/peer reviewer menjalankan project dari clean session. Failure modes umum:
| Pertanyaan | Bukti yang diharapkan |
|---|---|
| “Apa masalahnya?” | decision question dan stakeholder |
| “Mengapa data ini?” | metadata, representativeness, period |
| “Mengapa model ini?” | baseline comparison + validation |
| “Seberapa pasti?” | CV/bootstrap/sensitivity/calibration |
| “Apakah adil?” | subgroup analysis bila relevan |
| “Apakah spasial?” | map + W sensitivity jika dipakai |
| “Apa tindakan?” | recommendation traceable to findings |
| “Apa peran AI?” | AI-use log + verification |
Pekerjaan magister tidak ditentukan oleh jumlah algoritma. Standar yang diharapkan adalah argumentasi: mahasiswa mampu menjelaskan mengapa satu pilihan analitik lebih defensible daripada alternatif, mengukur uncertainty, mengenali asumsi yang rapuh, serta menahan diri dari klaim yang tidak didukung. Project dengan model sederhana tetapi argumentasi, validasi, dan policy translation kuat dapat lebih unggul daripada model kompleks yang tidak dipahami.
# Contoh artefak audit sederhana.
files_needed <- c(
"Sains_Data_Inovasi_Regional.Rmd",
"references.bib",
"data/simulasi_panel_regional.csv",
"R/00_setup.R"
)
tibble(file = files_needed, tersedia = file.exists(files_needed)) |>
knitr::kable(caption = "Contoh reproducibility checklist")| file | tersedia |
|---|---|
| Sains_Data_Inovasi_Regional.Rmd | TRUE |
| references.bib | TRUE |
| data/simulasi_panel_regional.csv | TRUE |
| R/00_setup.R | TRUE |
audit_plot <- tibble::tibble(file = files_needed, tersedia = file.exists(files_needed))
ggplot2::ggplot(audit_plot, ggplot2::aes(reorder(file, tersedia), as.integer(tersedia), fill = tersedia)) +
ggplot2::geom_col(show.legend = FALSE) +
ggplot2::coord_flip() +
ggplot2::scale_y_continuous(breaks = c(0,1), labels = c("Tidak", "Ya")) +
ggplot2::scale_fill_manual(values = c("TRUE" = "#145B8C", "FALSE" = "#C99A17")) +
ggplot2::labs(title = "Status artefak reproducibility", x = NULL, y = "Tersedia")Untuk data open data, tim menyimpan URL sumber dan metadata, bukan mengklaim kepemilikan data. Bila lisensi membatasi redistribusi, repository menyimpan script download dan checksum/versi, bukan file mentah.
Kartu dataset real untuk final project.
#> R version 4.5.1 (2025-06-13)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Sonoma 14.5
#>
#> Matrix products: default
#> BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
#>
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#>
#> time zone: Asia/Jakarta
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] httr2_1.2.3 jsonlite_2.0.0 leaflet_2.2.2 tmap_4.1
#> [5] spdep_1.3-13 spData_2.3.4 sf_1.0-21 factoextra_1.0.7
#> [9] cluster_2.1.8.1 ranger_0.17.0 yardstick_1.3.2 workflowsets_1.1.1
#> [13] workflows_1.3.0 tune_2.0.1 tailor_0.1.0 rsample_1.3.1
#> [17] recipes_1.3.1 parsnip_1.4.1 modeldata_1.5.1 infer_1.1.0
#> [21] dials_1.4.2 scales_1.4.0 tidymodels_1.4.1 broom_1.0.12
#> [25] knitr_1.50 skimr_2.2.2 janitor_2.2.1 lubridate_1.9.5
#> [29] forcats_1.0.1 stringr_1.6.0 dplyr_1.2.1 purrr_1.2.0
#> [33] readr_2.2.0 tidyr_1.3.1 tibble_3.3.1 ggplot2_4.0.1
#> [37] tidyverse_2.0.0
#>
#> loaded via a namespace (and not attached):
#> [1] splines_4.5.1 leaflegend_1.2.1 hardhat_1.4.2
#> [4] XML_3.99-0.18 rpart_4.1.24 sparsevctrs_0.3.4
#> [7] lifecycle_1.0.5 rstatix_0.7.2 globals_0.18.0
#> [10] lattice_0.22-7 vroom_1.7.1 MASS_7.3-65
#> [13] crosstalk_1.2.1 backports_1.5.0 magrittr_2.0.4
#> [16] sass_0.4.10 rmarkdown_2.30 jquerylib_0.1.4
#> [19] yaml_2.3.10 otel_0.2.0 sp_2.2-0
#> [22] DBI_1.2.3 RColorBrewer_1.1-3 multcomp_1.4-28
#> [25] abind_1.4-8 spatialreg_1.3-6 nnet_7.3-20
#> [28] TH.data_1.1-3 rappdirs_0.3.3 sandwich_3.1-1
#> [31] ipred_0.9-15 lava_1.8.1 ggrepel_0.9.6
#> [34] listenv_0.10.0 terra_1.8-54 units_0.8-7
#> [37] parallelly_1.45.0 codetools_0.2-20 tidyselect_1.2.1
#> [40] raster_3.6-32 farver_2.1.2 base64enc_0.1-3
#> [43] cols4all_0.9 e1071_1.7-16 Formula_1.2-5
#> [46] survival_3.8-3 tools_4.5.1 Rcpp_1.1.0
#> [49] glue_1.8.0 prodlim_2025.04.28 xfun_0.54
#> [52] leaflet.providers_2.0.0 mgcv_1.9-3 withr_3.0.2
#> [55] fastmap_1.2.0 boot_1.3-31 digest_0.6.38
#> [58] timechange_0.4.0 R6_2.6.1 microbenchmark_1.5.0
#> [61] colorspace_2.1-2 wk_0.9.4 spacesXYZ_1.6-0
#> [64] LearnBayes_2.15.1 dichromat_2.0-0.1 utf8_1.2.6
#> [67] generics_0.1.4 data.table_1.18.2.1 class_7.3-23
#> [70] htmlwidgets_1.6.4 tmaptools_3.2 pkgconfig_2.0.3
#> [73] gtable_0.3.6 timeDate_4051.111 GPfit_1.0-9
#> [76] S7_0.2.1 furrr_0.3.1 htmltools_0.5.8.1
#> [79] carData_3.0-5 bookdown_0.43 png_0.1-8
#> [82] gower_1.0.2 snakecase_0.11.1 rstudioapi_0.17.1
#> [85] tzdb_0.5.0 coda_0.19-4.1 nlme_3.1-168
#> [88] repr_1.1.7 proxy_0.4-27 cachem_1.1.0
#> [91] zoo_1.8-15 KernSmooth_2.23-26 parallel_4.5.1
#> [94] s2_1.1.9 leafsync_0.1.0 pillar_1.11.1
#> [97] grid_4.5.1 logger_0.4.0 vctrs_0.7.3
#> [100] ggpubr_0.6.1 car_3.1-3 lhs_1.2.0
#> [103] evaluate_1.0.5 mvtnorm_1.3-3 cli_3.6.5
#> [106] compiler_4.5.1 rlang_1.3.0 crayon_1.5.3
#> [109] maptiles_0.10.0 future.apply_1.20.0 ggsignif_0.6.4
#> [112] labeling_0.4.3 classInt_0.4-11 stringi_1.8.7
#> [115] modelenv_0.2.0 viridisLite_0.4.2 deldir_2.0-4
#> [118] stars_0.6-8 Matrix_1.7-3 hms_1.1.4
#> [121] bit64_4.6.0-1 leafem_0.2.4 future_1.58.0
#> [124] igraph_2.1.4 bslib_0.11.0 lwgeom_0.2-14
#> [127] bit_4.6.0 DiceDesign_1.10
Checklist akhir repository:
README menjelaskan pertanyaan, data, cara menjalankan project.data/raw tidak berisi data sensitif.Presentasi final harus berakhir dengan opsi tindakan dan batas bukti, bukan dengan “akurasi model 87%”. Contoh penutup yang lebih substantif: “Model membantu menyaring 20% wilayah dengan risiko tertinggi, tetapi error lebih besar pada wilayah berdata jarang; karena itu rekomendasi kami adalah menggunakan model sebagai tahap screening yang diikuti verifikasi lapangan, bukan keputusan otomatis.”
Serahkan paket final yang dapat direproduksi: Rmd/report, kode, instruksi data, tabel/figur utama, dashboard bila relevan, executive policy brief, deklarasi penggunaan AI, dan bahan presentasi.
UAS terdiri dari analytical synthesis individual dan oral defense. Mahasiswa tidak dinilai dari hafalan syntax R, tetapi dari kemampuan menjelaskan keputusan analitik, membaca output, menemukan risiko validitas, dan menghubungkan hasil dengan keputusan regional.
Milestone akhir: repository reproducible, dashboard/visual, policy memo, presentasi, dan defense. UAS individual menguji kemampuan menjelaskan metode serta mengkritik keterbatasan proyek.
Capstone yang baik dapat diaudit, direproduksi, dan dipertahankan secara substantif. Tujuan akhir bukan memamerkan algoritma, tetapi meningkatkan kualitas keputusan regional dengan bukti yang transparan.
Bagian ini berfungsi sebagai indeks cepat. Penjelasan, asumsi, dan contoh terdapat pada bab terkait.
| Topik | Rumus inti |
|---|---|
| Weighted index | |
| Rate | |
| Growth | |
| Z-score | |
| Mean/variance | , |
| Correlation | |
| Gini | |
| OLS | |
| VIF | |
| RMSE | |
| MAE | |
| Ridge | |
| Lasso | |
| Gini impurity | |
| RF regression | |
| Logistic | |
| Sensitivity | |
| Precision | |
| F1 | |
| K-means | |
| Silhouette | |
| PCA eigen | |
| PVE | |
| Moran’s I | |
| Bootstrap SE | |
| DID |
| Istilah | Definisi operasional dalam mata kuliah |
|---|---|
| Analytical question | pertanyaan yang dapat dijawab dengan data/metode dan diturunkan dari masalah keputusan |
| Outcome | variabel target yang dijelaskan, diprediksi, atau dievaluasi |
| Feature/predictor | informasi yang digunakan untuk menjelaskan/memprediksi outcome |
| Unit observasi | entitas satu baris data, misalnya kabupaten–tahun |
| Unit analisis | unit yang menjadi dasar inferensi/interpretasi; sering sama tetapi tidak selalu dengan unit observasi |
| Denominator | populasi dasar suatu rate/proportion |
| Provenance | jejak asal data, versi, transformasi, lisensi, dan tanggal akses |
| Metadata | informasi tentang definisi, satuan, periode, metode produksi, dan struktur data |
| Tidy data | struktur satu variabel per kolom, satu observasi per baris, satu jenis unit per tabel |
| Missingness | keadaan nilai tidak teramati; mekanismenya dapat memengaruhi bias |
| Outlier | observasi ekstrem; dapat berupa error atau fenomena substantif valid |
| Feature engineering | konstruksi fitur baru dari data mentah untuk merepresentasikan konsep yang lebih relevan |
| Leakage | informasi yang tidak seharusnya tersedia saat prediksi masuk ke training/preprocessing |
| EDA | exploratory data analysis: iterasi pertanyaan–visualisasi–pola–pertanyaan baru |
| Association | hubungan statistik, tidak otomatis kausal |
| Prediction | estimasi outcome pada observasi/waktu baru |
| Causal effect | perubahan outcome akibat intervensi/perlakuan di bawah definisi estimand dan asumsi identifikasi |
| Baseline model | model/rule sederhana sebagai pembanding wajib |
| Loss function | fungsi yang mengukur biaya kesalahan prediksi |
| Empirical risk | rata-rata loss pada sample training |
| Generalization | kemampuan perform pada data baru dari target deployment |
| Cross-validation | resampling untuk estimasi perform/tuning menggunakan training data |
| RMSE | akar mean squared error; menekankan error besar |
| MAE | mean absolute error; error absolut rata-rata |
| Calibration | kesesuaian predicted probability dengan observed frequency |
| Discrimination | kemampuan model membedakan/ranking kelas positif vs negatif |
| Threshold | batas probabilitas/score untuk mengubah prediksi menjadi tindakan/kelas |
| Random forest | ensemble randomized decision trees dengan agregasi prediksi |
| Boosting | ensemble sequential yang menambah weak learners untuk mengurangi loss |
| Regularization | penalti kompleksitas untuk mengontrol variance/overfitting |
| Clustering | pengelompokan unsupervised berdasarkan similarity yang didefinisikan |
| Centroid | pusat rata-rata cluster dalam K-means |
| Silhouette | ukuran compactness dan separation per observasi |
| PCA | rotasi linear yang mencari arah variance maksimum |
| Loading | coefficient/eigenvector yang membentuk principal component |
| Score PCA | koordinat observasi pada principal component |
| PVE | proportion of variance explained oleh komponen |
| CRS | coordinate reference system untuk menginterpretasi koordinat spasial |
| Spatial weights | definisi matematis siapa bertetangga/berinteraksi dengan siapa |
| Spatial lag | weighted combination nilai pada tetangga |
| Moran’s I | ukuran global spatial autocorrelation |
| LISA | local indicators of spatial association |
| MAUP | perubahan hasil akibat skala/zoning unit areal |
| Ecological fallacy | kesalahan menerapkan hubungan agregat kepada individu |
| Bootstrap | resampling dengan replacement untuk mengestimasi sampling variability |
| Robustness | kestabilan kesimpulan terhadap reasonable analytic alternatives |
| Sensitivity analysis | evaluasi bagaimana hasil berubah saat asumsi/parameter diubah |
| Fairness | evaluasi distribusi perform/keputusan di kelompok relevan; definisinya kontekstual |
| DID | difference-in-differences untuk evaluasi perubahan treated vs control dengan asumsi tertentu |
| Policy brief | dokumen ringkas yang menghubungkan bukti, opsi, rekomendasi, dan caveat |
| Dashboard | antarmuka monitoring/exploration; bukan pengganti analisis metodologis |
| Reproducibility | kemampuan pihak lain meregenerasi hasil dari data, kode, parameter, dan environment |
| AI-use declaration | catatan transparan tentang tujuan, bagian yang dibantu AI, dan metode verifikasi |
| Model card | dokumentasi intended use, data, metrics, limitations, dan risiko model |
| Datasheet | dokumentasi asal, komposisi, collection, preprocessing, penggunaan, limitations dataset |
Mulai dari objective Ekspansi: Turunkan terhadap : Set sama dengan nol: Jika invertibel: Ini menunjukkan OLS berasal langsung dari minimisasi SSE, bukan formula yang muncul tanpa alasan.
Untuk konstanta , minimalkan Turunan: Set nol memberi . Inilah alasan leaf prediction regression tree adalah mean pada node bila loss squared error.
Untuk fungsi tidak differentiable di data points, tetapi subgradient berubah tanda ketika jumlah observasi di bawah dan di atas seimbang. Solusi berada pada median. Ini menjelaskan hubungan natural MAE dengan median-type prediction.
Dari exponentiate: Maka sehingga
Variance projection adalah Cari dengan . Lagrangian: Turunan terhadap : Jadi arah principal component adalah eigenvector covariance/correlation matrix.
Misalkan , , . Untuk estimator : Cross-term dengan hilang karena mean nol dan independensi yang diasumsikan. Tambah-kurang menghasilkan Tiga komponen adalah irreducible noise, squared bias, dan variance.
Untuk satu cluster , minimalkan Turunan vector: sehingga Karena itu update centroid adalah mean anggota cluster.
Jika independen dengan variance : Maka , diestimasi dengan .
Odds . Sebaliknya Jika odds dikalikan OR, probability baru adalah Rumus ini menunjukkan perubahan probability bergantung pada baseline .
Pembilang besar positif jika neighbors memiliki deviasi dengan tanda sama; negatif jika tanda berlawanan. Penyebut menormalisasi overall variance dan menyesuaikan total bobot. Karena nilai ekspektasi null bergantung struktur W dan n, inference sebaiknya menggunakan teori/permutation yang tepat, bukan membandingkan sekadar dengan nol.
Sebelum menyerahkan tugas/project, pastikan:
Daftar pustaka berikut dihasilkan dari references.bib. URL sumber data dipertahankan agar mahasiswa dapat memeriksa metadata, tahun cakupan, versi, dan tanggal akses. Untuk dataset yang terus diperbarui, status data harus diverifikasi kembali pada saat project dikerjakan.