Kemiskinan mencerminkan rendahnya tingkat pendapatan seseorang
sehingga tidak mampu memenuhi standar hidup yang layak (Corral et al.,
2020). Kondisi ini, jika berlangsung dalam jangka panjang, dapat
menimbulkan berbagai dampak sosial dan ekonomi seperti meningkatnya
ketimpangan sosial, terhambatnya pembangunan, munculnya konflik
horizontal, serta naiknya tingkat kriminalitas (UN, 2023). Apabila tidak
diatasi secara tepat, kemiskinan berpotensi menciptakan siklus
antargenerasi yang sulit diputus (Rivera & Currais, 1999; Benhabib
& Spiegel, 1994; Lucas, 1990).
Meskipun tingkat kemiskinan di Indonesia, khususnya di Provinsi Jawa Barat, terus mengalami penurunan hingga mencapai 7,46% pada tahun 2024, persentase penduduk miskin dalam periode 2020–2024 cenderung stagnan. Hal ini menunjukkan perlunya analisis lebih mendalam terhadap faktor-faktor yang memengaruhi kemiskinan agar kebijakan penanggulangannya di Jawa Barat dapat dirancang secara lebih efektif dan berkelanjutan.
Pemetaan persentase kemiskinan di kabupaten/kota Provinsi Jawa Barat menunjukkan adanya pola spasial yang jelas, di mana daerah dengan tingkat kemiskinan tinggi cenderung berdekatan dengan daerah lain yang juga memiliki tingkat kemiskinan tinggi, begitu pula sebaliknya. Misalnya, beberapa wilayah di bagian selatan Jawa Barat seperti Kabupaten Garut, Tasikmalaya, dan Cianjur memperlihatkan tingkat kemiskinan yang relatif lebih tinggi dibandingkan wilayah utara seperti Kota Bandung atau Kota Bekasi. Pola pengelompokan ini mencerminkan adanya pola spasial, yaitu kecenderungan nilai suatu wilayah dipengaruhi oleh nilai wilayah tetangganya.
Fenomena tersebut dapat terjadi karena adanya kesamaan karakteristik sosial-ekonomi, seperti keterbatasan akses terhadap infrastruktur, lapangan kerja, dan kualitas pendidikan di wilayah yang berdekatan. Selain itu, interaksi antarwilayah seperti arus tenaga kerja, perdagangan lokal, maupun keterkaitan geografis juga dapat memperkuat keterhubungan antar tingkat kemiskinan. Dengan demikian, kondisi ini menunjukkan bahwa data kemiskinan di Jawa Barat tidak bersifat acak melainkan saling bergantung secara spasial (spatial dependence).
Ketika dependensi spasial ini diabaikan dan model regresi klasik (OLS) tetap digunakan, hasil estimasi yang diperoleh berpotensi bias dan tidak efisien karena pelanggaran asumsi independensi antar observasi. Oleh sebab itu, penggunaan pendekatan ekonometrika spasial menjadi penting untuk ditinjau sehingga akan menggambarkan hubungan spasial secara lebih akurat serta memahami bagaimana kemiskinan di suatu daerah dipengaruhi oleh kondisi di daerah sekitarnya.
Maksud dari penelitian ini adalah untuk menerapkan pendekatan spasial untuk menganalisis faktor yang mempengaruhi kemiskinan di Jawa Barat pada tahun 2024. Melalui analisis spasial, penelitian ini bertujuan untuk memperoleh model terbaik yang dapat menjelaskan hubungan antarwilayah serta faktor-faktor utama yang berpengaruh terhadap kemiskinan di Jawa Barat.
Penelitian ini dibatasi pada wilayah Provinsi Jawa Barat dengan unit analisis kabupaten/kota. Analisis difokuskan pada pola spasial kemiskinan tanpa membahas aspek penyebab non-spasial secara mendalam. Selain itu, penelitian ini hanya menggunakan data tahun 2024 sehingga hasilnya menggambarkan kondisi pada periode tertentu dan tidak mencakup dinamika perubahan antarwaktu.
Dalam analisis spasial, keterkaitan antar wilayah secara spasial diukur menggunakan Moran’s I. Nilai I > 0 menunjukkan adanya autokorelasi spasial positif, yaitu wilayah dengan nilai mirip (high-high atau low-low) cenderung berdekatan. Sebaliknya, I < 0 menandakan pola checkerboard (high-low), sedangkan I ≈ 0 menunjukkan pola yang acak. Dalam perhitungannya, Moran’s I memanfaatkanmatriks bobot spasial (W) yang menentukan seberapa kuat pengaruh satu wilayah terhadap wilayah lain berdasarkan kriteria kedekatan tertentu, yakni Rook, Queen, ataupun Jarak. Selain Moran’s I, terdapat metode pengukuran lain seperti Greary’s C untuk ukuran Global, serta Local Moran’s I dan Getis-Ord G* untuk ukuran lokal.
OLS adalah metode estimasi parameter untuk regresi klasik. Metode ini membutuhkan pemenuhan pengujian asumsi klasik, diantaranya pengujian multikolinearitas, residual berdistribusi normal, dan homoskedastisitas. Metode ini mengasumsikan bahwa error antarwilayah bersifat independen dan homogen, sehingga tidak dapat menangkap spillover atau pengaruh kemiskinan dari satu daerah ke daerah lain. Hal ini menyebabkan hasil estimasi menjadi bias dan kurang akurat. Untuk mengatasi keterbatasan tersebut, digunakan model ekonometrika spasial yang mampu memperhitungkan spatial dependence antarwilayah.
Adapun model matematis OLS adalah sebagai berikut: \[ Y = X\beta + \varepsilon \]
Uji ini digunakan untuk mengidentifikasi ada tidaknya dependensi spasial pada model. Jika hasil uji menunjukkan adanya dependensi lag, maka digunakan model Spatial Autoregressive (SAR). Jika yang muncul adalah dependensi galat, maka digunakan model Spatial Error Model (SEM). Uji ini membantu menentukan model spasial yang paling sesuai sebelum analisis lanjut.
Uji Pengganda Lagrange pada Lag
\[ H_0 : \rho = 0, \quad \text{(tidak terdapat dependensi spasial pada lag)} \] \[ H_1 : \rho \ne 0, \quad \text{(terdapat dependensi spasial pada lag)} \]
Uji Pengganda Lagrange pada Galat
\[ H_0 : \lambda = 0, \quad \text{(tidak terdapat dependensi spasial pada galat)} \] \[ H_1 : \lambda \ne 0, \quad \text{(terdapat dependensi spasial pada galat)} \]
Menurut Anselin (2003), Spatial Autoregressive Model (SAR) merupakan pengembangan dari model OLS dengan menambahkan pengaruh lag pada variabel dependen. Model ini digunakan ketika λ = 0, sehingga hanya mempertimbangkan proses autoregresif pada variabel respon. Dengan kata lain, SAR menunjukkan bahwa nilai variabel dependen di suatu wilayah dipengaruhi oleh nilai variabel dependen di wilayah-wilayah tetangganya, sesuai dengan hubungan spasial yang terbentuk dalam model.
\[ Y = \rho W Y + X\beta + \varepsilon \]
Asumsi penting dalam model SAR adalah bahwa residual tidak mengalami autokorelasi spasial, sehingga pengaruh spasial telah sepenuhnya ditangkap oleh komponen lag variabel dependen. Jika asumsi ini terpenuhi, maka model SAR dianggap tepat untuk menggambarkan struktur keterkaitan spasial dalam data.
Menurut Suryaningrat, S. H. (2021) Akaike Information Criterion (AIC) merupakan metode analisis yang digunakan untuk memperoleh model yang terbaik dengan menggunakan estimasi maximum likelihood sebagai perhitungan yang sesuai. AIC mempertimbangkan keseimbangan antara kompleksitas model (jumlah parameter) dan kecocokan model terhadap data (likelihood).
AIC dihitung dengan rumus:
\[ AIC = 2k - 2\ln(\hat{L}) \]
di mana k adalah jumlah parameter dalam model dan L adalah nilai maksimum dari fungsi likelihood. Model dengan nilai AIC yang lebih rendah dianggap lebih baik karena menunjukkan kompleksitas yang wajar namun tetap mampu menjelaskan data dengan baik.
Penelitian ini menggunakan data sekunder yang diperoleh dari Badan Pusat Statistik (BPS) tahun 2024 dengan unit analisis sebanyak 27 kabupaten/kota di Provinsi Jawa Barat. Data yang digunakan bersifat cross section dan mencerminkan kondisi sosial ekonomi daerah yang diduga berpengaruh terhadap tingkat kemiskinan.
Variabel yang digunakan terdiri atas satu variabel dependen yaitu kemiskinan, yang diukur melalui persentase penduduk miskin menurut kabupaten/kota, serta empat variabel independen yaitu Tingkat Pengangguran Terbuka (TPT), Produk Domestik Regional Bruto (PDRB) per kapita, Indeks Pembangunan Manusia (IPM), dan Gini Ratio. Keempat variabel tersebut dipilih karena secara teori memiliki hubungan erat dengan tingkat kesejahteraan dan ketimpangan sosial ekonomi masyarakat.
Selain data atribut, penelitian ini juga menggunakan data spasial berupa peta batas administrasi kabupaten/kota di Jawa Barat yang diperoleh dari geoBoundaries Indonesia Administrative Level 2 (ADM2) melalui situs www.geoboundaries.org dalam format shapefile (.shp). Data ini digunakan untuk membentuk hubungan antarwilayah dalam analisis spasial.
Analisis dilakukan menggunakan pendekatan statistik spasial dengan bantuan perangkat lunak R. Pendekatan ini bertujuan untuk mengidentifikasi pengaruh faktor sosial ekonomi terhadap tingkat kemiskinan serta mendeteksi adanya ketergantungan spasial antarwilayah di Jawa Barat. Analisis diawali dengan uji autokorelasi spasial global (Moran’s I, Geary’s C) dan lokal (LISA serta Getis-Ord Gi*) untuk melihat pola keterkaitan antarwilayah.
Selanjutnya digunakan model regresi OLS sebagai dasar analisis hubungan antarvariabel, diikuti uji Lagrange Multiplier (LM) untuk menentukan model spasial yang tepat. Beberapa model yang dipertimbangkan mencakup SAR, SDM, SAC/SARAR, dan GNS. Pemilihan model terbaik dilakukan berdasarkan nilai AIC, signifikansi parameter spasial (ρ dan λ), serta kesesuaian teori yang mendukung hubungan spasial antarwilayah.
Analisis deskriptif dilakukan untuk memberikan gambaran umum mengenai karakteristik data penelitian. Hasil analisis deskriptif data dapat dilihat pada tabel berikut:
| Variabel | Rata_rata | Minimum | Maksimum | Simpangan_Baku |
|---|---|---|---|---|
| Kemiskinan | 8.01 | 2.34 | 11.93 | 2.65 |
| TPT | 6.52 | 1.58 | 8.97 | 1.71 |
| PDRB | 53.11 | 24.91 | 147.08 | 33.26 |
| IPM | 74.68 | 68.89 | 83.75 | 4.33 |
| Gini Ratio | 0.37 | 0.29 | 0.48 | 0.05 |
Berdasarkan hasil analisis deskriptif, rata-rata tingkat kemiskinan di Jawa Barat sebesar 8,01%, dengan nilai terendah 2,34% dan tertinggi 11,93%, serta simpangan baku sebesar 2,65, yang menunjukkan adanya variasi cukup besar antarwilayah. Variasi ini tampak jelas pada peta persebaran, di mana wilayah selatan seperti Kabupaten Garut, Tasikmalaya, dan Cianjur memiliki tingkat kemiskinan yang lebih tinggi dibandingkan wilayah perkotaan seperti Kota Bandung, Kota Bekasi, dan Kota Depok.
Tingkat Pengangguran Terbuka (TPT) memiliki rata-rata
6,52%, dengan sebaran yang juga menunjukkan ketimpangan
antarwilayah, di mana daerah perkotaan cenderung memiliki TPT lebih
tinggi akibat tingginya kompetisi kerja di sektor formal.
PDRB per kapita rata-rata mencapai 53,11 juta rupiah,
dengan rentang nilai yang lebar (24,91–107,08 juta) dan simpangan baku
tinggi (33,26), mengindikasikan adanya kesenjangan
ekonomi antar daerah. Wilayah seperti Kota Bekasi dan Kota Bandung
memiliki nilai PDRB yang jauh lebih tinggi dibandingkan daerah pedesaan
di selatan.
Sementara itu, IPM rata-rata sebesar 74,68,
menandakan bahwa sebagian besar kabupaten/kota di Jawa Barat telah
mencapai tingkat pembangunan manusia yang cukup baik. Namun demikian,
masih terdapat ketimpangan antarwilayah, dengan nilai IPM lebih rendah
di bagian selatan provinsi.
Rasio Gini yang rata-rata sebesar 0,37 menunjukkan
tingkat ketimpangan pendapatan yang tergolong sedang, dengan variasi
kecil antarwilayah (simpangan baku 0,05).
Secara keseluruhan, hasil deskriptif dan peta tematik menunjukkan adanya perbedaan yang nyata antarwilayah dalam aspek sosial dan ekonomi. Pola spasial yang muncul, seperti pengelompokan wilayah dengan tingkat kemiskinan tinggi di selatan dan tingkat kemiskinan rendah di utara, mengindikasikan adanya spatial dependence atau keterkaitan spasial antarwilayah di Jawa Barat. Hal ini menjadi dasar penting untuk melakukan analisis lanjutan menggunakan model ekonometrika spasial.
\[ Y = 44.770 - 0.0879(\text{TPT}) - 0.0046(\text{PDRB}) - 0.5521(\text{IPM})^{***} + 14.2366(\text{GINI}) \]
| Statistik_Uji | F | p | Ket |
|---|---|---|---|
| Ramsey RESET | 0.476 | 0.6281 | Hubungan linier |
| Statistik_Uji | W | p | Ket |
|---|---|---|---|
| Shapiro–Wilk | 0.9552 | 0.2865 | Data berdistribusi normal |
| Statistik_Uji | BP | p | Ket |
|---|---|---|---|
| Breusch-Pagan Test | 2.56 | 0.6339 | Tidak terdapat heteroskedastisitas pada data. |
| Statistik_Uji | I | p_Monte_Carlo | Ket |
|---|---|---|---|
| Moran’s I | 2.3277 | 0.015 | Terdapat autokorelasi spasial pada error |
Berdasarkan hasil estimasi model Ordinary Least Square (OLS), seluruh asumsi klasik pada model telah terpenuhi, meliputi uji linearitas, normalitas, dan homoskedastisitas. Hasil uji Ramsey RESET menunjukkan nilai p-value sebesar 0,6281, yang mengindikasikan bahwa hubungan antara variabel dependen dan independen bersifat linier. Uji Shapiro–Wilk menghasilkan p-value 0,2865, sehingga residual berdistribusi normal. Selain itu, uji Breusch–Pagan dengan p-value 0,6339 menunjukkan tidak adanya masalah heteroskedastisitas pada model.
Namun, hasil uji Moran’s I pada residual memberikan nilai I = 2,3277 dengan p-value 0,015, yang berarti terdapat autokorelasi spasial pada residual. Dengan demikian, meskipun model OLS memenuhi asumsi klasik, adanya indikasi dependensi spasial menandakan bahwa model ini belum sepenuhnya sesuai digunakan untuk data yang memiliki keterkaitan antarwilayah. Oleh karena itu, perlu dilakukan analisis lanjutan menggunakan model ekonometrika spasial seperti SAR, SAC/SARAR, GNS atau SDM untuk menangkap efek spasial secara lebih akurat.
| Variabel | Morans_I | Z | p_permutasi | Ket |
|---|---|---|---|---|
| Kemiskinan | 0.283 | 3.65 | 0.001 | Signifikan |
| TPT | 0.511 | 4.07 | 0.001 | Signifikan |
| PDRB | 0.211 | 1.86 | 0.102 | Tidak Signifikan |
| IPM | 0.275 | 2.24 | 0.032 | Signifikan |
| GINI | 0.299 | 2.40 | 0.036 | Signifikan |
Berdasarkan hasil uji Moran’s I untuk masing-masing variabel, dapat diketahui bahwa sebagian besar variabel menunjukkan adanya autokorelasi spasial yang signifikan, yang berarti nilai suatu wilayah cenderung dipengaruhi oleh nilai di wilayah sekitarnya.
Nilai Moran’s I untuk variabel kemiskinan sebesar 0,283 (p = 0,001) menunjukkan adanya keterkaitan spasial positif yang signifikan. Artinya, kabupaten/kota dengan tingkat kemiskinan tinggi cenderung berdekatan dengan wilayah lain yang juga memiliki tingkat kemiskinan tinggi, dan sebaliknya. Pola ini menegaskan adanya pengelompokan (spatial clustering) kemiskinan di Jawa Barat.
Variabel Tingkat Pengangguran Terbuka (TPT) memiliki nilai Moran’s I paling tinggi, yaitu 0,511 (p = 0,001), yang mengindikasikan keterkaitan spasial yang sangat kuat. Hal ini menunjukkan bahwa wilayah dengan tingkat pengangguran tinggi cenderung berdekatan dengan wilayah lain yang memiliki karakteristik serupa, kemungkinan karena kesamaan struktur ekonomi dan kesempatan kerja antarwilayah berdekatan.
Variabel PDRB per kapita memiliki nilai Moran’s I 0,211 dengan p-value 0,102, yang berarti tidak signifikan secara spasial. Artinya, distribusi PDRB per kapita antarwilayah di Jawa Barat relatif acak dan tidak menunjukkan pola pengelompokan spasial yang kuat — kemungkinan karena perbedaan sektor unggulan antarwilayah (misalnya industri di utara dan pertanian di selatan).
Sementara itu, variabel IPM (0,275; p = 0,032) dan Rasio Gini (0,299; p = 0,036) sama-sama menunjukkan autokorelasi spasial positif yang signifikan. Ini menandakan bahwa tingkat pembangunan manusia dan ketimpangan pendapatan di suatu kabupaten/kota cenderung menyerupai wilayah yang berdekatan, yang bisa disebabkan oleh kesamaan dalam akses pendidikan, kesehatan, serta distribusi sumber daya ekonomi antarwilayah.
Secara keseluruhan, hasil ini memperkuat bukti adanya dependensi spasial antarwilayah di Jawa Barat, terutama pada variabel kemiskinan, TPT, IPM, dan Gini Ratio, sehingga analisis spasial lebih lanjut sangat diperlukan untuk memodelkan hubungan antarvariabel secara lebih akurat.
| Variabel | Gearys_C |
|---|---|
| Kemiskinan | 0.410 |
| TPT | 0.465 |
| PDRB | 0.660 |
| IPM | 0.607 |
| GINI | 0.504 |
Dari hasil tersebut, variabel kemiskinan (0,410) dan TPT (0,465) memiliki nilai Geary’s C yang cukup jauh di bawah 1, menunjukkan autokorelasi spasial positif yang kuat. Artinya, wilayah dengan tingkat kemiskinan atau pengangguran tinggi cenderung berdekatan dengan wilayah lain yang juga memiliki nilai tinggi.
Variabel IPM (0,607) dan Gini Ratio (0,504) juga menunjukkan autokorelasi spasial positif, meskipun dengan tingkat yang lebih moderat dibanding dua variabel sebelumnya. Hal ini menandakan bahwa pembangunan manusia dan ketimpangan pendapatan memiliki pola pengelompokan antarwilayah yang masih cukup nyata.
Sementara itu, nilai Geary’s C PDRB (0,660) mendekati 1, mengindikasikan autokorelasi spasial lemah atau hampir tidak ada keterkaitan spasial pada distribusi PDRB antar kabupaten/kota di Jawa Barat.
Secara keseluruhan, hasil Geary’s C ini konsisten dengan uji Moran’s I sebelumnya, di mana sebagian besar variabel (kecuali PDRB) menunjukkan adanya pola spasial positif, sehingga memperkuat indikasi adanya pengaruh spasial yang perlu diperhatikan dalam pemodelan ekonometrika spasial.
Hasil analisis Local Moran’s I (LISA) menunjukkan adanya pola pengelompokan spasial pada variabel sosial-ekonomi di Jawa Barat.
Untuk kemiskinan, terdapat klaster High-High di wilayah Garut dan Tasikmalaya, yang berarti daerah dengan kemiskinan tinggi berdekatan dengan daerah berkemiskinan tinggi lainnya. Sementara itu, klaster Low-Low muncul di wilayah utara, seperti Kota Bandung dan sekitarnya, yang menunjukkan daerah dengan kemiskinan rendah cenderung berdekatan dengan wilayah serupa.
TPT, IPM, dan Rasio Gini menunjukkan pola Low-Low, menandakan adanya pengelompokan wilayah dengan pengangguran, pembangunan manusia, dan ketimpangan pendapatan yang relatif rendah. Sedangkan PDRB per kapita tidak menunjukkan klaster signifikan, sehingga distribusinya bersifat acak.
Secara keseluruhan, hasil LISA mengonfirmasi adanya pola spasial lokal pada sebagian besar variabel, terutama kemiskinan, yang memperkuat adanya keterkaitan antarwilayah di Jawa Barat.
Hasil analisis Getis-Ord G* menunjukkan bahwa kemiskinan membentuk klaster hot spot di wilayah Bogor dan sekitarnya (high-high) serta cold spot di bagian barat Jawa Barat (low-low). Variabel TPT, IPM, dan GINI menunjukkan pola cold spot di wilayah selatan yang menandakan pengangguran, pembangunan manusia, dan ketimpangan yang relatif rendah secara berkelompok. Sementara itu, PDRB tidak menunjukkan pola spasial yang signifikan, menandakan distribusinya relatif acak di seluruh wilayah Jawa Barat.
| Statistik_Uji | Value | p | Ket |
|---|---|---|---|
| LM Error (RSerr) | 3.4944 | 0.0616 | not sig. |
| LM Lag (RSlag) | 8.8489 | 0.0029 | sig. |
| Robust LM Error (AdjRSerr) | 1.0849 | 0.2976 | not sig. |
| Robust LM Lag (AdjRSlag) | 6.4394 | 0.0112 | sig. |
| LM SARMA (Gabungan) | 9.9338 | 0.0070 | sig. |
Berdasarkan hasil uji Lagrange Multiplier (LM), diketahui bahwa nilai LM Lag (p = 0.0029) dan Adjusted LM Lag (p = 0.0112) signifikan pada α = 0.05, sedangkan LM Error dan Adjusted LM Error tidak signifikan. Hal ini menunjukkan adanya pengaruh spasial pada variabel dependen (lag spasial), bukan pada error-nya. Dengan demikian, model spasial yang paling tepat digunakan adalah model (SAR). Hasil ini juga diperkuat oleh nilai LM SARMA (p = 0.007) yang signifikan, menegaskan adanya dependensi spasial secara keseluruhan dalam model.
| Model | LogLik | AIC | Ket |
|---|---|---|---|
| SAR (Spatial Autoregressive) | -43.976 | 101.953 | Memasukkan lag pada variabel dependen; AIC terendah. Menunjukkan peningkatan kecocokan yang signifikan. |
| SDM (Spatial Durbin Model) | -40.163 | 102.327 | Memasukkan lag pada dependen dan independen; AIC rendah dan residual tidak berautokorelasi. |
| GNS (General Nesting Spatial) | -39.951 | 103.903 | Model paling kompleks; meski log-likelihood tertinggi, AIC lebih besar karena banyak parameter. |
| SAC/SARAR | -43.449 | 102.898 | Menggabungkan lag dan error spasial; AIC sedikit lebih tinggi dari SDM. |
Mempertimbangkan hasil uji LM, nilai Log-Likelihood, AIC, dan dependensi spasial pada setiap variabel, akan dibandingkan model Spatial Durbin dan model Spatial Autoregressive (SAR).
Berdasarkan hasil pengujian autokorelasi spasial, diketahui bahwa terdapat dependensi spasial, baik pada variabel X maupun variabel Y, maka model SDM cocok digunakan karena dapat mengakomodasi hal tersebut. Dengan estimasi parameter model SDM menggunakan MLE, kemiskinan di Jawa Barat dapat dimodelkan sebagai:
\[ \text{Kemiskinan}_i = 0.55 \sum_{j} w_{ij} y_j + 39.14^{***} + 0.26(\text{TPT})_i - 0.0033(\text{PDRB})_i - 0.42(\text{IPM})_i^{***} + 18.98(\text{GINI})_i^{***} \\ \quad + 0.46 \sum_{j} w_{ij} (\text{TPT})_j + 0.01 \sum_{j} w_{ij} (\text{PDRB})_j - 0.06 \sum_{j} w_{ij} (\text{IPM})_j - 13.86 \sum_{j} w_{ij} (\text{GINI})_j \]
| Statistik_Uji | rho | LR | p_value | Ket |
|---|---|---|---|---|
| Likelihood Ratio | 0.555 | 8.029 | 0.0046 | sig. |
Signifikansi nilai menunjukkan bahwa kemiskinan di suatu wilayah dipengaruhi oleh kemiskinan di wilayah sekitarnya. Jika kemiskinan di suatu kabupaten meningkat, maka kemiskinan di kabupaten tetangga cenderung ikut meningkat. Sama halnya dengan nilai variabel lain (TPT, PDRB, IPM, dan Gini Ratio).
| Variabel | Jenis_Impact | Z | P_value | Ket |
|---|---|---|---|---|
| IPM | Direct | -4.626 | 0.0000 | sig |
| Gini Ratio | Direct | 1.819 | 0.0689 | sig (=0.01) |
IPM memiliki dampak langsung negatif dan signifikan terhadap kemiskinan, yang berarti peningkatan pembangunan manusia berperan penting dalam menekan kemiskinan secara lokal, namun tidak menimbulkan efek spillover ke daerah sekitar. Sedangkan Gini ratio signifikan (dengan α = 0.01) mempengaruhi Kemiskinan secara langsung.
Berdasarkan uji asumsi, diketahui bahwa model SDM memenuhi semua uji asumsi. Hasil uji dapat dilihat pada tabel berikut:
| Uji | Statistik | P_value | Ket |
|---|---|---|---|
| Residual Autokorelasi | 0.5686 | 0.2848 | tidak terdapat autokorelasi spasial |
| Normalitas | 0.9845 | 0.9466 | berdistribusi normal |
| Homoskedastisitas | 9.3304 | 0.3152 | tidak terdapat heteroskedastisitas |
Berdasarkan hasil perbandingan model, model Spatial Autoregressive (SAR) dipilih menjadi model terbaik yang dapat menjelaskan adanya spatial dependence antar kabupaten/kota dan model ini juga mampu menjelaskan faktor-faktor yang mempengaruhi persentase kemiskinan di Jawa Barat. Dengan estimasi model SAR menggunakan MLE, kemiskinan di Jawa Barat dapat dimodelkan sebagai:
\[ y_i = \sum_{j=1}^{n} w_{ij} y_j + 28.449^{***} + 0.1132(\text{TPT})_i - 0.0087(\text{PDRB})_i - 0.4132(\text{IPM})_i^{***} + 12.705(\text{GINI})_i^{*} \]
| Statistik_Uji | rho | LR | p_value | Ket |
|---|---|---|---|---|
| Likelihood Ratio | 0.6527 | 12.428 | 4e-04 | sig. |
Signifikansi nilai menunjukkan bahwa kemiskinan di suatu wilayah dipengaruhi oleh kemiskinan di wilayah sekitarnya. Jika kemiskinan di suatu kabupaten meningkat, maka kemiskinan di kabupaten tetangga cenderung ikut meningkat.
| Variabel | Jenis_Impact | Koefisien | P_value | Ket |
|---|---|---|---|---|
| IPM | Direct | -0.4816 | 0.000 | sig |
| Indirect | -0.7083 | 0.504 | not.sig | |
| Total | -1.1899 | 0.339 | not.sig |
Keterangan:
Direct effect = pengaruh langsung variabel terhadap kemiskinan di wilayahnya sendiri.
Indirect effect = pengaruh tidak langsung (spillover) terhadap wilayah tetangga.
Total effect = gabungan dari efek langsung dan tidak langsung.
IPM memiliki dampak langsung negatif dan signifikan terhadap kemiskinan, yang berarti peningkatan pembangunan manusia berperan penting dalam menekan kemiskinan secara lokal, namun tidak menimbulkan efek ke daerah sekitar.
| Uji | Statistik | P_value | Ket |
|---|---|---|---|
| Residual Autokorelasi | -0.1110 | 0.7077 | not sig. |
| Normalitas | 0.9552 | 0.2865 | sig. |
| Homoskedastisitas | 3.0169 | 0.5550 | not sig. |
Asumsi linearitas pada model SAR dilakukan secara visual melalui pola residual. Berdasarkan plot residual terhadap nilai prediksi yang acak di sekitar nol, sehingga hubungan antara variabel dalam model SAR dapat dikatakan linier.
| Bobot | rho | AIC | LogLik |
|---|---|---|---|
| Queen | 0.6527 | 101.9525 | -43.9762 |
| Rook | 0.6527 | 101.9525 | -43.9762 |
| KNN-4 | 0.4871 | 105.5565 | -45.7782 |
Uji sensivitas bobot spasial dilakukan untuk melihat stabilitas dari model SAR sebelumnya. Berdasarkan tabel bobot di atas, diketahui bahwa Queen dan Rook memberikan nilai , AIC, dan hasil log-likelihood yang sama, meskipun terjadi perbedaan pada bobot KNN-4. Hal ini menunjukkan bahwa spatial dependence di Jawa Barat lebih dipengaruhi oleh kedekatan geografis administratif dan bukan jarak nyata.
Berdasarkan peta prediksi kemiskinan (SDM dan SAR), terlihat bahwa kedua model sama-sama menunjukkan konsentrasi kemiskinan yang relatif tinggi di wilayah Bogor, Sukabumi, dan Cianjur bagian utara, serta Subang dan Indramayu. Sementara itu, wilayah dengan tingkat kemiskinan yang lebih rendah tampak di Bandung Raya (Kota Bandung, Kota Cimahi, Kabupaten Bandung, dan Kabupaten Bandung Barat) serta wilayah timur seperti Sumedang, Majalengka, dan Kuningan. Jika dibandingkan, model SAR (Spatial Autoregressive) memberikan hasil prediksi yang lebih halus dan konsisten di seluruh kabupaten/kota, sedangkan model SDM (Spatial Durbin Model) masih menunjukkan variasi ekstrem antarwilayah, misalnya nilai prediksi yang sangat tinggi di sebagian kecil Kabupaten Bogor dan terlalu rendah di wilayah selatan. Hal ini menunjukkan bahwa model SAR lebih mampu menangkap keterkaitan spasial antarwilayah secara proporsional tanpa menghasilkan prediksi yang berlebihan. | Hasil ini semakin diperkuat oleh peta residual standar. Pada model SDM, masih terlihat adanya pola spasial pada residual, terutama di wilayah Bekasi dan Bogor bagian utara yang cenderung underfit (berwarna merah), serta Tasikmalaya dan Ciamis yang menunjukkan overfit (berwarna biru). Ini menandakan bahwa model SDM belum sepenuhnya mengakomodasi pengaruh spasial antarwilayah tersebut. Sebaliknya, pada model SAR, distribusi residual tampak lebih acak dan intensitas warna lebih lembut di hampir seluruh kabupaten/kota Jawa Barat, termasuk di Cirebon, Garut, dan Sukabumi. Kondisi ini menandakan bahwa model SAR lebih baik dalam menjelaskan variasi spasial kemiskinan dan menghasilkan prediksi yang lebih stabil dan akurat. Dengan demikian, berdasarkan hasil visualisasi residual dan peta prediksi, model SAR dapat dinyatakan sebagai model terbaik untuk menggambarkan pola kemiskinan di Provinsi Jawa Barat.
Berdasarkan hasil perbandingan model, model Spatial Autoregressive (SAR) terpilih sebagai model terbaik dengan nilai AIC terendah (101.95) dan hasil prediksi yang baik. Model SAR untuk kemiskinan secara matematis dapat dituliskan sebagai:
\[ y_i = \sum_{j=1}^{n} w_{ij} y_j + 28.449^{***} + 0.1132(\text{TPT})_i - 0.0087(\text{PDRB})_i - 0.4132(\text{IPM})_i^{***} + 12.705(\text{GINI})_i^{*} \]
Model ini paling sesuai untuk menganalisis faktor ekonomi dan sosial terhadap kemiskinan di Jawa Barat tahun 2024. Hasil menunjukkan bahwa IPM berpengaruh negatif dan signifikan terhadap kemiskinan, Gini Ratio signifikan pada taraf signifikansi 0.01, sedangkan TPT, PDRB tidak signifikan. Pola spasial juga terlihat jelas, di mana wilayah utara dan barat laut memiliki tingkat kemiskinan lebih tinggi dibanding wilayah tengah dan selatan.
Berdasarkan hasil analisis yang sudah dilakukan, dapat disimpulkan bahwa peningkatan IPM perlu menjadi fokus utama kebijakan pengentasan kemiskinan, dimana IPM ini mencakup tiga dimensi utama yaitu Pendidikan, Kesehatan, dan Standar Hidup yang Layak. Selain itu, fokus berdasarkan variabel Gini, pemerintah diharapkan juga bisa mengentaskan ketimpangan ekonomi (sehingga jarak antara yang kaya dan miskin tidak terlalu jauh).
Untuk penelitian berikutnya, disarankan untuk menambahkan variabel lain pada penelitian selanjutnya agar hasil analisis lebih komprehensif, dalam hal ini misalnya variabel akses terhadap air bersih, akses listrik, perumahan, dan lainnya.
PSKK UGM. (2018, 8 Juni). Upaya penanggulangan kemiskinan dari masa ke masa. Diakses darihttps://cpps.ugm.ac.id/upaya-penanggulangan-kemiskinan-dari-masa-ke-masa/
Corral. P. et al.. 2020. Fragility and Conflict: On the Front Lines of the Fight against Poverty. Washington DC: World Bank Publications
United Nations Development Programme. 2022. Sustainable Development Goals. [Online] Available at: https://www.undp.org/sustain able-development-goals [Accessed 16 OKT 2024].
World Population Review. 2022. Poorest Countries in the World 2022. [Online] Available at: https:// worldpopulationreview.com/country-rankings /poorest-countries-in-the-world [Accessed 2 November 2022].
Pohan, H. L. M., & Vitale, J. D. (2016). Overcoming the poverty trap through education: An intergenerational study on Indonesia. Journal of Indonesian Applied Economics, 6(1), 1–21.
Suryaningrat, S. H. (2021). Aplikasi Akaike Information Criterion (AIC) pada Perhitungan Efisiensi Teknis Perikanan Pukat Cincin di Indonesia. Jurnal Penyuluhan Perikanan dan Kelautan, 15(2). Diakses dari: https://doi.org/10.29244/jmf.v11i2.38550.
Prasetya, I. P. G. I. B., Baharuddin, B., & Wibawa, G. N. A. (2024). Pemodelan Regresi Spasial untuk Menentukan Faktor-Faktor yang Berpengaruh terhadap Tingkat Kriminalitas di Provinsi Bali dan Jawa Timur. Jurnal Syntax Admiration, 5(6), 2033-2046.
Astutik, D. (2020). Analisis Faktor yang Mempengaruhi Kemiskinan di Jawa Timur (Pendekatan Spasial). Jurnal Ilmiah Mahasiswa FEB, 9(1).
Putri, A. A., & Sanusi, W. (2018). Model Regresi Spasial dan Aplikasinya pada Kasus Tingkat Kemiskinan Kabupaten Soppeng. Indonesian Journal of Fundamental Sciences Vol, 4(2).
library(sf)
## Warning: package 'sf' was built under R version 4.4.3
## Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(stringr)
## Warning: package 'stringr' was built under R version 4.4.3
library(spdep)
## Warning: package 'spdep' was built under R version 4.4.3
## Loading required package: spData
## Warning: package 'spData' was built under R version 4.4.3
## To access larger datasets in this package, install the spDataLarge
## package with: `install.packages('spDataLarge',
## repos='https://nowosad.github.io/drat/', type='source')`
library(spatialreg)
## Warning: package 'spatialreg' was built under R version 4.4.3
## Loading required package: Matrix
##
## Attaching package: 'spatialreg'
## The following objects are masked from 'package:spdep':
##
## get.ClusterOption, get.coresOption, get.mcOption,
## get.VerboseOption, get.ZeroPolicyOption, set.ClusterOption,
## set.coresOption, set.mcOption, set.VerboseOption,
## set.ZeroPolicyOption
library(tmap)
## Warning: package 'tmap' was built under R version 4.4.3
library(broom)
## Warning: package 'broom' was built under R version 4.4.3
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(psych)
## Warning: package 'psych' was built under R version 4.4.3
##
## Attaching package: 'psych'
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
library(readxl)
## Warning: package 'readxl' was built under R version 4.4.3
library(viridis)
## Warning: package 'viridis' was built under R version 4.4.3
## Loading required package: viridisLite
## Warning: package 'viridisLite' was built under R version 4.4.3
library(scales)
## Warning: package 'scales' was built under R version 4.4.3
##
## Attaching package: 'scales'
## The following object is masked from 'package:viridis':
##
## viridis_pal
## The following objects are masked from 'package:psych':
##
## alpha, rescale
library(tibble)
library(purrr)
## Warning: package 'purrr' was built under R version 4.4.3
##
## Attaching package: 'purrr'
## The following object is masked from 'package:scales':
##
## discard
library(forcats)
## Warning: package 'forcats' was built under R version 4.4.3
library(htmltools)
## Warning: package 'htmltools' was built under R version 4.4.3
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.4.3
# Import shapefile
setwd("C:/Users/Owner/Downloads/geoBoundaries-IDN-ADM2-all")
indo_adm2 <- st_read("geoBoundaries-IDN-ADM2.shp")
## Reading layer `geoBoundaries-IDN-ADM2' from data source
## `C:\Users\Owner\Downloads\geoBoundaries-IDN-ADM2-all\geoBoundaries-IDN-ADM2.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 519 features and 5 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 95.01079 ymin: -11.00762 xmax: 141.0194 ymax: 6.07693
## Geodetic CRS: WGS 84
kab_jabar <- c("Bandung","Bandung Barat","Bekasi","Bogor","Ciamis","Cianjur","Cirebon",
"Garut","Indramayu","Karawang","Kuningan","Majalengka","Pangandaran",
"Purwakarta","Subang","Sukabumi","Sumedang","Tasikmalaya",
"Kota Bandung","Kota Bekasi","Kota Bogor","Kota Cimahi",
"Kota Cirebon","Kota Depok","Kota Sukabumi","Kota Tasikmalaya",
"Kota Banjar")
kab_jabar
## [1] "Bandung" "Bandung Barat" "Bekasi" "Bogor"
## [5] "Ciamis" "Cianjur" "Cirebon" "Garut"
## [9] "Indramayu" "Karawang" "Kuningan" "Majalengka"
## [13] "Pangandaran" "Purwakarta" "Subang" "Sukabumi"
## [17] "Sumedang" "Tasikmalaya" "Kota Bandung" "Kota Bekasi"
## [21] "Kota Bogor" "Kota Cimahi" "Kota Cirebon" "Kota Depok"
## [25] "Kota Sukabumi" "Kota Tasikmalaya" "Kota Banjar"
# normalisasi kolom shapeName
indo_adm2 <- indo_adm2 %>% mutate(shapeName_clean = str_to_lower(str_squish(shapeName)))
# normalisasi daftar kabupaten agar sama format
kab_jabar_clean <- str_to_lower(kab_jabar)
# subset Jawa Barat
jabar <- indo_adm2 %>% filter(shapeName_clean %in% kab_jabar_clean)
# jika masih kosong, coba pendekatan fuzzy match (string distance)
if(nrow(jabar) == 0){
message("Tidak ada match exact; mencoba fuzzy join...")
# minta user menyesuaikan nama; contoh pendekatan:
# tampilkan beberapa nama dari shapefile untuk manual mapping
print(unique(indo_adm2$shapeName)[1:80])
stop("Periksa & adaptasi nama kab/kota lalu jalankan ulang.")
}
# Import atribut
attr <- read_xlsx("C:/Users/Owner/Downloads/DATA SPASIAL.xlsx")
# nama kolom kab/kota di CSV (sesuaikan jika berbeda)
# misal kolom bernama "KAB.KOTA" atau "KAB/KOTA" atau "KAB_KOTA"
names(attr)
## [1] "KAB/KOTA" "KEMISKINAN" "IPM" "GINI" "RLS"
## [6] "TPT" "PDRB" "PPP" "AHH"
# contoh: ubah nama menjadi 'kabupaten' dan normalisasi
attr <- attr %>%
rename(kabupaten = starts_with("KAB")) %>% # adapt jika perlu
mutate(kab_clean = str_to_lower(str_squish(kabupaten)))
# cek beberapa baris
head(attr)
## # A tibble: 6 × 10
## kabupaten KEMISKINAN IPM GINI RLS TPT PDRB PPP AHH kab_clean
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Bogor 7.05 73.6 0.398 8.39 7.34 54.9 11.6 72.2 bogor
## 2 Sukabumi 6.87 70.2 0.342 7.34 7.11 31.2 9.82 72.1 sukabumi
## 3 Cianjur 10.1 68.9 0.338 7.33 5.99 24.9 9.03 71.0 cianjur
## 4 Bandung 6.19 74.6 0.364 9.15 6.36 44.1 11.4 74.6 bandung
## 5 Garut 9.68 69.9 0.324 7.85 6.96 29.0 9.17 72.3 garut
## 6 Tasikmalaya 10.2 70.0 0.363 7.97 3.74 25.9 8.96 70.4 tasikmalaya
# Join atribut ke shapefile
# join berdasarkan nama kabupaten (clean)
jabar <- jabar %>% left_join(attr, by = c("shapeName_clean" = "kab_clean"))
jabar
## Simple feature collection with 27 features and 15 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 106.3703 ymin: -7.820979 xmax: 108.8469 ymax: -5.918148
## Geodetic CRS: WGS 84
## First 10 features:
## shapeName shapeISO shapeID shapeGroup shapeType
## 1 Bandung <NA> 22746128B73297609500416 IDN ADM2
## 2 Bandung Barat <NA> 22746128B79756617117888 IDN ADM2
## 3 Bekasi <NA> 22746128B74302729610221 IDN ADM2
## 4 Bogor <NA> 22746128B99423643145371 IDN ADM2
## 5 Ciamis <NA> 22746128B17121530580660 IDN ADM2
## 6 Cianjur <NA> 22746128B34542084533901 IDN ADM2
## 7 Cirebon <NA> 22746128B77544549346240 IDN ADM2
## 8 Garut <NA> 22746128B66421464971893 IDN ADM2
## 9 Indramayu <NA> 22746128B59462811669242 IDN ADM2
## 10 Karawang <NA> 22746128B53840275251202 IDN ADM2
## shapeName_clean kabupaten KEMISKINAN IPM GINI RLS TPT PDRB
## 1 bandung Bandung 6.19 74.59 0.364 9.15 6.36 44.12583
## 2 bandung barat Bandung Barat 10.49 70.77 0.400 8.24 6.70 32.50007
## 3 bekasi Bekasi 4.80 76.80 0.367 9.76 8.82 128.69290
## 4 bogor Bogor 7.05 73.63 0.398 8.39 7.34 54.85684
## 5 ciamis Ciamis 7.39 73.64 0.326 8.10 3.37 34.33605
## 6 cianjur Cianjur 10.14 68.89 0.338 7.33 5.99 24.91437
## 7 cirebon Cirebon 11.00 72.30 0.374 7.65 6.74 28.13950
## 8 garut Garut 9.68 69.91 0.324 7.85 6.96 29.01236
## 9 indramayu Indramayu 11.93 70.72 0.306 6.95 6.25 55.16555
## 10 karawang Karawang 7.86 73.82 0.376 8.05 8.04 121.29850
## PPP AHH geometry
## 1 11.392 74.55279 MULTIPOLYGON (((107.75 -6.8...
## 2 9.583 73.35373 MULTIPOLYGON (((107.525 -6....
## 3 12.500 74.62647 MULTIPOLYGON (((107.0982 -5...
## 4 11.563 72.15454 MULTIPOLYGON (((106.994 -6....
## 5 10.085 72.92110 MULTIPOLYGON (((108.3857 -7...
## 6 9.026 70.95969 MULTIPOLYGON (((107.3118 -7...
## 7 11.529 73.06450 MULTIPOLYGON (((108.685 -6....
## 8 9.168 72.28017 MULTIPOLYGON (((107.7202 -7...
## 9 11.010 72.80831 MULTIPOLYGON (((108.539 -6....
## 10 12.942 73.17286 MULTIPOLYGON (((107.1717 -6...
# STATISTIKA DESKRIPTIF
data_spasial <- jabar %>%
sf::st_drop_geometry() %>%
dplyr::select(KEMISKINAN, TPT, PDRB, IPM, GINI)
# Histogram Setiap Variabel ----
# Histogram KEMISKINAN
ggplot(data_spasial, aes(x = KEMISKINAN)) +
geom_histogram(
binwidth = 1, # atur lebar tiap batang agar batas jelas
fill = "skyblue",
color = "black",
boundary = 0, # memastikan bar mulai dari angka bulat
closed = "left" # agar sisi kiri dan kanan bar tertutup rapat
) +
scale_x_continuous(
name = "Kemiskinan (%)",
breaks = seq(floor(min(data_spasial$KEMISKINAN)), ceiling(max(data_spasial$KEMISKINAN)), by = 1)
) +
scale_y_continuous(name = "Frekuensi") +
labs(title = "Distribusi Tingkat Kemiskinan") +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(hjust = 0.5, face = "bold"),
panel.grid.minor = element_blank()
)
# Histogram TPT
ggplot(data_spasial, aes(x = TPT)) +
geom_histogram(bins = 10, fill = "lightgreen", color = "black") +
labs(title = "Distribusi Tingkat Pengangguran Terbuka", x = "TPT (%)", y = "Frekuensi")
# Histogram PDRB
ggplot(data_spasial, aes(x = PDRB)) +
geom_histogram(bins = 10, fill = "lightcoral", color = "black") +
labs(title = "Distribusi PDRB per Kapita", x = "PDRB (juta rupiah)", y = "Frekuensi")
# Histogram IPM
ggplot(data_spasial, aes(x = IPM)) +
geom_histogram(bins = 10, fill = "gold", color = "black") +
labs(title = "Distribusi Indeks Pembangunan Manusia", x = "IPM", y = "Frekuensi")
# Histogram GINI
ggplot(data_spasial, aes(x = GINI)) +
geom_histogram(bins = 10, fill = "plum", color = "black") +
labs(title = "Distribusi Rasio Gini", x = "GINI", y = "Frekuensi")
# Boxplot Setiap Variabel ----
# Boxplot KEMISKINAN
ggplot(data_spasial, aes(y = KEMISKINAN)) +
geom_boxplot(fill = "skyblue", color = "black") +
labs(title = "Boxplot Tingkat Kemiskinan", y = "Kemiskinan (%)", x = "") +
theme_minimal()
# Boxplot TPT
ggplot(data_spasial, aes(y = TPT)) +
geom_boxplot(fill = "lightgreen", color = "black") +
labs(title = "Boxplot Tingkat Pengangguran Terbuka", y = "TPT (%)", x = "") +
theme_minimal()
# Boxplot PDRB
ggplot(data_spasial, aes(y = PDRB)) +
geom_boxplot(fill = "lightcoral", color = "black") +
labs(title = "Boxplot PDRB per Kapita", y = "PDRB (juta rupiah)", x = "") +
theme_minimal()
# Boxplot IPM
ggplot(data_spasial, aes(y = IPM)) +
geom_boxplot(fill = "gold", color = "black") +
labs(title = "Boxplot Indeks Pembangunan Manusia", y = "IPM", x = "") +
theme_minimal()
# Boxplot GINI
ggplot(data_spasial, aes(y = GINI)) +
geom_boxplot(fill = "plum", color = "black") +
labs(title = "Boxplot Rasio Gini", y = "GINI", x = "") +
theme_minimal()
# Plot Antar variabel ----
# Scatter Plot KEMISKINAN vs TPT
ggplot(data_spasial, aes(x = TPT, y = KEMISKINAN)) +
geom_point(color = "steelblue", size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "darkred", linetype = "dashed") +
labs(title = "Hubungan antara Kemiskinan dan TPT",
x = "Tingkat Pengangguran Terbuka (%)",
y = "Kemiskinan (%)") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Scatter Plot KEMISKINAN vs PDRB
ggplot(data_spasial, aes(x = PDRB, y = KEMISKINAN)) +
geom_point(color = "seagreen", size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "darkred", linetype = "dashed") +
labs(title = "Hubungan antara Kemiskinan dan PDRB per Kapita",
x = "PDRB per Kapita (juta rupiah)",
y = "Kemiskinan (%)") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Scatter Plot KEMISKINAN vs IPM
ggplot(data_spasial, aes(x = IPM, y = KEMISKINAN)) +
geom_point(color = "goldenrod", size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "darkred", linetype = "dashed") +
labs(title = "Hubungan antara Kemiskinan dan IPM",
x = "Indeks Pembangunan Manusia",
y = "Kemiskinan (%)") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Scatter Plot KEMISKINAN vs GINI
ggplot(data_spasial, aes(x = GINI, y = KEMISKINAN)) +
geom_point(color = "purple", size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "darkred", linetype = "dashed") +
labs(title = "Hubungan antara Kemiskinan dan Rasio Gini",
x = "Rasio Gini",
y = "Kemiskinan (%)") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
# Choropleth ----
# Tema peta yang konsisten
theme_map <- function() {
theme_minimal(base_size = 11) +
theme(
axis.title = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank(),
legend.position = "right",
plot.title = element_text(face = "bold")
)
}
# 1) Kemiskinan
p_kemiskinan <- ggplot(jabar) +
geom_sf(aes(fill = KEMISKINAN), color = "white", size = 0.2) +
scale_fill_viridis_c(name = "Kemiskinan (%)", option = "C", direction = -1) +
labs(title = "Penyebaran Kemiskinan (%) – Jawa Barat") +
coord_sf() + theme_map()
# 2) TPT
p_tpt <- ggplot(jabar) +
geom_sf(aes(fill = TPT), color = "white", size = 0.2) +
scale_fill_viridis_c(name = "TPT (%)", option = "C", direction = -1) +
labs(title = "Penyebaran TPT (%) – Jawa Barat") +
coord_sf() + theme_map()
# 3) PDRB (biasanya miring kanan → gunakan skala log agar kontrasnya lebih informatif)
p_pdrb <- ggplot(jabar) +
geom_sf(aes(fill = PDRB), color = "white", size = 0.2) +
scale_fill_viridis_c(
name = "PDRB per Kapita\n(juta rupiah, log10)",
option = "C", direction = -1,
trans = "log10",
labels = label_number(accuracy = 0.1)
) +
labs(title = "Penyebaran PDRB per Kapita – Jawa Barat") +
coord_sf() + theme_map()
# 4) IPM
p_ipm <- ggplot(jabar) +
geom_sf(aes(fill = IPM), color = "white", size = 0.2) +
scale_fill_viridis_c(name = "IPM", option = "C", direction = -1) +
labs(title = "Penyebaran IPM – Jawa Barat") +
coord_sf() + theme_map()
# 5) GINI
p_gini <- ggplot(jabar) +
geom_sf(aes(fill = GINI), color = "white", size = 0.2) +
scale_fill_viridis_c(name = "Rasio Gini", option = "C", direction = -1) +
labs(title = "Penyebaran Rasio Gini – Jawa Barat") +
coord_sf() + theme_map()
# Tampilkan satu per satu (setiap baris akan memunculkan satu plot)
p_kemiskinan
p_tpt
p_pdrb
p_ipm
p_gini
# Autokorelasi Spatial
# Moran’s I ----
# 1) Weights Queen
nb_queen <- poly2nb(jabar, queen = TRUE)
lw_queen <- nb2listw(nb_queen, style = "W", zero.policy = TRUE)
# 2) Variabel yang diuji
vars <- c("KEMISKINAN", "TPT", "PDRB", "IPM", "GINI")
# 3) Helper: Moran's I (Asimtotik + Permutasi) aman dari NA
safe_moran_row_both <- function(y, varname, nb_full, nsim = 999, seed = 77) {
# Tangani NA: subset data & struktur tetangga
ok <- is.finite(y)
y_use <- y[ok]
nb_sub <- if (all(ok)) nb_full else spdep::subset.nb(nb_full, ok)
lw_sub <- nb2listw(nb_sub, style = "W", zero.policy = TRUE)
## --- Asimtotik ---
mt <- moran.test(y_use, lw_sub, zero.policy = TRUE)
est <- mt$estimate
I_asym <- suppressWarnings(as.numeric(est[["Moran I statistic"]]))
EI <- suppressWarnings(as.numeric(est[["Expectation"]]))
VarI <- est[["Variance"]]
if (is.null(VarI)) VarI <- est[["variance of Moran's I"]]
VarI <- suppressWarnings(as.numeric(VarI))
Z_asym <- suppressWarnings(as.numeric(mt$statistic))
SD_asym <- if (!is.null(VarI) && is.finite(VarI)) sqrt(VarI) else NA_real_
p_asym <- mt$p.value
## --- Permutasi (Monte Carlo) ---
set.seed(seed)
mmc <- moran.mc(y_use, lw_sub, nsim = nsim, zero.policy = TRUE, alternative = "two.sided")
I_perm <- suppressWarnings(as.numeric(mmc$statistic))
p_perm <- mmc$p.value
tibble(
Variabel = varname,
Moran_I = round(I_asym, 6),
Expected_I = round(EI, 6),
SD = round(SD_asym, 6),
Z_value = round(Z_asym, 6),
P_asym = signif(p_asym, 6),
I_perm = round(I_perm, 6),
P_perm = signif(p_perm, 6),
nsim = nsim
)
}
# 4) Jalankan untuk semua variabel dan gabungkan ke satu tabel
hasil_moran_both <- map_dfr(vars, ~ safe_moran_row_both(jabar[[.x]], .x, nb_queen))
# 5) Lihat tabel hasil
hasil_moran_both
## # A tibble: 5 × 9
## Variabel Moran_I Expected_I SD Z_value P_asym I_perm P_perm nsim
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 KEMISKINAN 0.478 -0.0385 0.141 3.65 0.000129 0.478 0 999
## 2 TPT 0.511 -0.0385 0.135 4.07 0.0000240 0.511 0 999
## 3 PDRB 0.211 -0.0385 0.134 1.86 0.0314 0.211 0.102 999
## 4 IPM 0.275 -0.0385 0.140 2.24 0.0127 0.275 0.032 999
## 5 GINI 0.299 -0.0385 0.140 2.40 0.00811 0.299 0.036 999
# Geary C ----
safe_geary_row <- function(y, varname, nb_full) {
# Tangani NA: subset data & struktur tetangga
ok <- is.finite(y)
if (!all(ok)) {
# subset nb (fungsi subset.nb ada di spdep)
nb_sub <- spdep::subset.nb(nb_full, ok)
} else {
nb_sub <- nb_full
}
lw_sub <- nb2listw(nb_sub, style = "W", zero.policy = TRUE)
# Asimtotik
gt <- geary.test(y[ok], lw_sub, randomisation = TRUE, zero.policy = TRUE)
est <- gt$estimate
# Ambil nilai C & ekspektasi dengan fallback nama
C_asym <- suppressWarnings(
as.numeric(est[["Geary C statistic"]])
)
if (is.na(C_asym)) {
C_asym <- suppressWarnings(as.numeric(est[["Geary's C"]]))
}
E_C <- suppressWarnings(as.numeric(est[["Expectation"]]))
if (is.na(E_C)) E_C <- 1 # default teoritis Geary's C
Z_asym <- suppressWarnings(as.numeric(gt$statistic))
p_asym <- gt$p.value
# Permutasi (Monte Carlo)
set.seed(77)
gmc <- geary.mc(y[ok], lw_sub, nsim = 999, zero.policy = TRUE)
C_perm <- suppressWarnings(as.numeric(gmc$statistic))
p_perm <- gmc$p.value
tibble(
Variabel = varname,
Geary_C = round(C_asym, 6),
Expected_C = round(E_C, 6),
Z_value = round(Z_asym, 6),
P_asym = signif(p_asym, 6),
C_perm = round(C_perm, 6),
P_perm = signif(p_perm, 6)
)
}
# 3) Hitung untuk semua variabel dan gabungkan ke tabel
hasil_geary <- map_dfr(vars, ~ safe_geary_row(jabar[[.x]], .x, nb_queen))
# 4) Lihat tabel hasil
hasil_geary
## # A tibble: 5 × 7
## Variabel Geary_C Expected_C Z_value P_asym C_perm P_perm
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 KEMISKINAN 0.410 1 3.76 0.0000865 0.410 0.001
## 2 TPT 0.465 1 2.92 0.00175 0.465 0.001
## 3 PDRB 0.660 1 1.82 0.0344 0.660 0.031
## 4 IPM 0.607 1 2.42 0.00787 0.607 0.005
## 5 GINI 0.504 1 3.07 0.00105 0.504 0.004
###Interpetasi
# Geary’s C < 1 → kecenderungan clustering (mirip Moran’s I positif).
# Geary’s C ≈ 1 → acak (tidak ada autokorelasi spasial).
# Geary’s C > 1 → dispersion (tetangga cenderung berbeda/kontras).
# Gunakan P_asym (uji asimtotik) dan P_perm (Monte Carlo) untuk signifikansi. Biasanya saya laporkan keduanya; jika hasilnya konsisten, kesimpulan lebih kuat.
# Local Moran’s I (LISA) -----
# 3️⃣ Fungsi untuk menghitung LISA & klasifikasi kuadran
safe_lisa <- function(y, varname, sf_obj, lw, sig_thr = 0.05) {
ok <- is.finite(y)
z <- as.numeric(scale(y[ok]))
lag_z <- lag.listw(lw, z, zero.policy = TRUE)
lisa_df <- as.data.frame(localmoran(z, lw, zero.policy = TRUE))
# Hitung p-value dua sisi (karena versi spdep bisa beda nama)
if ("Pr(z > 0)" %in% names(lisa_df)) {
p_right <- lisa_df[,"Pr(z > 0)"]
p_left <- 1 - p_right
p_two <- 2*pmin(p_right, p_left)
} else if ("Pr(z <= 0)" %in% names(lisa_df)) {
p_left <- lisa_df[,"Pr(z <= 0)"]
p_right <- 1 - p_left
p_two <- 2*pmin(p_right, p_left)
} else if ("Pr(z != E(Ii))" %in% names(lisa_df)) {
p_two <- lisa_df[,"Pr(z != E(Ii))"]
} else {
zval <- lisa_df[,"Z.Ii"]
p_two <- 2*pnorm(-abs(zval))
}
# Klasifikasi kuadran
quad_raw <- ifelse(z >= 0 & lag_z >= 0, "High-High",
ifelse(z < 0 & lag_z < 0, "Low-Low",
ifelse(z >= 0 & lag_z < 0, "High-Low", "Low-High")))
cluster <- ifelse(p_two <= sig_thr, quad_raw, "Not Significant")
# Gabungkan ke sf
sf_sub <- sf_obj[ok, ] %>%
mutate(
z_score = z,
lag_z = lag_z,
Ii = lisa_df$Ii,
Z_Ii = lisa_df$Z.Ii,
p_lisa = p_two,
LISA_cat = factor(cluster,
levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")),
Variabel = varname
)
# Tabel ringkasan kategori
tab <- sf_sub %>%
st_drop_geometry() %>%
group_by(LISA_cat) %>%
summarise(
Kabupaten = paste(kabupaten, collapse = ", "),
Jumlah = n(),
.groups = "drop"
)
list(sf = sf_sub, tabel = tab)
}
# 4️⃣ Jalankan untuk semua variabel
lisa_results <- map(vars, ~ safe_lisa(jabar[[.x]], .x, jabar, lw_queen))
# 5️⃣ Gabungkan tabel hasil
lisa_tables <- map2_df(lisa_results, vars, ~ mutate(.x$tabel, Variabel = .y))
lisa_tables
## # A tibble: 10 × 4
## LISA_cat Kabupaten Jumlah Variabel
## <fct> <chr> <int> <chr>
## 1 High-High Cirebon, Majalengka 2 KEMISKI…
## 2 Low-Low Bogor, Kota Bekasi 2 KEMISKI…
## 3 Not Significant Bandung, Bandung Barat, Bekasi, Ciamis, Cian… 23 KEMISKI…
## 4 Low-Low Ciamis, Kota Tasikmalaya, Pangandaran, Tasik… 4 TPT
## 5 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Cianj… 23 TPT
## 6 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Ciami… 27 PDRB
## 7 Low-Low Sumedang 1 IPM
## 8 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Ciami… 26 IPM
## 9 Low-Low Sumedang, Tasikmalaya 2 GINI
## 10 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Ciami… 25 GINI
# 6️⃣ Plot peta cluster untuk tiap variabel
plots <- map2(lisa_results, vars, ~ {
ggplot(.x$sf) +
geom_sf(aes(fill = LISA_cat), color = "white", size = 0.2) +
scale_fill_manual(values = c(
"High-High" = "#d7191c",
"Low-Low" = "#2c7bb6",
"High-Low" = "#fdae61",
"Low-High" = "#abd9e9",
"Not Significant" = "grey80"
), drop = FALSE, name = "Cluster") +
labs(title = paste0("Peta Cluster LISA - ", .y),
subtitle = "Metode Local Moran’s I (Queen Contiguity)") +
theme_minimal() +
theme(axis.text = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank())
})
# 7️⃣ Tampilkan tabel & peta contoh
print(lisa_tables)
## # A tibble: 10 × 4
## LISA_cat Kabupaten Jumlah Variabel
## <fct> <chr> <int> <chr>
## 1 High-High Cirebon, Majalengka 2 KEMISKI…
## 2 Low-Low Bogor, Kota Bekasi 2 KEMISKI…
## 3 Not Significant Bandung, Bandung Barat, Bekasi, Ciamis, Cian… 23 KEMISKI…
## 4 Low-Low Ciamis, Kota Tasikmalaya, Pangandaran, Tasik… 4 TPT
## 5 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Cianj… 23 TPT
## 6 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Ciami… 27 PDRB
## 7 Low-Low Sumedang 1 IPM
## 8 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Ciami… 26 IPM
## 9 Low-Low Sumedang, Tasikmalaya 2 GINI
## 10 Not Significant Bandung, Bandung Barat, Bekasi, Bogor, Ciami… 25 GINI
plots[[1]] # tampilkan peta KEMISKINAN
plots[[2]] # tampilkan peta TPT
plots[[3]] # tampilkan peta PDRB
plots[[4]] # tampilkan peta IPM
plots[[5]] # tampilkan peta GINI
# Jika ingin semua peta ditampilkan sekaligus:
# library(patchwork)
# wrap_plots(plots, ncol = 2)
# Getis–Ord 𝐺∗𝑖----
# === Palet kategori (sesuai contohmu) ===
cols_gstar <- c("Hot spot" = "#D7191C", "Cold spot" = "#1B9E77", "Not significant" = "grey99")
# === Helper: hitung Gi* satu variabel, hasilkan sf + tabel ringkasan ===
compute_gistar <- function(sf_obj, varname, lw) {
x_raw <- sf_obj[[varname]]
ok <- is.finite(x_raw)
# Subset bobot & data bila ada NA
nb_sub <- if (all(ok)) lw$neighbours else spdep::subset.nb(lw$neighbours, ok)
lw_sub <- nb2listw(nb_sub, style = "W", zero.policy = TRUE)
# Matriks bobot (untuk G, G*)
Wb <- spdep::listw2mat(lw_sub)
sum_x <- sum(x_raw[ok])
# --- G_i (tanpa i) ---
num_G <- as.numeric(Wb %*% x_raw[ok])
den_G <- (sum_x - x_raw[ok])
G_raw <- num_G / den_G
# --- G_i* (dengan i): set w_ii = 1 ---
Wb_star <- Wb; diag(Wb_star) <- 1
num_Gs <- as.numeric(Wb_star %*% x_raw[ok])
den_Gs <- sum_x
G_star_raw <- num_Gs / den_Gs
# --- Z-score Gi* (uji lokal) ---
Gz <- spdep::localG(x_raw[ok], listw = lw_sub, zero.policy = TRUE)
# Susun vektor full-length (NA di posisi non-ok)
z_Gistar_full <- rep(NA_real_, nrow(sf_obj)); z_Gistar_full[ok] <- as.numeric(Gz)
G_raw_full <- rep(NA_real_, nrow(sf_obj)); G_raw_full[ok] <- G_raw
G_star_raw_full <- rep(NA_real_, nrow(sf_obj)); G_star_raw_full[ok] <- G_star_raw
# Kategori
GSTAR_cat <- case_when(
z_Gistar_full >= 1.96 ~ "Hot spot",
z_Gistar_full <= -1.96 ~ "Cold spot",
TRUE ~ "Not significant"
)
# Gabungkan ke sf
sf_out <- sf_obj |>
mutate(
!!paste0("G_raw_", varname) := G_raw_full,
!!paste0("Gstar_", varname) := G_star_raw_full,
!!paste0("z_Gi_", varname) := z_Gistar_full,
!!paste0("GSTAR_", varname) := factor(GSTAR_cat,
levels = c("Hot spot","Cold spot","Not significant")),
Variabel = varname
)
# Tabel ringkasan hotspot/coldspot
tab <- sf_out |>
st_drop_geometry() |>
transmute(
Variabel = varname,
Kabupaten = kabupaten,
Kategori = .data[[paste0("GSTAR_", varname)]],
Gi_star = round(.data[[paste0("z_Gi_", varname)]], 3)
) |>
filter(Kategori %in% c("Hot spot","Cold spot")) |>
arrange(Kategori, dplyr::desc(if_else(Kategori == "Hot spot", Gi_star, -Gi_star)))
list(sf = sf_out, table = tab)
}
# === Jalankan untuk semua variabel ===
gistar_results <- map(vars, ~ compute_gistar(jabar, .x, lw_queen))
# === Tabel gabungan hotspot/coldspot semua variabel ===
gistar_tables <- map_dfr(gistar_results, "table")
gistar_tables
## Variabel Kabupaten Kategori Gi_star
## 1 KEMISKINAN Cirebon Hot spot 2.489
## 2 KEMISKINAN Majalengka Hot spot 2.485
## 3 KEMISKINAN Kota Bekasi Cold spot -2.459
## 4 KEMISKINAN Bogor Cold spot -2.122
## 5 TPT Pangandaran Cold spot -3.278
## 6 TPT Tasikmalaya Cold spot -3.175
## 7 TPT Ciamis Cold spot -3.119
## 8 TPT Kota Tasikmalaya Cold spot -2.513
## 9 IPM Sumedang Cold spot -2.051
## 10 GINI Tasikmalaya Cold spot -2.414
## 11 GINI Sumedang Cold spot -2.052
# -> berisi kolom: Variabel, Kabupaten, Kategori ("Hot spot"/"Cold spot"), Gi_star (z-score)
# === Plot peta cluster per variabel
# --- palet lebih kontras ---
cols_gstar <- c(
"Hot spot" = "#D7191C",
"Cold spot" = "#1B9E77",
"Not significant" = "#EAEAEA" # bukan putih; abu muda biar batas terlihat
)
# --- buat layer batas (garis) yang tajam ---
sf_plot <- gistar_results[[which(vars == "KEMISKINAN")]]$sf
batas_prov <- sf::st_as_sf(sf::st_cast(sf::st_union(sf_plot), "MULTILINESTRING"))
fill_col <- paste0("GSTAR_", "KEMISKINAN")
sf_plot <- sf_plot |>
mutate(
!!fill_col := as.character(.data[[fill_col]]),
!!fill_col := ifelse(is.na(.data[[fill_col]]), "Not significant", .data[[fill_col]]),
!!fill_col := forcats::fct(.data[[fill_col]],
levels = c("Hot spot","Cold spot","Not significant"))
)
gistar_plots <- purrr::map2(gistar_results, vars, ~{
sf_plot <- .x$sf
fill_col <- paste0("GSTAR_", .y)
batas_prov <- sf::st_as_sf(sf::st_cast(sf::st_union(sf_plot), "MULTILINESTRING"))
sf_plot <- sf_plot |>
mutate(
!!fill_col := as.character(.data[[fill_col]]),
!!fill_col := ifelse(is.na(.data[[fill_col]]), "Not significant", .data[[fill_col]]),
!!fill_col := forcats::fct(.data[[fill_col]],
levels = c("Hot spot","Cold spot","Not significant"))
)
ggplot(sf_plot) +
geom_sf(aes(fill = .data[[fill_col]]), color = "#FFFFFF", size = 0.3) +
geom_sf(data = sf::st_boundary(sf_plot), color = "#6B7280", size = 0.35, fill = NA) +
geom_sf(data = batas_prov, color = "#374151", size = 0.6, fill = NA) +
scale_fill_manual(values = cols_gstar,
limits = c("Hot spot","Cold spot","Not significant"),
drop = FALSE, name = "Kategori") +
labs(title = paste0("Getis–Ord G* – ", .y)) +
coord_sf(expand = FALSE) +
theme_minimal(base_size = 12) +
theme(axis.title = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank())
})
gistar_plots[[1]] # KEMISKINAN
gistar_plots[[2]] # TPT
gistar_plots[[3]] # PDRB
gistar_plots[[4]] # IPM
gistar_plots[[5]] # GINI
# UJI OLS ----
ols_jabar <- lm(KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
summary(ols_jabar)
##
## Call:
## lm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.2564 -0.8408 -0.2461 0.8028 3.9446
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 44.770143 6.655302 6.727 9.23e-07 ***
## TPT -0.087919 0.255841 -0.344 0.734
## PDRB -0.004582 0.012384 -0.370 0.715
## IPM -0.552077 0.114684 -4.814 8.28e-05 ***
## GINI 14.236635 11.360662 1.253 0.223
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.72 on 22 degrees of freedom
## Multiple R-squared: 0.6431, Adjusted R-squared: 0.5782
## F-statistic: 9.912 on 4 and 22 DF, p-value: 9.655e-05
# Uji Moran’s I residual OLS ----
moran.test(residuals(ols_jabar), lw_queen)
##
## Moran I test under randomisation
##
## data: residuals(ols_jabar)
## weights: lw_queen
##
## Moran I statistic standard deviate = 2.3277, p-value = 0.009964
## alternative hypothesis: greater
## sample estimates:
## Moran I statistic Expectation Variance
## 0.28323118 -0.03846154 0.01909999
moran.mc(residuals(ols_jabar), lw_queen, nsim = 999)
##
## Monte-Carlo simulation of Moran I
##
## data: residuals(ols_jabar)
## weights: lw_queen
## number of simulations + 1: 1000
##
## statistic = 0.28323, observed rank = 985, p-value = 0.015
## alternative hypothesis: greater
# Uji Lagrange Multiplier (LM) ----
lm.LMtests(ols_jabar, lw_queen, test = "all")
## Please update scripts to use lm.RStests in place of lm.LMtests
##
## Rao's score (a.k.a Lagrange multiplier) diagnostics for spatial
## dependence
##
## data:
## model: lm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
## test weights: listw
##
## RSerr = 3.4944, df = 1, p-value = 0.06158
##
##
## Rao's score (a.k.a Lagrange multiplier) diagnostics for spatial
## dependence
##
## data:
## model: lm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
## test weights: listw
##
## RSlag = 8.8489, df = 1, p-value = 0.002933
##
##
## Rao's score (a.k.a Lagrange multiplier) diagnostics for spatial
## dependence
##
## data:
## model: lm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
## test weights: listw
##
## adjRSerr = 1.0849, df = 1, p-value = 0.2976
##
##
## Rao's score (a.k.a Lagrange multiplier) diagnostics for spatial
## dependence
##
## data:
## model: lm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
## test weights: listw
##
## adjRSlag = 6.4394, df = 1, p-value = 0.01116
##
##
## Rao's score (a.k.a Lagrange multiplier) diagnostics for spatial
## dependence
##
## data:
## model: lm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar)
## test weights: listw
##
## SARMA = 9.9338, df = 2, p-value = 0.006965
# 1. SDM ----
# Estimasi SDM (Durbin = TRUE mengaktifkan WX)
sdm_jabar <- lagsarlm(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
Durbin = TRUE, # aktifkan Spatial Lag of X
method = "eigen", # metode umum untuk estimasi SDM
zero.policy = TRUE
)
# Tampilkan ringkasan hasil
summary(sdm_jabar)
##
## Call:lagsarlm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar,
## listw = lw_queen, Durbin = TRUE, method = "eigen", zero.policy = TRUE)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.089226 -0.655366 0.098144 0.608557 2.156242
##
## Type: mixed
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 39.1412149 13.4707343 2.9056 0.003665
## TPT 0.2570906 0.1778978 1.4452 0.148413
## PDRB -0.0033225 0.0080008 -0.4153 0.677948
## IPM -0.4249462 0.0895674 -4.7444 2.091e-06
## GINI 18.9755585 7.6787113 2.4712 0.013466
## lag.TPT -0.4591547 0.3122474 -1.4705 0.141431
## lag.PDRB 0.0100997 0.0256549 0.3937 0.693819
## lag.IPM -0.0686563 0.2408683 -0.2850 0.775616
## lag.GINI -13.8560728 19.2998455 -0.7179 0.472796
##
## Rho: 0.55505, LR test value: 8.029, p-value: 0.0046033
## Asymptotic standard error: 0.15968
## z-value: 3.476, p-value: 0.00050893
## Wald statistic: 12.083, p-value: 0.00050893
##
## Log likelihood: -40.16333 for mixed model
## ML residual variance (sigma squared): 1.048, (sigma: 1.0237)
## Number of observations: 27
## Number of parameters estimated: 11
## AIC: 102.33, (AIC for lm: 108.36)
## LM test for residual autocorrelation
## test value: 0.35755, p-value: 0.54987
# Efek langsung, tidak langsung, dan total
impacts_sdm <- impacts(sdm_jabar, listw = lw_queen, R = 999)
summary(impacts_sdm, zstats = TRUE, short = FALSE)
## Impact measures (mixed, exact):
## Direct Indirect Total
## TPT dy/dx 0.197308186 -0.65143378 -0.45412560
## PDRB dy/dx -0.001762873 0.01699438 0.01523151
## IPM dy/dx -0.482473829 -0.62686447 -1.10933830
## GINI dy/dx 18.347667907 -6.84196900 11.50569891
## ========================================================
## Simulation results ( variance matrix):
## Direct:
##
## Iterations = 1:996
## Thinning interval = 1
## Number of chains = 1
## Sample size per chain = 996
##
## 1. Empirical mean and standard deviation for each variable,
## plus standard error of the mean:
##
## Mean SD Naive SE Time-series SE
## TPT dy/dx 0.197685 0.238979 0.0075723 0.0075723
## PDRB dy/dx -0.001126 0.009938 0.0003149 0.0003149
## IPM dy/dx -0.494379 0.099348 0.0031480 0.0031480
## GINI dy/dx 18.715194 11.851586 0.3755319 0.3755319
##
## 2. Quantiles for each variable:
##
## 2.5% 25% 50% 75% 97.5%
## TPT dy/dx -0.24152 0.064503 0.187069 0.333676 0.6056
## PDRB dy/dx -0.02078 -0.007163 -0.001676 0.004569 0.0187
## IPM dy/dx -0.69410 -0.548654 -0.489306 -0.433094 -0.3240
## GINI dy/dx 0.43026 12.454428 18.413817 25.042559 39.3885
##
## ========================================================
## Indirect:
##
## Iterations = 1:996
## Thinning interval = 1
## Number of chains = 1
## Sample size per chain = 996
##
## 1. Empirical mean and standard deviation for each variable,
## plus standard error of the mean:
##
## Mean SD Naive SE Time-series SE
## TPT dy/dx -0.6179 2.34520 0.074310 0.074310
## PDRB dy/dx 0.0249 0.08373 0.002653 0.002774
## IPM dy/dx -0.7752 0.90498 0.028675 0.025409
## GINI dy/dx -8.1287 140.80942 4.461717 4.461717
##
## 2. Quantiles for each variable:
##
## 2.5% 25% 50% 75% 97.5%
## TPT dy/dx -2.6061 -1.1240 -0.62917 -0.21004 0.9927
## PDRB dy/dx -0.1016 -0.0167 0.01897 0.06029 0.1690
## IPM dy/dx -2.5393 -1.0601 -0.63136 -0.31984 0.2710
## GINI dy/dx -110.1849 -35.6953 -6.97074 22.39558 116.7446
##
## ========================================================
## Total:
##
## Iterations = 1:996
## Thinning interval = 1
## Number of chains = 1
## Sample size per chain = 996
##
## 1. Empirical mean and standard deviation for each variable,
## plus standard error of the mean:
##
## Mean SD Naive SE Time-series SE
## TPT dy/dx -0.42019 2.50394 0.079340 0.079340
## PDRB dy/dx 0.02378 0.09007 0.002854 0.002964
## IPM dy/dx -1.26953 0.95517 0.030266 0.027210
## GINI dy/dx 10.58653 149.66139 4.742203 4.742203
##
## 2. Quantiles for each variable:
##
## 2.5% 25% 50% 75% 97.5%
## TPT dy/dx -2.7095 -0.99241 -0.46956 0.07018 1.4540
## PDRB dy/dx -0.1139 -0.02062 0.01918 0.06090 0.1863
## IPM dy/dx -3.0767 -1.56041 -1.10231 -0.79602 -0.1988
## GINI dy/dx -108.2936 -19.85880 11.57316 43.07807 148.5133
##
## ========================================================
## Simulated standard errors
## Direct Indirect Total
## TPT dy/dx 0.238978566 2.34519929 2.50393527
## PDRB dy/dx 0.009938453 0.08372882 0.09007449
## IPM dy/dx 0.099347883 0.90498164 0.95517030
## GINI dy/dx 11.851585543 140.80941724 149.66139389
##
## Simulated z-values:
## Direct Indirect Total
## TPT dy/dx 0.8272080 -0.26346185 -0.16781008
## PDRB dy/dx -0.1132518 0.29741656 0.26396809
## IPM dy/dx -4.9762426 -0.85654032 -1.32911632
## GINI dy/dx 1.5791299 -0.05772811 0.07073656
##
## Simulated p-values:
## Direct Indirect Total
## TPT dy/dx 0.40812 0.79219 0.86673
## PDRB dy/dx 0.90983 0.76615 0.79180
## IPM dy/dx 6.483e-07 0.39170 0.18381
## GINI dy/dx 0.11431 0.95397 0.94361
# 2. GNS -----
# Estimasi model GNS
gns_jabar <- sacsarlm(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
Durbin = TRUE, # aktifkan Spatial Lag of X
method = "eigen", # metode numerik untuk dekomposisi spasial
zero.policy = TRUE
)
# Ringkasan hasil estimasi
summary(gns_jabar)
##
## Call:sacsarlm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar,
## listw = lw_queen, Durbin = TRUE, method = "eigen", zero.policy = TRUE)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.01845 -0.73957 0.16932 0.66633 2.08399
##
## Type: sacmixed
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 50.8859986 29.1817765 1.7438 0.08120
## TPT 0.2518314 0.1839399 1.3691 0.17097
## PDRB -0.0026465 0.0081610 -0.3243 0.74572
## IPM -0.4399850 0.0956475 -4.6001 4.224e-06
## GINI 19.2987749 7.8683875 2.4527 0.01418
## lag.TPT -0.5364431 0.3414370 -1.5711 0.11615
## lag.PDRB 0.0031261 0.0260318 0.1201 0.90441
## lag.IPM -0.1942414 0.3390701 -0.5729 0.56674
## lag.GINI -10.2259445 18.7534928 -0.5453 0.58556
##
## Rho: 0.31514
## Asymptotic standard error: 0.58522
## z-value: 0.5385, p-value: 0.59023
## Lambda: 0.38332
## Asymptotic standard error: 0.59239
## z-value: 0.64707, p-value: 0.51758
##
## LR test value: 20.478, p-value: 0.0022761
##
## Log likelihood: -39.9514 for sacmixed model
## ML residual variance (sigma squared): 1.0572, (sigma: 1.0282)
## Number of observations: 27
## Number of parameters estimated: 12
## AIC: 103.9, (AIC for lm: 112.38)
impacts_gns <- impacts(gns_jabar, listw = lw_queen, R = 999)
summary(impacts_gns, zstats = TRUE, short = TRUE)
## Impact measures (sacmixed, exact):
## Direct Indirect Total
## TPT dy/dx 0.21185842 -0.627435256 -0.4155768354
## PDRB dy/dx -0.00244606 0.003146329 0.0007002691
## IPM dy/dx -0.46909794 -0.456970178 -0.9260681209
## GINI dy/dx 18.93636004 -5.688633168 13.2477268723
## ========================================================
## Simulation results ( variance matrix):
## ========================================================
## Simulated standard errors
## Direct Indirect Total
## TPT dy/dx 0.34865335 6.640903 6.9247158
## PDRB dy/dx 0.02644265 0.579019 0.6036337
## IPM dy/dx 0.25034767 5.554890 5.7850484
## GINI dy/dx 15.14916279 281.032374 293.3327719
##
## Simulated z-values:
## Direct Indirect Total
## TPT dy/dx 0.65242103 -0.15511006 -0.115903972
## PDRB dy/dx -0.04622883 0.01188410 0.009374409
## IPM dy/dx -1.93974093 -0.13540182 -0.213957039
## GINI dy/dx 1.28430861 -0.02003272 0.047135396
##
## Simulated p-values:
## Direct Indirect Total
## TPT dy/dx 0.514130 0.87673 0.90773
## PDRB dy/dx 0.963128 0.99052 0.99252
## IPM dy/dx 0.052411 0.89229 0.83058
## GINI dy/dx 0.199034 0.98402 0.96241
# 3. SAC/SARAR ----
# Estimasi model SAC / SARAR
sac_jabar <- sacsarlm(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
method = "eigen", # metode numerik dekomposisi eigen
zero.policy = TRUE
)
# Ringkasan hasil model
summary(sac_jabar)
##
## Call:sacsarlm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar,
## listw = lw_queen, method = "eigen", zero.policy = TRUE)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.618260 -0.433617 -0.067514 0.402969 3.049638
##
## Type: sac
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 27.3556558 5.3130193 5.1488 2.622e-07
## TPT 0.0828665 0.1562761 0.5303 0.5959
## PDRB -0.0066943 0.0077519 -0.8636 0.3878
## IPM -0.4018809 0.0762069 -5.2735 1.338e-07
## GINI 11.7918439 7.2013261 1.6375 0.1015
##
## Rho: 0.73341
## Asymptotic standard error: 0.14298
## z-value: 5.1295, p-value: 2.9057e-07
## Lambda: -0.31297
## Asymptotic standard error: 0.34317
## z-value: -0.91202, p-value: 0.36176
##
## LR test value: 13.483, p-value: 0.0011812
##
## Log likelihood: -43.44892 for sac model
## ML residual variance (sigma squared): 1.194, (sigma: 1.0927)
## Number of observations: 27
## Number of parameters estimated: 8
## AIC: 102.9, (AIC for lm: 112.38)
# 4. SAR ----
# Estimasi model SAR
sar_jabar <- lagsarlm(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
method = "eigen",
zero.policy = TRUE
)
# Ringkasan hasil estimasi
summary(sar_jabar)
##
## Call:lagsarlm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar,
## listw = lw_queen, method = "eigen", zero.policy = TRUE)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.811768 -0.603120 0.058127 0.410091 3.318332
##
## Type: lag
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 28.4991886 5.1628398 5.5201 3.389e-08
## TPT 0.1132664 0.1721913 0.6578 0.51067
## PDRB -0.0087101 0.0083088 -1.0483 0.29450
## IPM -0.4132629 0.0803241 -5.1449 2.676e-07
## GINI 12.7051666 7.6638468 1.6578 0.09736
##
## Rho: 0.65269, LR test value: 12.428, p-value: 0.00042297
## Asymptotic standard error: 0.12453
## z-value: 5.2411, p-value: 1.5964e-07
## Wald statistic: 27.469, p-value: 1.5964e-07
##
## Log likelihood: -43.97625 for lag model
## ML residual variance (sigma squared): 1.3317, (sigma: 1.154)
## Number of observations: 27
## Number of parameters estimated: 7
## AIC: 101.95, (AIC for lm: 112.38)
## LM test for residual autocorrelation
## test value: 1.4493, p-value: 0.22865
# Hitung impacts (dengan simulasi Monte Carlo R=500)
imp_sar <- impacts(
sar_jabar,
listw = lw_queen,
R = 500, # jumlah replikasi simulasi (biasanya 500–1000)
zero.policy = TRUE
)
# Tampilkan hasil ringkas
summary(imp_sar, zstats = TRUE, short = TRUE)
## Impact measures (lag, exact):
## Direct Indirect Total
## TPT dy/dx 0.13200312 0.19411954 0.32612265
## PDRB dy/dx -0.01015097 -0.01492769 -0.02507866
## IPM dy/dx -0.48162546 -0.70826290 -1.18988836
## GINI dy/dx 14.80687435 21.77451312 36.58138746
## ========================================================
## Simulation results ( variance matrix):
## ========================================================
## Simulated standard errors
## Direct Indirect Total
## TPT dy/dx 0.205683618 0.50647847 0.68261387
## PDRB dy/dx 0.009929494 0.03226359 0.03991287
## IPM dy/dx 0.103413999 0.83325294 0.89829356
## GINI dy/dx 9.366448647 38.55651486 45.32990789
##
## Simulated z-values:
## Direct Indirect Total
## TPT dy/dx 0.660727 0.4926766 0.5646395
## PDRB dy/dx -1.058324 -0.6203655 -0.7647617
## IPM dy/dx -4.779253 -1.0765981 -1.5488481
## GINI dy/dx 1.630268 0.7295042 0.9573582
##
## Simulated p-values:
## Direct Indirect Total
## TPT dy/dx 0.50879 0.62224 0.57232
## PDRB dy/dx 0.28991 0.53502 0.44441
## IPM dy/dx 1.7595e-06 0.28166 0.12142
## GINI dy/dx 0.10304 0.46569 0.33839
# SLX ----
# Estimasi model SLX
slx_jabar <- lmSLX(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
Durbin = TRUE, # aktifkan lag pada variabel X (WX)
zero.policy = TRUE
)
# Ringkasan hasil model
summary(slx_jabar)
##
## Call:
## lm(formula = formula(paste("y ~ ", paste(colnames(x)[-1], collapse = "+"))),
## data = as.data.frame(x), weights = weights)
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 62.758787 16.696300 3.758844 0.001437
## TPT 0.188540 0.264058 0.714009 0.484378
## PDRB 0.001629 0.011827 0.137714 0.891995
## IPM -0.494633 0.131822 -3.752286 0.001458
## GINI 19.022804 11.413348 1.666715 0.112876
## lag.TPT -0.517804 0.459869 -1.125981 0.274963
## lag.PDRB -0.002175 0.037836 -0.057478 0.954798
## lag.IPM -0.264498 0.342100 -0.773158 0.449464
## lag.GINI -9.208540 28.632934 -0.321607 0.751455
# Efek langsung, tidak langsung, dan total
impacts_slx <- impacts(slx_jabar, listw = lw_queen, R = 999)
summary(impacts_slx, zstats = TRUE, short = FALSE)
## Impact measures (SlX, glht, n-k):
## Direct Indirect Total
## TPT dy/dx 0.188539631 -0.517803935 -0.3292643039
## PDRB dy/dx 0.001628748 -0.002174735 -0.0005459867
## IPM dy/dx -0.494633172 -0.264497733 -0.7591309044
## GINI dy/dx 19.022803508 -9.208539596 9.8142639114
## ========================================================
## Standard errors:
## Direct Indirect Total
## TPT dy/dx 0.26405783 0.45986930 0.50045586
## PDRB dy/dx 0.01182703 0.03783591 0.03690502
## IPM dy/dx 0.13182183 0.34210045 0.29496886
## GINI dy/dx 11.41334794 28.63293396 29.69946736
## ========================================================
## Z-values:
## Direct Indirect Total
## TPT dy/dx 0.7140089 -1.12598064 -0.65792876
## PDRB dy/dx 0.1377140 -0.05747805 -0.01479437
## IPM dy/dx -3.7522856 -0.77315810 -2.57359678
## GINI dy/dx 1.6667155 -0.32160657 0.33045252
##
## p-values:
## Direct Indirect Total
## TPT dy/dx 0.47522169 0.26017 0.510584
## PDRB dy/dx 0.89046643 0.95416 0.988196
## IPM dy/dx 0.00017523 0.43943 0.010065
## GINI dy/dx 0.09557100 0.74775 0.741058
# SEM ----
# Estimasi model SEM
sem_jabar <- errorsarlm(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
method = "eigen",
zero.policy = TRUE
)
# Ringkasan hasil model
summary(sem_jabar)
##
## Call:errorsarlm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar,
## listw = lw_queen, method = "eigen", zero.policy = TRUE)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.16279 -0.86976 -0.11366 0.80556 3.20803
##
## Type: error
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 33.649799 5.679634 5.9246 3.130e-09
## TPT 0.303626 0.192064 1.5809 0.11391
## PDRB -0.005517 0.008960 -0.6157 0.53807
## IPM -0.456813 0.092540 -4.9364 7.959e-07
## GINI 19.147958 8.015995 2.3887 0.01691
##
## Lambda: 0.76303, LR test value: 8.3202, p-value: 0.0039206
## Asymptotic standard error: 0.1119
## z-value: 6.8192, p-value: 9.1565e-12
## Wald statistic: 46.501, p-value: 9.1563e-12
##
## Log likelihood: -46.03007 for error model
## ML residual variance (sigma squared): 1.4495, (sigma: 1.204)
## Number of observations: 27
## Number of parameters estimated: 7
## AIC: 106.06, (AIC for lm: 112.38)
# SDEM ----
# Estimasi model SDEM
sdem_jabar <- errorsarlm(
KEMISKINAN ~ TPT + PDRB + IPM + GINI,
data = jabar,
listw = lw_queen,
Durbin = TRUE, # aktifkan lag pada variabel X
method = "eigen",
zero.policy = TRUE
)
# Ringkasan hasil model
summary(sdem_jabar)
##
## Call:errorsarlm(formula = KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar,
## listw = lw_queen, Durbin = TRUE, method = "eigen", zero.policy = TRUE)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.01471 -0.68286 0.15237 0.55950 2.17018
##
## Type: error
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 64.6681636 12.4764414 5.1832 2.181e-07
## TPT 0.2309217 0.1778903 1.2981 0.19425
## PDRB -0.0028092 0.0080739 -0.3479 0.72789
## IPM -0.4642902 0.0819782 -5.6636 1.482e-08
## GINI 19.0523236 7.9231049 2.4047 0.01619
## lag.TPT -0.5258451 0.3602129 -1.4598 0.14434
## lag.PDRB -0.0021198 0.0238506 -0.0889 0.92918
## lag.IPM -0.3421141 0.2055820 -1.6641 0.09609
## lag.GINI -4.9824738 17.1255537 -0.2909 0.77110
##
## Lambda: 0.6422, LR test value: 8.0242, p-value: 0.0046156
## Asymptotic standard error: 0.14849
## z-value: 4.3249, p-value: 1.526e-05
## Wald statistic: 18.705, p-value: 1.526e-05
##
## Log likelihood: -40.16573 for error model
## ML residual variance (sigma squared): 1.0095, (sigma: 1.0047)
## Number of observations: 27
## Number of parameters estimated: 11
## AIC: 102.33, (AIC for lm: 108.36)
# BANDINGKAN MODEL ----
compare_stats <- data.frame(
Model = c("OLS","SLX","SAR","SDM","GNS","SAC/SARAR","SEM","SDEM"),
LogLik = c(logLik(ols_jabar), logLik(slx_jabar), logLik(sar_jabar),
logLik(sdm_jabar), logLik(gns_jabar), logLik(sac_jabar),
logLik(sem_jabar), logLik(sdem_jabar)),
AIC = c(AIC(ols_jabar), AIC(slx_jabar), AIC(sar_jabar),
AIC(sdm_jabar), AIC(gns_jabar), AIC(sac_jabar),
AIC(sem_jabar), AIC(sdem_jabar))
)
compare_stats
## Model LogLik AIC
## 1 OLS -50.19019 112.3804
## 2 SLX -44.17784 108.3557
## 3 SAR -43.97625 101.9525
## 4 SDM -40.16333 102.3267
## 5 GNS -39.95140 103.9028
## 6 SAC/SARAR -43.44892 102.8978
## 7 SEM -46.03007 106.0601
## 8 SDEM -40.16573 102.3315
# VISUALISASI MODEL ----
# Prediksi in-sample & residual
jabar_pred <- jabar %>%
mutate(
y_hat = as.numeric(fitted(sar_jabar)), # prediksi SAR
resid = as.numeric(residuals(sar_jabar)), # residual
z_resid = as.numeric(scale(resid)) # residual distandarkan (opsional)
)
## This method assumes the response is known - see manual page
# Peta Prediksi (nilai taksiran kemiskinan)
p_pred <- ggplot(jabar_pred) +
geom_sf(aes(fill = y_hat), color = "white", size = 0.2) +
scale_fill_viridis_c(name = "Prediksi\nKemiskinan (%)",
option = "C", direction = -1) +
labs(title = "Peta Prediksi (SAR) – Kemiskinan Jawa Barat") +
theme_minimal(base_size = 12) +
theme(axis.title = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank())
p_pred
# Peta Kemiskinan Aktual
p_kemiskinan
# Peta Residual (standar, pusat di 0, divergen)
# Pilih limit simetris agar mudah baca deviasi +/- (opsional)
lim_resid <- max(abs(jabar_pred$z_resid), na.rm = TRUE)
p_resid <- ggplot(jabar_pred) +
geom_sf(aes(fill = z_resid), color = "white", size = 0.2) +
scale_fill_gradient2(
name = "Residual (z)",
low = "#2c7bb6", mid = "white", high = "#d7191c",
midpoint = 0, limits = c(-lim_resid, lim_resid), oob = squish
) +
labs(title = "Peta Residual Standar (SAR) – Kemiskinan Jawa Barat",
subtitle = "Merah: terprediksi terlalu rendah (underfit) • Biru: terprediksi terlalu tinggi (overfit)") +
theme_minimal(base_size = 12) +
theme(axis.title = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank())
p_resid
# Klasifikasi sederhana residual z (untuk legenda diskrit)
jabar_pred <- jabar_pred %>%
mutate(res_cat = cut(z_resid,
breaks = c(-Inf, -1.96, -1, 1, 1.96, Inf),
labels = c("<= -1.96", "(-1.96,-1]", "(-1,1]", "(1,1.96]", ">= 1.96"),
include.lowest = TRUE))
p_resid_disc <- ggplot(jabar_pred) +
geom_sf(aes(fill = res_cat), color = "white", size = 0.2) +
scale_fill_brewer(name = "Residual (z)", palette = "RdBu", direction = -1, drop = FALSE) +
labs(title = "Peta Residual Standar (SAR) – Klasifikasi Diskrit") +
theme_minimal(base_size = 12) +
theme(axis.title = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank())
p_resid_disc
# Peta interaktif (leaflet)
# jabar_pred: sf dengan kolom kabupaten, y_hat, KEMISKINAN, z_resid
# 1) siapkan VEKTOR label (satu elemen per baris)
labels <- sprintf(
"<b>%s</b><br/>Prediksi: %.2f<br/>Aktual: %.2f<br/>Residual (z): %.2f",
jabar_pred$kabupaten,
jabar_pred$y_hat,
jabar_pred$KEMISKINAN,
jabar_pred$z_resid
) |> lapply(HTML) # <- list of HTML snippets, panjang = nrow(jabar_pred)
# 2) palet
pal_pred <- colorNumeric("viridis", domain = jabar_pred$y_hat)
# 3) plot leaflet (label per-fitur)
leaflet(jabar_pred) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(
fillColor = ~pal_pred(y_hat),
color = "white", weight = 1, fillOpacity = 0.85,
label = labels, # <- pakai vektor 'labels', bukan ~HTML(...)
labelOptions = labelOptions(direction = "auto"),
highlightOptions = highlightOptions(weight = 2, bringToFront = TRUE)
) %>%
addLegend("bottomright", pal = pal_pred, values = ~y_hat, title = "Prediksi (%)")
# Uji Bobot W ----
# --- 1. Definisikan beberapa matriks bobot ---
nb_queen <- poly2nb(jabar, queen = TRUE)
lw_queen <- nb2listw(nb_queen, style = "W")
nb_rook <- poly2nb(jabar, queen = FALSE)
lw_rook <- nb2listw(nb_rook, style = "W")
coords <- sf::st_coordinates(sf::st_centroid(jabar))
## Warning: st_centroid assumes attributes are constant over geometries
nb_knn4 <- knn2nb(knearneigh(coords, k = 4))
lw_knn4 <- nb2listw(nb_knn4, style = "W")
# --- 2. Jalankan model SAR untuk setiap W ---
sar_queen <- lagsarlm(KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar, listw = lw_queen)
sar_rook <- lagsarlm(KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar, listw = lw_rook)
sar_knn4 <- lagsarlm(KEMISKINAN ~ TPT + PDRB + IPM + GINI, data = jabar, listw = lw_knn4)
# --- 3. Bandingkan hasil utama ---
data.frame(
Bobot = c("Queen", "Rook", "KNN-4"),
Rho = c(sar_queen$rho, sar_rook$rho, sar_knn4$rho),
AIC = c(AIC(sar_queen), AIC(sar_rook), AIC(sar_knn4)),
LogLik = c(logLik(sar_queen), logLik(sar_rook), logLik(sar_knn4))
)
## Bobot Rho AIC LogLik
## 1 Queen 0.6526877 101.9525 -43.97625
## 2 Rook 0.6526877 101.9525 -43.97625
## 3 KNN-4 0.4871373 105.5565 -45.77824
\[ # =========================================================# app.R — West Java Poverty Dashboard 2024 (VERSI 4.1 - FIX)# =========================================================suppressPackageStartupMessages({ library(shiny) library(shinydashboard) library(DT) library(sf) library(dplyr) library(stringr) library(spdep) library(spatialreg) library(ggplot2) library(viridis) library(scales) library(psych) library(forcats) library(purrr) library(lmtest) library(car) library(readxl) library(leaflet) library(htmltools) library(gridExtra) library(openxlsx) library(showtext) library(sysfonts)})# -------------------------# GLOBAL: Fonts & Assets# -------------------------# Poppins font (UI & plot)try({ font_add_google("Poppins", "Poppins", regular.wt = 400, bold.wt = 700) showtext_auto(enable = TRUE)}, silent = TRUE)theme_set(theme_minimal(base_size = 12, base_family = "Poppins"))# -------------------------# GLOBAL: Data & helpers# -------------------------shp_path <- "data/geoBoundaries-IDN-ADM2.shp"excel_path <- "data/DATA SPASIAL.xlsx"indo_adm2 <- st_read(shp_path, quiet = TRUE)kab_jabar <- c( "Bandung","Bandung Barat","Bekasi","Bogor","Ciamis","Cianjur","Cirebon", "Garut","Indramayu","Karawang","Kuningan","Majalengka","Pangandaran", "Purwakarta","Subang","Sukabumi","Sumedang","Tasikmalaya", "Kota Bandung","Kota Bekasi","Kota Bogor","Kota Cimahi", "Kota Cirebon","Kota Depok","Kota Sukabumi","Kota Tasikmalaya","Kota Banjar")indo_adm2 <- indo_adm2 %>% mutate(shapeName_clean = str_to_lower(str_squish(shapeName)))jabar <- indo_adm2 %>% filter(shapeName_clean %in% str_to_lower(kab_jabar))attr <- read_xlsx(excel_path) %>% rename(kabupaten = dplyr::matches("^KAB|KOTA", ignore.case = TRUE)) %>% mutate(kabupaten = as.character(kabupaten), shapeName_clean = str_to_lower(str_squish(kabupaten)))jabar <- jabar %>% left_join(attr, by = "shapeName_clean")vars <- c("KEMISKINAN","TPT","PDRB","IPM","GINI")var_labels <- c( KEMISKINAN = "KEMISKINAN", TPT = "TPT", PDRB = "PDRB", IPM = "IPM", GINI = "GINI RATIO")stats_limits <- function(x) { x <- x[is.finite(x)] mu <- mean(x) sig <- sd(x) lo <- mu - 3*sig hi <- mu + 3*sig lo <- max(min(x), lo) hi <- min(max(x), hi) c(lo, hi)}# Weightsnb_queen <- poly2nb(jabar, queen = TRUE)lw_queen <- nb2listw(nb_queen, style = "W", zero.policy = TRUE)nb_rook <- poly2nb(jabar, queen = FALSE)lw_rook <- nb2listw(nb_rook, style = "W", zero.policy = TRUE)coords <- sf::st_coordinates(sf::st_centroid(jabar))nb_knn4 <- knn2nb(knearneigh(coords, k = 4))lw_knn4 <- nb2listw(nb_knn4, style = "W", zero.policy = TRUE)round3_df <- function(df) df %>% mutate(across(where(is.numeric), ~ round(., 3)))desc_table <- function(df_num) { d <- psych::describe(df_num) %>% as.data.frame() %>% tibble::rownames_to_column("Variabel") %>% select(Variabel, mean, sd, median, min, max, skew, kurtosis) d$var <- d$sd^2 d %>% select(Variabel, mean, sd, var, median, min, max, skew, kurtosis) %>% round3_df()}safe_moran_both_raw <- function(y, nb, nsim = 999, seed = 77) { ok <- is.finite(y); y_use <- y[ok] nb_sub <- if (all(ok)) nb else spdep::subset.nb(nb, ok) lw_sub <- nb2listw(nb_sub, style = "W", zero.policy = TRUE) mt <- moran.test(y_use, lw_sub, zero.policy = TRUE) set.seed(seed); mmc <- moran.mc(y_use, lw_sub, nsim = nsim, zero.policy = TRUE) list(mt = mt, mmc = mmc)}safe_geary_both_raw <- function(y, nb, nsim = 999, seed = 77) { ok <- is.finite(y); y_use <- y[ok] nb_sub <- if (all(ok)) nb else spdep::subset.nb(nb, ok) lw_sub <- nb2listw(nb_sub, style = "W", zero.policy = TRUE) gt <- geary.test(y_use, lw_sub, randomisation = TRUE, zero.policy = TRUE) set.seed(seed); gmc <- geary.mc(y_use, lw_sub, nsim = nsim, zero.policy = TRUE) list(gt = gt, gmc = gmc)}compute_lisa <- function(y, nb, sig_thr = 0.05) { ok <- is.finite(y); y_use <- y[ok] lw_sub <- nb2listw(if (all(ok)) nb else spdep::subset.nb(nb, ok), style = "W", zero.policy = TRUE) z <- as.numeric(scale(y_use)) lz <- lag.listw(lw_sub, z, zero.policy = TRUE) lisa <- as.data.frame(localmoran(z, lw_sub, zero.policy = TRUE)) p_two <- if ("Pr(z > 0)" %in% names(lisa)) { p_right <- lisa[,"Pr(z > 0)"]; p_left <- 1 - p_right; 2*pmin(p_right, p_left) } else if ("Pr(z <= 0)" %in% names(lisa)) { p_left <- lisa[,"Pr(z <= 0)"]; p_right <- 1 - p_left; 2*pmin(p_right, p_left) } else if ("Pr(z != E(Ii))" %in% names(lisa)) { lisa[,"Pr(z != E(Ii))"] } else 2*pnorm(-abs(lisa[,"Z.Ii"])) quad <- ifelse(z >= 0 & lz >= 0, "High-High", ifelse(z < 0 & lz < 0, "Low-Low", ifelse(z >= 0 & lz < 0, "High-Low", "Low-High"))) cl <- ifelse(p_two <= sig_thr, quad, "Not Significant") list(z = z, lagz = lz, Ii = lisa$Ii, Zi = lisa$Z.Ii, p = p_two, cluster = cl, ok = ok)}compute_gistar <- function(x, nb) { ok <- is.finite(x); x_use <- x[ok] nb_sub <- if (all(ok)) nb else spdep::subset.nb(nb, ok) lw_sub <- nb2listw(nb_sub, style = "W", zero.policy = TRUE) Gz <- spdep::localG(x_use, listw = lw_sub, zero.policy = TRUE) z_full <- rep(NA_real_, length(x)); z_full[ok] <- as.numeric(Gz) cat <- case_when( z_full >= 1.96 ~ "Hot spot", z_full <= -1.96 ~ "Cold spot", TRUE ~ "Not significant" ) list(z = z_full, cat = factor(cat, levels = c("Hot spot","Cold spot","Not significant")))}fit_models <- function(sfobj, yname, xnames, lw) { fml <- as.formula(paste(yname, "~", paste(xnames, collapse = " + "))) ols <- lm(fml, data = sfobj) slx <- lmSLX(fml, data = sfobj, listw = lw, Durbin = TRUE, zero.policy = TRUE) sar <- lagsarlm(fml, data = sfobj, listw = lw, method = "eigen", zero.policy = TRUE) sdm <- lagsarlm(fml, data = sfobj, listw = lw, Durbin = TRUE, method = "eigen", zero.policy = TRUE) gns <- sacsarlm(fml, data = sfobj, listw = lw, Durbin = TRUE, method = "eigen", zero.policy = TRUE) sac <- sacsarlm(fml, data = sfobj, listw = lw, method = "eigen", zero.policy = TRUE) sem <- errorsarlm(fml, data = sfobj, listw = lw, method = "eigen", zero.policy = TRUE) sdem <- errorsarlm(fml, data = sfobj, listw = lw, Durbin = TRUE, method = "eigen", zero.policy = TRUE) list(ols = ols, slx = slx, sar = sar, sdm = sdm, gns = gns, sac = sac, sem = sem, sdem = sdem)}model_long_names <- c( "OLS" = "OLS (Ordinary Least Square)", "SLX" = "SLX (Spatial Lag of X Model)", "SAR" = "SAR (Spatial Autoregressive)", "SDM" = "SDM (Spatial Durbin Model)", "GNS" = "GNS (General Nesting Spatial)", "SAC/SARAR" = "SAC/SARAR (Spatial Autoregressive Combined)", "SEM" = "SEM (Spatial Error Model)", "SDEM" = "SDEM (Spatial Durbin Error Model)")model_stats <- function(models, y) { get_loglik <- function(m) tryCatch(as.numeric(logLik(m)), error = function(e) NA_real_) get_aic <- function(m) tryCatch(AIC(m), error = function(e) NA_real_) get_r2 <- function(m, y) { if (inherits(m, "lm")) return(summary(m)$r.squared) if (!is.null(m$s2)) return(1 - (m$s2 / var(y))) NA_real_ } tibble::tibble( ModelKey = c("OLS","SLX","SAR","SDM","GNS","SAC/SARAR","SEM","SDEM"), `Log-Likelihood` = c(get_loglik(models$ols), get_loglik(models$slx), get_loglik(models$sar), get_loglik(models$sdm), get_loglik(models$gns), get_loglik(models$sac), get_loglik(models$sem), get_loglik(models$sdem)), AIC = c(get_aic(models$ols), get_aic(models$slx), get_aic(models$sar), get_aic(models$sdm), get_aic(models$gns), get_aic(models$sac), get_aic(models$sem), get_aic(models$sdem)), `R²` = c(get_r2(models$ols, y), get_r2(models$slx, y), get_r2(models$sar, y), get_r2(models$sdm, y), get_r2(models$gns, y), get_r2(models$sac, y), get_r2(models$sem, y), get_r2(models$sdem, y)) ) %>% mutate(Model = unname(model_long_names[ModelKey])) %>% select(ModelKey, Model, `Log-Likelihood`, AIC, `R²`) %>% round3_df()}bar_cell <- function(value, minv, maxv, color = "#b05d39", txt_color = "#3e2723") { if (is.na(value)) return("") pct <- if (maxv == minv) 100 else scales::rescale(value, to = c(8, 100), from = c(minv, maxv)) lbl <- format(round(value, 3), nsmall = 3) htmltools::tags$div(style = sprintf( "background: linear-gradient(to right, %s %0.2f%%, rgba(0,0,0,0) %0.2f%%); padding:3px 8px; border-radius:6px; color:%s; font-weight:600; font-family:Poppins,system-ui,sans-serif;", color, pct, pct, txt_color ), lbl) |> as.character()}# =========================================================# UI# =========================================================ui <- dashboardPage( dashboardHeader(title = "West Java Poverty Dashboard 2024", tags$li(class = "dropdown", tags$a(href = "https://unpad.ac.id", target = "_blank", tags$img(src = "logo_unpad.png", height = "30px", style = "margin-top:10px;") ) ) ), dashboardSidebar(collapsed = FALSE, sidebarMenu(id = "tabs", menuItem("Data", tabName = "data", icon = icon("table")), menuItem("Statistika Deskriptif", tabName = "des", icon = icon("chart-bar")), menuItem("Peta", tabName = "peta", icon = icon("map")), menuItem("Autokorelasi Spasial", tabName = "auto", icon = icon("project-diagram")), menuItem("Pemodelan", tabName = "model", icon = icon("cogs")), menuItem("About", tabName = "about", icon = icon("info-circle")) ) ), dashboardBody( tags$head( tags$style(HTML(" /* Import Poppins Font */ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap'); :root{ --bg: #fdfaf6; /* Light Cream */ --header: #5d4037; /* Dark Warm Brown */ --sidebar: #5d4037; /* COKLAT TERANG (YANG DIGANTI) */ --sidebar-hover: #5d4037; /* Coklat Lebih Terang - Hover (YANG DIGANTI) */ --box-primary: #b05d39; /* Earthy Rust/Terracotta */ --text: #3e2723; /* Darkest Brown */ --text-inv: #fdfaf6; /* Light Cream (Teks sidebar tetap terang) */ --ink: #3e2723; /* Darkest Brown */ } /* Background dengan highlight lembut yang bergerak */ body, .content-wrapper, .right-side { background-color: var(--bg); font-family:'Poppins', system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; position: relative; overflow-x: hidden; } body::before{ content:''; position: fixed; inset:-20% -20% -20% -20%; background: radial-gradient(600px 400px at 15% 25%, rgba(93,64,55,0.06), transparent 60%), radial-gradient(700px 450px at 80% 20%, rgba(176,93,57,0.05), transparent 60%), radial-gradient(800px 500px at 30% 85%, rgba(78,52,46,0.05), transparent 60%); animation: floatBg 18s ease-in-out infinite alternate; pointer-events:none; z-index:-1; } @keyframes floatBg{ 0%{ transform: translate3d(0,0,0) scale(1); filter: blur(0px); } 100%{ transform: translate3d(-2%, -1%, 0) scale(1.02); filter: blur(0.2px); } } /* Header & navbar dengan animasi halus */ .skin-blue .main-header .logo, .skin-blue .main-header .navbar { background-color: var(--header); color: var(--text-inv); box-shadow: 0 6px 24px rgba(62,39,35,0.18); transition: box-shadow .25s ease, transform .2s ease, filter .25s ease; } .skin-blue .main-header .logo:hover{ transform: translateY(-1px); filter: brightness(1.04); } /* PENYESUAIAN CSS SIDEBAR (SESUAI WARNA BARU) */ .skin-blue .main-sidebar { background-color: var(--sidebar); } .skin-blue .sidebar a { color: var(--text-inv); transition: color .2s ease; } /* Teks pakai variabel */ .skin-blue .sidebar-menu>li>a{ position: relative; transition: background-color .2s ease, color .2s ease, transform .15s ease; } .skin-blue .sidebar-menu>li.active>a, .skin-blue .sidebar-menu>li:hover>a { background: var(--sidebar-hover); color: #fff; /* Teks tetap putih/terang saat hover */ transform: translateX(2px); } /* Indikator aktif animatif di sisi kiri item */ .skin-blue .sidebar-menu>li.active>a::before, .skin-blue .sidebar-menu>li:hover>a::before{ content:''; position:absolute; left:0; top:8px; bottom:8px; width:3px; background:#ffffff; /* Indikator putih cocok di coklat terang */ border-radius:2px; animation: glow 2.4s ease-in-out infinite; } @keyframes glow{ 0%,100%{ box-shadow: 0 0 0 rgba(255,255,255,0.0); } 50%{ box-shadow: 0 0 10px rgba(255,255,255,0.35); } } /* Kartu/box dengan efek hover */ .box { border: none; /* Hapus semua border bawaan */ border-radius: 10px; background: #fff; transition: transform .18s ease, box-shadow .25s ease, border-color .25s ease; box-shadow: 0 6px 20px rgba(0,0,0,0.06); } /* Hanya tambahkan border-top ke box non-solid */ .box:not(.box-solid) { border-top: 3px solid var(--box-primary); } .box:hover{ transform: translateY(-2px); box-shadow: 0 14px 30px rgba(0,0,0,0.12); } /* Pastikan header solid box masih memiliki border radius yang pas */ .box.box-solid.box-primary>.box-header { color:#fff; background: var(--box-primary); position: relative; overflow: hidden; /* Pastikan radius atas sesuai dengan box */ border-top-left-radius: 10px; border-top-right-radius: 10px; } /* sheen animasi lembut pada header box */ .box.box-solid.box-primary>.box-header::after{ content:''; position:absolute; top:0; bottom:0; left:-40%; width:40%; background: linear-gradient(90deg, rgba(255,255,255,0.2), transparent); transform: skewX(-20deg); animation: sheen 4s linear infinite; } @keyframes sheen{ 0%{ left:-40%; } 100%{ left:120%; } } /* Tombol dengan ripple & hover */ .btn, .btn-default, .btn-primary { border-radius: 10px; transition: transform .08s ease, box-shadow .2s ease, filter .2s ease; box-shadow: 0 6px 18px rgba(0,0,0,0.08); } .btn:hover{ filter: brightness(1.04); box-shadow: 0 10px 22px rgba(0,0,0,0.12); } .btn:active{ transform: scale(0.98); } /* Konten */ .content { padding-top: 10px; } /* DataTable: highlight baris, transisi */ table.dataTable { color: var(--ink); } .dataTables_wrapper .dataTables_paginate .paginate_button { border-radius:6px; transition: background-color .2s ease, transform .1s ease; } .dataTables_wrapper .dataTables_paginate .paginate_button:hover{ background: rgba(0,0,0,0.06); transform: translateY(-1px); } table.dataTable tbody tr{ transition: background-color .15s ease; } table.dataTable tbody tr:hover{ background-color: rgba(176,93,57,0.08); } /* Leaflet: kontrol & tooltip dengan efek halus */ .leaflet-container { font-family: 'Poppins', sans-serif; } .leaflet-bar a{ transition: transform .12s ease, box-shadow .2s ease, filter .2s ease; box-shadow: 0 4px 12px rgba(0,0,0,0.08); } .leaflet-bar a:hover{ transform: translateY(-1px); filter: brightness(1.04); } .leaflet-tooltip{ background: rgba(255,255,255,0.95); border: 1px solid rgba(62,39,35,0.15); color: var(--ink); transition: opacity .2s ease; } /* Scrollbar halus */ ::-webkit-scrollbar{ width: 10px; height:10px; } ::-webkit-scrollbar-thumb{ background: rgba(62,39,35,0.2); border-radius: 8px; transition: background .2s ease; } ::-webkit-scrollbar-thumb:hover{ background: rgba(62,39,35,0.32); } ")), # Ripple kecil untuk tombol (tanpa ubah warna) tags$script(HTML(" (function(){ function ripple(e){ var btn = e.currentTarget; var circle = document.createElement('span'); circle.className = 'ripple-span'; var d = Math.max(btn.clientWidth, btn.clientHeight); circle.style.width = circle.style.height = d+'px'; var rect = btn.getBoundingClientRect(); circle.style.left = (e.clientX - rect.left - d/2)+'px'; circle.style.top = (e.clientY - rect.top - d/2)+'px'; btn.appendChild(circle); setTimeout(function(){ circle.remove(); }, 450); } document.addEventListener('DOMContentLoaded', function(){ document.querySelectorAll('.btn, .btn-default, .btn-primary').forEach(function(b){ b.style.position='relative'; b.style.overflow='hidden'; b.addEventListener('click', ripple); }); }); })(); ")), tags$style(HTML(" .ripple-span{ position:absolute; border-radius:50%; transform: scale(0); background: rgba(0,0,0,0.12); animation: ripple .45s ease-out; pointer-events:none; opacity:1; } @keyframes ripple{ to{ transform: scale(2.6); opacity:0; } } ")) ), tabItems( # ------------ DATA ------------ tabItem(tabName = "data", fluidRow( # Box ini TIDAK solid, jadi akan punya border-top box(width = 3, title = "Download Data", status = "primary", solidHeader = FALSE, tags$p(tags$em("Sumber data: Badan Pusat Statistik Provinsi Jawa Barat 2024")), downloadButton("download_data_csv", "Download CSV"), br(), br(), downloadButton("download_data_xlsx", "Download XLSX") ), # Box ini solid, jadi TIDAK akan punya border-top box(width = 9, title = "Data Overview", status = "primary", solidHeader = TRUE, DTOutput("data_table") ) ) ), # ------------ DESKRIPTIF ------------ tabItem(tabName = "des", fluidRow( box(width = 3, title = "Pengaturan", status = "primary", solidHeader = TRUE, selectInput("var_desc", "Pilih variabel:", choices = setNames(vars, var_labels), selected = "KEMISKINAN"), sliderInput("bins", "Jumlah bins histogram:", min = 5, max = 10, value = 7, step = 1), sliderInput("pointSize", "Ukuran titik scatter:", min = 1, max = 6, value = 3), selectInput("x_for_scatter", "Pilih variabel X untuk scatter plot:", choices = setNames(vars[vars != "KEMISKINAN"], var_labels[vars != "KEMISKINAN"]), selected = "IPM"), br(), downloadButton("download_plots", "Download Plot (PNG)") ), box(width = 9, title = "Tabel Statistika Deskriptif", status = "primary", solidHeader = TRUE, DTOutput("desc_table"), hr(), fluidRow( column(6, plotOutput("hist_plot", height = 340)), column(6, plotOutput("box_plot", height = 340)) ), fluidRow( column(12, plotOutput("scatter_plot", height = 520)) ) ) ) ), # ------------ PETA (LEAFLET + download PNG statis) ------------ tabItem(tabName = "peta", fluidRow( box(width = 3, title = "Pengaturan", status = "primary", solidHeader = TRUE, selectInput("var_map_left", "Peta Kiri: variabel", choices = setNames(vars, var_labels), selected = "KEMISKINAN"), selectInput("var_map_right", "Peta Kanan: variabel", choices = setNames(vars, var_labels), selected = "IPM") ), box(width = 9, title = "Peta Penyebaran Data", status = "primary", solidHeader = TRUE, fluidRow( column(6, leafletOutput("map_left", height = 520), br(), downloadButton("dl_map_left_png", "Download PNG (Peta Kiri)") ), column(6, leafletOutput("map_right", height = 520), br(), downloadButton("dl_map_right_png", "Download PNG (Peta Kanan)") ) ) ) ) ), # ------------ AUTOKORELASI SPASIAL ------------ tabItem(tabName = "auto", fluidRow( box(width = 3, title = "Pengaturan", status = "primary", solidHeader = TRUE, selectInput("var_auto", "Pilih variabel:", choices = setNames(vars, var_labels), selected = "KEMISKINAN"), selectInput("auto_method", "Metode:", choices = c("Moran's I","Geary's C","LISA","Getis-Ord G*"), selected = "Moran's I"), conditionalPanel( "input.auto_method == 'LISA'", checkboxGroupInput("lisa_filter", "Filter kategori:", choices = c("High-High","Low-Low","High-Low","Low-High","Not Significant"), selected = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) ), conditionalPanel( "input.auto_method == 'Getis-Ord G*'", checkboxGroupInput("gstar_filter", "Filter kategori:", choices = c("Hot spot","Cold spot","Not significant"), selected = c("Hot spot","Cold spot","Not significant")) ), br(), downloadButton("dl_auto_map_png", "Download PNG (Peta)") ), box(width = 9, title = "Hasil Analisis", status = "primary", solidHeader = TRUE, DTOutput("auto_table"), br(), leafletOutput("auto_map", height = 520) ) ) ), # ------------ PEMODELAN ------------ tabItem(tabName = "model", fluidRow( box(width = 3, title = "Pengaturan", status = "primary", solidHeader = TRUE, selectInput("y_model", "Pilih Variabel Y:", choices = setNames(vars, var_labels), selected = "KEMISKINAN"), checkboxGroupInput("x_model", "Pilih Variabel X:", choices = setNames(vars, var_labels), selected = c("TPT","PDRB","IPM","GINI")), selectInput("w_choice", "Pilih jenis matriks bobot spasial:", choices = c("Queen","Rook","KNN-4"), selected = "Queen"), selectInput("model_pred", "Pilih model untuk peta residual:", choices = c("SAR","SDM","SAC/SARAR","GNS","SLX","SEM","SDEM"), selected = "SAR"), actionButton("fit_btn", "Fit / Refit Model") ), box(width = 9, title = "Ukuran Kebaikan Model", status = "primary", solidHeader = TRUE, DTOutput("model_table"), uiOutput("best_model_cards"), tags$small(HTML( "<b>Catatan:</b> R² pada OLS adalah koefisien determinasi konvensional dari regresi linear. Untuk model spasial, nilai R² yang ditampilkan merupakan <i>Pseudo-R²</i> yang dihitung sebagai 1 − (σ²_model / Var(y))" )), hr(), h4("Peta Residual"), leafletOutput("resid_leaf", height = 520), br(), downloadButton("dl_resid_map_png", "Download PNG (Residual)"), hr(), h4("Uji Sensitivitas Matriks Pembobot Spasial (berdasarkan pilihan Y dan X)"), DTOutput("sens_table"), plotOutput("sens_bar", height = 360), br(), downloadButton("dl_sens_bar", "Download PNG (Bar Chart Sensitivitas)") ) ) ), # ------------ TENTANG KAMI ------------ tabItem(tabName = "about", fluidRow( box(width = 12, title = "About", status = "primary", solidHeader = TRUE, HTML(" <h4><b>Judul Analisis</b></h4> <p><b>PEMILIHAN MODEL TERBAIK DALAM MENGANALISIS FAKTOR EKONOMI DAN SOSIAL TERHADAP TINGKAT KEMISKINAN DI JAWA BARAT TAHUN 2024</b></p> <h4><b>Dibuat pada</b></h4> <p>17 Oktober 2025</p> <h4><b>Dibuat oleh</b></h4> <p>Ara Figura Bilbina — 140610230004</p> <p><b>Mata Kuliah:</b> Spatial Statistics</p> <p><b>Dosen Pengampu:</b> Dr. I Gede Nyoman Mindra Jaya, S. Si., M.Si.</p> <p><b>Instansi:</b> Program Studi Statistika, FMIPA, Universitas Padjadjaran.</p> <p>Dashboard ini dirancang untuk membantu eksplorasi data kemiskinan tingkat kabupaten/kota di Jawa Barat, analisis autokorelasi spasial, pemodelan spasial lanjutan, serta evaluasi sensitivitas matriks bobot. Pengguna dapat menyesuaikan variabel, model, serta parameter visualisasi secara interaktif.</p> ") ) ) ) ) ))# =========================================================# SERVER# =========================================================server <- function(input, output, session){ observeEvent(input$y_model, { if (input$y_model %in% input$x_model) { updateCheckboxGroupInput(session, "x_model", selected = setdiff(input$x_model, input$y_model) ) } }) observeEvent(input$x_model, { if (input$y_model %in% input$x_model) { updateCheckboxGroupInput(session, "x_model", selected = setdiff(input$x_model, input$y_model) ) } }) # ---------- DATA data_df <- reactive({ jabar |> st_drop_geometry() |> transmute( Kabupaten = kabupaten, `KEMISKINAN (%)` = KEMISKINAN, `TPT (%)` = TPT, `PDRB (juta)` = PDRB, IPM = IPM, `GINI RATIO` = GINI ) |> round3_df() }) output$data_table <- renderDT({ DT::datatable(data_df(), options = list(pageLength = 15), rownames = FALSE) }) output$download_data_csv <- downloadHandler( filename = function() "data_spasial_jabar.csv", content = function(file) write.csv(data_df(), file, row.names = FALSE, na = "") ) output$download_data_xlsx <- downloadHandler( filename = function() "data_spasial_jabar.xlsx", content = function(file) openxlsx::write.xlsx(data_df(), file, overwrite = TRUE) ) # ---------- DESKRIPTIF df_num <- reactive({ jabar |> sf::st_drop_geometry() |> dplyr::select(all_of(vars)) }) output$desc_table <- renderDT({ DT::datatable(desc_table(df_num()), rownames = FALSE, options = list(pageLength = 8)) }) # Palet plot tema (Earth Tone Cerah - Opsi 1: Terracotta & Sage) col_hist <- "#D9804C" # Terracotta cerah col_box <- "#9DB589" # Sage green col_outline<- "#3e2723" # Cokelat Tua (kontras) col_point <- "#9DB589" # Sage green col_smooth <- "#f2a900" # Amber output$hist_plot <- renderPlot({ v <- req(input$var_desc) ggplot(jabar, aes(x = .data[[v]])) + geom_histogram(bins = input$bins, color = col_outline, fill = col_hist, closed = "right") + scale_x_continuous(expand = expansion(mult = 0.02)) + labs(title = paste("Histogram", var_labels[[v]]), x = paste0(var_labels[[v]]), y = "Frekuensi") + theme_minimal(base_size = 12, base_family = "Poppins") }) output$box_plot <- renderPlot({ v <- req(input$var_desc) ggplot(jabar, aes(y = .data[[v]])) + geom_boxplot(fill = col_box, color = col_outline) + labs(title = paste("Boxplot", var_labels[[v]]), y = var_labels[[v]], x = "") + theme_minimal(base_size = 12, base_family = "Poppins") }) output$scatter_plot <- renderPlot({ x <- req(input$x_for_scatter) ggplot(jabar |> st_drop_geometry(), aes(x = .data[[x]], y = KEMISKINAN)) + geom_point(size = input$pointSize, color = col_point) + geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = col_smooth) + labs(title = paste("KEMISKINAN vs", var_labels[[x]]), x = var_labels[[x]], y = "KEMISKINAN") + theme_minimal(base_size = 12, base_family = "Poppins") }) output$download_plots <- downloadHandler( filename = function() "deskriptif_plots.png", content = function(file) { v <- isolate(input$var_desc); x <- isolate(input$x_for_scatter) xv <- jabar[[v]] lims <- stats_limits(xv) brks <- pretty(lims, n = isolate(input$bins)) p1 <- ggplot(jabar, aes(x = .data[[v]])) + geom_histogram(breaks = brks, color = col_outline, fill = col_hist, closed = "right") + scale_x_continuous(limits = lims, breaks = brks, expand = expansion(mult = 0.02)) + labs(title = paste("Histogram", var_labels[[v]]), x = paste0(var_labels[[v]]), y = "Frekuensi") + theme_minimal(base_size = 12, base_family = "Poppins") p2 <- ggplot(jabar, aes(y = .data[[v]])) + geom_boxplot(fill = col_box, color = col_outline) + labs(title = paste("Boxplot", var_labels[[v]]), y = var_labels[[v]], x = "") + theme_minimal(base_size = 12, base_family = "Poppins") p3 <- ggplot(jabar |> st_drop_geometry(), aes(x = .data[[x]], y = KEMISKINAN)) + geom_point(size = isolate(input$pointSize), color = col_point) + geom_smooth(method = "lm", se = FALSE, linetype = "dashed", color = col_smooth) + labs(title = paste("KEMISKINAN vs", var_labels[[x]]), x = var_labels[[x]], y = "KEMISKINAN") + theme_minimal(base_size = 12, base_family = "Poppins") g <- gridExtra::arrangeGrob(p1, p2, p3, ncol = 2) ggsave(file, g, width = 12, height = 8, dpi = 300) } ) # ---------- PETA pal_fun <- function(x) colorNumeric("viridis", domain = x) render_leaflet_map <- function(varname) { x <- jabar[[varname]] pal <- pal_fun(x); cols <- pal(x) labels <- sprintf( "<b>%s</b><br/>%s: %s", jabar$kabupaten, var_labels[[varname]], format(round(x, 3), nsmall = 3) ) |> lapply(HTML) leaflet(jabar) %>% addProviderTiles(providers$CartoDB.Positron) %>% addPolygons( fillColor = cols, color = "white", weight = 1, fillOpacity = 0.85, label = labels, labelOptions = labelOptions(direction = "auto"), highlightOptions = highlightOptions(weight = 2, bringToFront = TRUE) ) %>% addLegend("bottomright", pal = pal, values = x, title = var_labels[[varname]]) } output$map_left <- renderLeaflet({ render_leaflet_map(req(input$var_map_left)) }) output$map_right <- renderLeaflet({ render_leaflet_map(req(input$var_map_right)) }) make_static_choropleth <- function(varname) { ggplot(jabar) + geom_sf(aes(fill = .data[[varname]]), color = "white", size = 0.25) + scale_fill_viridis_c(name = var_labels[[varname]], option = "C", direction = -1) + labs(title = paste("Peta", var_labels[[varname]])) + theme_minimal(base_size = 12, base_family = "Poppins") + theme(axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) } output$dl_map_left_png <- downloadHandler( filename = function() sprintf("peta_kiri_%s.png", input$var_map_left), content = function(file) { p <- make_static_choropleth(isolate(input$var_map_left)) ggsave(file, p, width = 7, height = 6, dpi = 300) } ) output$dl_map_right_png <- downloadHandler( filename = function() sprintf("peta_kanan_%s.png", input$var_map_right), content = function(file) { p <- make_static_choropleth(isolate(input$var_map_right)) ggsave(file, p, width = 7, height = 6, dpi = 300) } ) # ---------- AUTOKORELASI output$auto_table <- renderDT({ v <- req(input$var_auto) if (input$auto_method == "Moran's I") { res <- safe_moran_both_raw(jabar[[v]], nb_queen) Moran_I <- unname(res$mt$estimate[["Moran I statistic"]]) Expected_I <- unname(res$mt$estimate[["Expectation"]]) Z_value <- unname(res$mt$statistic) P_perm <- res$mmc$p.value tab <- tibble::tibble( `Moran's I` = Moran_I, `Expected I` = Expected_I, `Z-value` = Z_value, `p-value Uji Permutasi` = P_perm, `Keputusan` = ifelse(P_perm < 0.05, "Signifikan", "Tidak signifikan") ) %>% round3_df() DT::datatable(tab, options = list(dom = 't')) } else if (input$auto_method == "Geary's C") { res <- safe_geary_both_raw(jabar[[v]], nb_queen) estC <- res$gt$estimate[["Geary C statistic"]]; if (is.null(estC)) estC <- res$gt$estimate[["Geary's C"]] Expected_C <- unname(res$gt$estimate[["Expectation"]]) Z_value <- unname(res$gt$statistic) P_perm <- res$gmc$p.value tab <- tibble::tibble( `Geary's C` = unname(estC), `Expected C` = Expected_C, `Z-value` = Z_value, `p-value Uji Permutasi` = P_perm, `Keputusan` = ifelse(P_perm < 0.05, "Signifikan", "Tidak signifikan") ) %>% round3_df() DT::datatable(tab, options = list(dom = 't')) } else if (input$auto_method == "LISA") { lis <- compute_lisa(jabar[[v]], nb_queen) sf_sub <- jabar sf_sub$LISA_cat <- factor("Not Significant", levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) sf_sub$LISA_cat[lis$ok] <- factor(lis$cluster, levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) tab <- sf_sub |> st_drop_geometry() |> transmute( Kabupaten = kabupaten, Kategori = as.character(LISA_cat) ) keep <- input$lisa_filter if (!is.null(keep)) tab <- tab %>% filter(Kategori %in% keep) DT::datatable(tab, options = list(pageLength = 15)) } else { # Getis-Ord G* gs <- compute_gistar(jabar[[v]], nb_queen) tab <- jabar |> st_drop_geometry() |> transmute( Kabupaten = kabupaten, `Z(G*)` = round(gs$z, 3), Kategori = as.character(gs$cat) ) keep <- input$gstar_filter if (!is.null(keep)) tab <- tab %>% filter(Kategori %in% keep) DT::datatable(tab, options = list(pageLength = 15)) } }) build_auto_leaflet <- function(method, v) { if (method == "LISA") { lis <- compute_lisa(jabar[[v]], nb_queen) sf_sub <- jabar sf_sub$LISA_cat <- factor("Not Significant", levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) sf_sub$LISA_cat[lis$ok] <- factor(lis$cluster, levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) # Warna LISA tegas (non-pastel) cols_lisa <- c("High-High"="#E53935","Low-Low"="#1E88E5","High-Low"="#FB8C00","Low-High"="#43A047","Not Significant"="#B0BEC5") pal <- colorFactor(cols_lisa, levels = names(cols_lisa)) labels <- sprintf("<b>%s</b><br/>Kategori: %s", sf_sub$kabupaten, as.character(sf_sub$LISA_cat)) |> lapply(HTML) leaflet(sf_sub) %>% addProviderTiles(providers$CartoDB.Positron) %>% addPolygons(fillColor = pal(sf_sub$LISA_cat), color="white", weight=1, fillOpacity=0.85, label=labels, labelOptions = labelOptions(direction="auto"), highlightOptions = highlightOptions(weight = 2, bringToFront=TRUE)) %>% addLegend("bottomright", pal = pal, values = sf_sub$LISA_cat, title = "LISA") } else if (method == "Getis-Ord G*") { gs <- compute_gistar(jabar[[v]], nb_queen) sf_g <- jabar %>% mutate(GSTAR = gs$cat, z_g = gs$z) cols_g <- c("Hot spot"="#E53935","Cold spot"="#1E88E5","Not significant"="#CFD8DC") pal <- colorFactor(cols_g, levels = names(cols_g)) labels <- sprintf("<b>%s</b><br/>Kategori: %s<br/>Z(G*): %s", sf_g$kabupaten, as.character(sf_g$GSTAR), format(round(sf_g$z_g,3), nsmall=3)) |> lapply(HTML) leaflet(sf_g) %>% addProviderTiles(providers$CartoDB.Positron) %>% addPolygons(fillColor = pal(sf_g$GSTAR), color="white", weight=1, fillOpacity=0.85, label=labels, labelOptions = labelOptions(direction="auto"), highlightOptions = highlightOptions(weight=2, bringToFront=TRUE)) %>% addLegend("bottomright", pal = pal, values = sf_g$GSTAR, title = "Getis–Ord G*") } else if (method == "Moran's I") { res <- safe_moran_both_raw(jabar[[v]], nb_queen) Moran_I <- round(unname(res$mt$estimate[["Moran I statistic"]]), 3) P_perm <- round(res$mmc$p.value, 3) x <- jabar[[v]] pal <- colorNumeric("viridis", domain = x) labels <- sprintf("<b>%s</b><br/>%s: %s<br/>Moran's I: %s<br/>p (perm): %s", jabar$kabupaten, var_labels[[v]], format(round(x,3), nsmall=3), Moran_I, P_perm) |> lapply(HTML) leaflet(jabar) %>% addProviderTiles(providers$CartoDB.Positron) %>% addPolygons(fillColor = pal(x), color="white", weight=1, fillOpacity=0.85, label=labels, labelOptions = labelOptions(direction="auto"), highlightOptions = highlightOptions(weight=2, bringToFront=TRUE)) %>% addLegend("bottomright", pal = pal, values = x, title = var_labels[[v]]) } else { # Geary # ==================================================================== # === PERBAIKAN BUG ADA DI SINI === # ==================================================================== res <- safe_geary_both_raw(jabar[[v]], nb_queen) # MENGGUNAKAN NAMA YANG BENAR: "Geary C statistic" (tanpa 'R' dan tanpa apostrof) Geary_C <- round(unname(res$gt$estimate[["Geary C statistic"]]), 3) # Baris 'if (is.na...)' tidak diperlukan lagi karena nama di atas sudah benar # if (is.na(Geary_C)) Geary_C <- round(unname(res$gt$estimate[["Geary's C"]]), 3) # ==================================================================== P_perm <- round(res$gmc$p.value, 3) x <- jabar[[v]] pal <- colorNumeric("viridis", domain = x) labels <- sprintf("<b>%s</b><br/>%s: %s<br/>Geary's C: %s<br/>p (perm): %s", jabar$kabupaten, var_labels[[v]], format(round(x,3), nsmall=3), Geary_C, P_perm) |> lapply(HTML) leaflet(jabar) %>% addProviderTiles(providers$CartoDB.Positron) %>% addPolygons(fillColor = pal(x), color="white", weight=1, fillOpacity=0.85, label=labels, labelOptions = labelOptions(direction="auto"), highlightOptions = highlightOptions(weight=2, bringToFront=TRUE)) %>% addLegend("bottomright", pal = pal, values = x, title = var_labels[[v]]) } } output$auto_map <- renderLeaflet({ build_auto_leaflet(input$auto_method, req(input$var_auto)) }) make_static_auto_plot <- function(method, v) { if (method == "LISA") { lis <- compute_lisa(jabar[[v]], nb_queen) sf_sub <- jabar sf_sub$LISA_cat <- factor("Not Significant", levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) sf_sub$LISA_cat[lis$ok] <- factor(lis$cluster, levels = c("High-High","Low-Low","High-Low","Low-High","Not Significant")) cols_lisa <- c("High-High"="#E53935","Low-Low"="#1E88E5","High-Low"="#FB8C00","Low-High"="#43A047","Not Significant"="#B0BEC5") ggplot(sf_sub) + geom_sf(aes(fill = LISA_cat), color = "white", size = 0.25) + scale_fill_manual(values = cols_lisa, drop = FALSE, name = "Kategori") + labs(title = paste("LISA —", var_labels[[v]])) + theme_minimal(base_size = 12, base_family = "Poppins") + theme(axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) } else if (method == "Getis-Ord G*") { gs <- compute_gistar(jabar[[v]], nb_queen) sf_g <- jabar %>% mutate(GSTAR = gs$cat) cols_g <- c("Hot spot"="#E53935","Cold spot"="#1E88E5","Not significant"="#CFD8DC") ggplot(sf_g) + geom_sf(aes(fill = GSTAR), color = "white", size = 0.25) + scale_fill_manual(values = cols_g, drop = FALSE, name = "Kategori") + labs(title = paste("Getis–Ord G* —", var_labels[[v]])) + theme_minimal(base_size = 12, base_family = "Poppins") + theme(axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) } else if (method == "Moran's I") { ggplot(jabar) + geom_sf(aes(fill = .data[[v]]), color = "white", size = 0.25) + scale_fill_viridis_c(name = var_labels[[v]], option = "C", direction = -1) + labs(title = paste("Moran's I —", var_labels[[v]])) + theme_minimal(base_size = 12, base_family = "Poppins") + theme(axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) } else { ggplot(jabar) + geom_sf(aes(fill = .data[[v]]), color = "white", size = 0.25) + scale_fill_viridis_c(name = var_labels[[v]], option = "C", direction = -1) + labs(title = paste("Geary's C —", var_labels[[v]])) + theme_minimal(base_size = 12, base_family = "Poppins") + theme(axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) } } output$dl_auto_map_png <- downloadHandler( filename = function() sprintf("autokorelasi_%s_%s.png", input$auto_method, input$var_auto), content = function(file) { p <- make_static_auto_plot(isolate(input$auto_method), isolate(input$var_auto)) ggsave(file, p, width = 7.2, height = 6.2, dpi = 300) } ) # ---------- PEMODELAN current_w <- reactive({ switch(input$w_choice, "Queen" = lw_queen, "Rook" = lw_rook, "KNN-4" = lw_knn4 ) }) models_reactive <- eventReactive(input$fit_btn, { y <- req(input$y_model); x <- req(input$x_model) validate(need(length(x) >= 1, "Pilih minimal satu X")) fit_models(jabar, y, x, current_w()) }, ignoreInit = TRUE) output$model_table <- renderDT({ req(models_reactive()) yv <- jabar[[input$y_model]] df <- model_stats(models_reactive(), yv) rng_aic <- range(df$AIC, na.rm = TRUE) rng_ll <- range(df$`Log-Likelihood`, na.rm = TRUE) rng_r2 <- range(df$`R²`, na.rm = TRUE) df_render <- df %>% transmute( Model, `Log-Likelihood (bar)` = vapply(`Log-Likelihood`, bar_cell, character(1), minv = rng_ll[1], maxv = rng_ll[2], color = "#2e7d32", txt_color = "#fdfaf6"), `Log-Likelihood_num` = `Log-Likelihood`, `AIC (bar)` = vapply(AIC, bar_cell, character(1), minv = rng_aic[1], maxv = rng_aic[2], color = "#b05d39", txt_color = "#fdfaf6"), AIC_num = AIC, `R² (bar)` = vapply(`R²`, bar_cell, character(1), minv = rng_r2[1], maxv = rng_r2[2], color = "#f2a900", txt_color = "#3e2723"), R2_num = `R²` ) DT::datatable( df_render, escape = FALSE, rownames = FALSE, options = list( pageLength = 8, dom = 'tip', columnDefs = list( list(targets = 1, orderData = 2), # sort LL by hidden numeric list(visible = FALSE, targets = 2), list(targets = 3, orderData = 4), # sort AIC by hidden numeric list(visible = FALSE, targets = 4), list(targets = 5, orderData = 6), # sort R2 by hidden numeric list(visible = FALSE, targets = 6) ) ) ) }) output$best_model_cards <- renderUI({ req(models_reactive()) yv <- jabar[[input$y_model]] df <- model_stats(models_reactive(), yv) best_aic <- df$Model[which.min(df$AIC)] best_r2 <- df$Model[which.max(df$`R²`)] best_ll <- df$Model[which.max(df$`Log-Likelihood`)] tagList( tags$b(sprintf("Model dengan AIC terendah: %s", best_aic)), tags$br(), tags$b(sprintf("Model dengan R² tertinggi: %s", best_r2)), tags$br(), tags$b(sprintf("Model dengan Log-Likelihood tertinggi: %s", best_ll)) ) }) pred_resid_from_model <- reactive({ req(models_reactive()) mods <- models_reactive() mdl <- switch(input$model_pred, "SAR" = mods$sar, "SDM" = mods$sdm, "SAC/SARAR" = mods$sac, "GNS" = mods$gns, "SLX" = mods$slx, "SEM" = mods$sem, "SDEM" = mods$sdem ) data.frame( yhat = as.numeric(fitted(mdl)), resid = as.numeric(residuals(mdl)) ) }) build_resid_leaflet <- reactive({ df <- req(pred_resid_from_model()) jabar_res <- jabar %>% mutate( y_hat = round(df$yhat, 3), z_resid = round(as.numeric(scale(df$resid)), 3) ) rng <- range(jabar_res$z_resid, na.rm = TRUE) lim <- max(abs(rng)) pal_res <- colorNumeric(c("#1E88E5","white","#E53935"), domain = c(-lim, lim)) labels <- sprintf( "<b>%s</b><br/>Prediksi: %.3f<br/>Aktual: %.3f<br/>Residual (z): %.3f", jabar_res$kabupaten, jabar_res$y_hat, jabar_res$KEMISKINAN, jabar_res$z_resid ) |> lapply(HTML) leaflet(jabar_res) %>% addProviderTiles(providers$CartoDB.Positron) %>% addPolygons( fillColor = pal_res(jabar_res$z_resid), color = "white", weight = 1, fillOpacity = 0.85, label = labels, labelOptions = labelOptions(direction="auto"), highlightOptions = highlightOptions(weight = 2, bringToFront = TRUE) ) %>% addLegend("bottomright", colors = c("#1E88E5","white","#E53935"), labels = c("Negatif besar", "0", "Positif besar"), title = "Residual (z)") }) output$resid_leaf <- renderLeaflet({ build_resid_leaflet() }) make_static_resid_plot <- function() { df <- req(pred_resid_from_model()) sfp <- jabar %>% mutate(z_resid = round(as.numeric(scale(df$resid)), 3)) lim_res <- max(abs(sfp$z_resid), na.rm = TRUE) ggplot(sfp) + geom_sf(aes(fill = z_resid), color = "white", size = 0.25) + scale_fill_gradient2(low = "#1E88E5", mid = "white", high = "#E53935", midpoint = 0, limits = c(-lim_res, lim_res), oob = scales::squish, name = "Residual (z)") + labs(title = paste("Peta Residual —", input$model_pred)) + theme_minimal(base_size = 12, base_family = "Poppins") + theme(axis.title = element_blank(), axis.text = element_blank(), panel.grid = element_blank()) } output$dl_resid_map_png <- downloadHandler( filename = function() sprintf("peta_residual_%s.png", input$model_pred), content = function(file) { p <- make_static_resid_plot() ggsave(file, p, width = 7.2, height = 6.2, dpi = 300) } ) # ---------- SENSITIVITAS W output$sens_table <- renderDT({ y <- req(input$y_model); x <- req(input$x_model) validate(need(length(x) >= 1, "Pilih minimal satu X lalu klik Fit.")) fml <- as.formula(paste(y, "~", paste(x, collapse = " + "))) mQ <- lagsarlm(fml, data = jabar, listw = lw_queen, method = "eigen", zero.policy = TRUE) mR <- lagsarlm(fml, data = jabar, listw = lw_rook, method = "eigen", zero.policy = TRUE) mK <- lagsarlm(fml, data = jabar, listw = lw_knn4, method = "eigen", zero.policy = TRUE) tab <- data.frame( Bobot = c("Queen","Rook","KNN-4"), Rho = round(c(mQ$rho, mR$rho, mK$rho), 3), AIC = round(c(AIC(mQ), AIC(mR), AIC(mK)), 3), `Log-Likelihood` = round(c(as.numeric(logLik(mQ)), as.numeric(logLik(mR)), as.numeric(logLik(mK))), 3) ) DT::datatable(tab, rownames = FALSE, options = list(pageLength = 5)) }) output$sens_bar <- renderPlot({ y <- req(input$y_model); x <- req(input$x_model) validate(need(length(x) >= 1, "Pilih minimal satu X lalu klik Fit.")) fml <- as.formula(paste(y, "~", paste(x, collapse = " + "))) mQ <- lagsarlm(fml, data = jabar, listw = lw_queen, method = "eigen", zero.policy = TRUE) mR <- lagsarlm(fml, data = jabar, listw = lw_rook, method = "eigen", zero.policy = TRUE) mK <- lagsarlm(fml, data = jabar, listw = lw_knn4, method = "eigen", zero.policy = TRUE) df <- data.frame( Bobot = factor(c("Queen","Rook","KNN-4"), levels = c("Queen","Rook","KNN-4")), Rho = c(mQ$rho, mR$rho, mK$rho), AIC = c(AIC(mQ), AIC(mR), AIC(mK)) ) pAIC <- ggplot(df, aes(x = Bobot, y = AIC)) + geom_col(width = 0.6, fill = "#b05d39") + labs(title = "AIC per Bobot W") + theme_minimal(base_size = 12, base_family = "Poppins") pRho <- ggplot(df, aes(x = Bobot, y = Rho)) + geom_col(width = 0.6, fill = "#43A047") + labs(title = "Rho (ρ) per Bobot W") + theme_minimal(base_size = 12, base_family = "Poppins") gridExtra::grid.arrange(pAIC, pRho, ncol = 2) }) output$dl_sens_bar <- downloadHandler( filename = function() "sensitivitas_W.png", content = function(file) { y <- isolate(input$y_model); x <- isolate(input$x_model) fml <- as.formula(paste(y, "~", paste(x, collapse = " + "))) mQ <- lagsarlm(fml, data = jabar, listw = lw_queen, method = "eigen", zero.policy = TRUE) mR <- lagsarlm(fml, data = jabar, listw = lw_rook, method = "eigen", zero.policy = TRUE) mK <- lagsarlm(fml, data = jabar, listw = lw_knn4, method = "eigen", zero.policy = TRUE) df <- data.frame( Bobot = factor(c("Queen","Rook","KNN-4"), levels = c("Queen","Rook","KNN-4")), Rho = c(mQ$rho, mR$rho, mK$rho), AIC = c(AIC(mQ), AIC(mR), AIC(mK)) ) pAIC <- ggplot(df, aes(x = Bobot, y = AIC)) + geom_col(width = 0.6, fill = "#b05d39") + labs(title = "AIC per Bobot W") + theme_minimal(base_size = 12, base_family = "Poppins") pRho <- ggplot(df, aes(x = Bobot, y = Rho)) + geom_col(width = 0.6, fill = "#43A047") + labs(title = "Rho (ρ) per Bobot W") + theme_minimal(base_size = 12, base_family = "Poppins") g <- gridExtra::arrangeGrob(pAIC, pRho, ncol = 2) ggsave(file, g, width = 10, height = 5.5, dpi = 300) } )}# =========================================================# RUN# =========================================================shinyApp(ui, server) \]