Disclaimer: Modul pembelajaran ini disusun dengan menyintesis berbagai sumber literatur ilmiah yang tercantum pada bagian referensi. Dalam proses pengerjaannya, teknologi kecerdasan buatan (Artificial Intelligence/AI) digunakan sebagai alat bantu untuk meringkas, menyatukan informasi dari beberapa sumber sekaligus, serta menyusun draf sintaks pemrograman. Kendati demikian, seluruh isi, logika pemodelan, dan kode pemrograman di dalam modul ini telah melalui proses pengecekan, pengujian, serta validasi secara mandiri oleh penyusun sebelum diterbitkan.
Dalam analisis spasial, kita sering berasumsi bahwa hubungan antarvariabel bersifat stasioner — yaitu konstan di seluruh wilayah studi. Regresi Kuadrat Terkecil Biasa (Ordinary Least Squares/OLS) mengikuti asumsi ini dengan menghasilkan satu set koefisien global yang mewakili rata-rata hubungan di seluruh area.
Namun, kenyataan geografis menunjukkan hal berbeda. Tobler (1970) menyatakan dalam Hukum Pertama Geografi: “Everything is related to everything else, but near things are more related than distant things.” Prinsip ini menyiratkan bahwa hubungan antarvariabel dapat berbeda-beda bergantung pada lokasi.
Sebagai contoh:
Pengaruh pendapatan terhadap harga rumah mungkin lebih kuat di pusat kota daripada di pinggiran.
Pengaruh kemiskinan terhadap angka kriminalitas mungkin berbeda antara wilayah perkotaan dan perdesaan.
Pengaruh elevasi terhadap curah hujan bervariasi di setiap wilayah topografi.
Fenomena ini disebut non-stasioneritas spasial atau heterogenitas spasial dalam hubungan antar-variabel.
Geographically Weighted Regression (GWR) adalah teknik regresi yang memungkinkan koefisien regresi bervariasi secara spasial. GWR dikembangkan oleh Brunsdon, Fotheringham, dan Charlton (1996) sebagai ekstensi lokal dari model regresi global.
Alih-alih menghasilkan satu set koefisien global, GWR menghasilkan satu set koefisien unik untuk setiap lokasi dalam dataset. Estimasi dilakukan dengan memberikan bobot lebih besar pada pengamatan yang lebih dekat secara geografis dengan lokasi yang sedang diestimasi, mirip dengan prinsip kernel density estimation.
GWR tepat digunakan ketika:
| Kondisi | Indikator |
|---|---|
| Dugaan non-stasioneritas spasial | Ada alasan teoritis mengapa hubungan antar-variabel bervariasi antar-lokasi |
| Residual OLS berautokorelasi spasial | Moran’s I dari residual OLS signifikan |
| Heterogenitas spasial terdeteksi | Uji Breusch-Pagan atau Koenker-Bassett signifikan |
| Tujuan eksplorasi spasial | Ingin memetakan di mana suatu variabel memiliki pengaruh positif vs. negatif |
| Data bersifat agregat spasial | Data pada level wilayah (kecamatan, kabupaten, dll.) |
GWR kurang tepat digunakan ketika: - Data tidak memiliki komponen spasial yang bermakna - Jumlah pengamatan sangat sedikit (n < 50) - Tujuan utama adalah prediksi bukan eksplorasi (GWR cenderung overfitting) - Multikolinieritas lokal sangat tinggi
| Aspek | OLS (Regresi Global) | GWR (Regresi Lokal) |
|---|---|---|
| Koefisien | Satu nilai untuk seluruh wilayah | Berbeda di setiap lokasi |
| Asumsi | Stasioneritas spasial | Non-stasioneritas diperbolehkan |
| Output | Tabel koefisien | Peta koefisien lokal |
| Interpretasi | Rata-rata pengaruh global | Pengaruh yang bervariasi secara spasial |
| Kompleksitas | Sederhana | Lebih kompleks |
| Overfitting | Rendah | Perlu kehati-hatian |
Model regresi OLS standar:
\[y_i = \beta_0 + \sum_{k=1}^{p} \beta_k x_{ik} + \varepsilon_i\]
di mana \(\beta_0, \beta_1, \ldots, \beta_p\) adalah koefisien global (sama untuk semua \(i\)), dan \(\varepsilon_i \sim N(0, \sigma^2)\).
Estimasi OLS: \(\hat{\boldsymbol{\beta}} = (\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^T\mathbf{y}\)
Model GWR memperluas OLS dengan membiarkan koefisien bervariasi secara spasial:
\[y_i = \beta_0(u_i, v_i) + \sum_{k=1}^{p} \beta_k(u_i, v_i)\, x_{ik} + \varepsilon_i\]
di mana \((u_i, v_i)\) adalah koordinat geografis lokasi ke-\(i\), dan \(\beta_k(u_i, v_i)\) adalah koefisien lokal yang bergantung pada lokasi.
Koefisien GWR diestimasi dengan Weighted Least Squares (WLS) secara terpisah untuk setiap lokasi:
\[\hat{\boldsymbol{\beta}}(u_i, v_i) = \left[\mathbf{X}^T \mathbf{W}(u_i, v_i)\, \mathbf{X}\right]^{-1} \mathbf{X}^T \mathbf{W}(u_i, v_i)\, \mathbf{y}\]
di mana \(\mathbf{W}(u_i, v_i)\) adalah matriks bobot diagonal \(n \times n\):
\[\mathbf{W}(u_i, v_i) = \mathrm{diag}\left[w_{i1},\, w_{i2},\, \ldots,\, w_{in}\right]\]
Bobot \(w_{ij}\) mencerminkan kedekatan spasial antara lokasi ke-\(i\) (lokasi yang sedang diestimasi) dan lokasi ke-\(j\) (pengamatan yang digunakan sebagai data). Pengamatan yang lebih dekat mendapat bobot lebih besar.
Fungsi kernel menentukan bagaimana bobot menurun seiring bertambahnya jarak \(d_{ij}\) dari titik estimasi.
a. Gaussian (kontinu, batas tak terhingga): \[w_{ij} = \exp\!\left(-\frac{d_{ij}^2}{2h^2}\right)\]
b. Exponential (kontinu, batas tak terhingga): \[w_{ij} = \exp\!\left(-\frac{d_{ij}}{h}\right)\]
c. Bisquare (diskontinu, batas terhingga — compact support): \[w_{ij} = \begin{cases} \left[1 - \left(\dfrac{d_{ij}}{h}\right)^2\right]^2 & \text{jika } d_{ij} \leq h \\ 0 & \text{jika } d_{ij} > h \end{cases}\]
d. Tricube (diskontinu, compact support): \[w_{ij} = \begin{cases} \left[1 - \left(\dfrac{d_{ij}}{h}\right)^3\right]^3 & \text{jika } d_{ij} \leq h \\ 0 & \text{jika } d_{ij} > h \end{cases}\]
e. Boxcar (semua pengamatan dalam radius mendapat bobot sama): \[w_{ij} = \begin{cases} 1 & \text{jika } d_{ij} \leq h \\ 0 & \text{jika } d_{ij} > h \end{cases}\]
Catatan: Kernel bisquare dan tricube memiliki compact support — pengamatan di luar bandwidth mendapat bobot nol. Ini membuat komputasi lebih efisien. Kernel Gaussian dan exponential secara teoritis menggunakan semua pengamatan, tetapi pengamatan jauh hampir tidak berpengaruh.
Ada dua jenis bandwidth \(h\):
a. Fixed bandwidth (bandwidth tetap):
Jari-jari pencarian konstan dalam satuan jarak (km, meter). Cocok ketika
data terdistribusi merata secara spasial. Kelemahan: di daerah data
padat, banyak pengamatan digunakan; di daerah jarang, sedikit pengamatan
tersedia.
b. Adaptive bandwidth (bandwidth adaptif):
Jumlah tetangga (k nearest neighbors) konstan di setiap lokasi.
Bandwidth (jarak) menyesuaikan kepadatan data. Di daerah padat,
bandwidth sempit; di daerah jarang, bandwidth lebar.
AICc (Corrected Akaike Information Criterion): \[\text{AICc} = 2n\ln(\hat{\sigma}) + n\ln(2\pi) + n\left(\frac{n + \mathrm{tr}(\mathbf{H})}{n - 2 - \mathrm{tr}(\mathbf{H})}\right)\]
R² Lokal: Mengukur kecocokan model di setiap
lokasi.
R² Global GWR: Rata-rata tertimbang R² lokal.
# Instalasi paket (jalankan sekali saja)
install.packages(c(
"GWmodel", # GWR utama
"sf", # simple features (data spasial modern)
"spdep", # uji dependensi spasial
"tmap", # visualisasi peta tematik
"ggplot2", # visualisasi umum
"tidyverse", # manipulasi data
"car", # uji regresi (VIF, dll.)
"lmtest", # uji diagnostik regresi
"RColorBrewer"# palet warna
))
# Memuat paket
library(GWmodel)
library(sf)
library(spdep)
library(tmap)
library(ggplot2)
library(tidyverse)
library(car)
library(lmtest)
library(RColorBrewer)
# Pengaturan tampilan peta
tmap_mode("plot")
Dataset yang digunakan adalah Georgia, yang tersedia
langsung dalam paket GWmodel. Dataset ini berisi data
tingkat kabupaten (county) untuk negara bagian Georgia, Amerika
Serikat, tahun 1990 (n = 159 kabupaten).
# Memuat data Georgia dari paket GWmodel
data(Georgia) #akan tersimpan sebagai Gedu.df
Georgia<-Gedu.df
# Melihat kelas objek
class(Georgia)
## [1] "data.frame"
# Melihat nama variabel
names(Georgia)
## [1] "AreaKey" "Latitude" "Longitud" "TotPop90" "PctRural" "PctBach"
## [7] "PctEld" "PctFB" "PctPov" "PctBlack" "ID" "X"
## [13] "Y"
Keterangan variabel:
| Variabel | Deskripsi |
|---|---|
| AreaKey | Nomor identifikasi untuk setiap county (kabupaten/wilayah administratif) |
| Latitude | Garis lintang (latitude) titik pusat geografis county |
| Longitud | Garis bujur (longitude) titik pusat geografis county |
| TotPop90 | Jumlah penduduk county pada tahun 1990 |
| PctRural | Persentase penduduk county yang dikategorikan sebagai penduduk pedesaan (%) |
| PctBach | Persentase penduduk county yang memiliki gelar sarjana (%) |
| PctEld | Persentase penduduk county yang berusia 65 tahun atau lebih (%) |
| PctFB | Persentase penduduk county yang lahir di luar Amerika Serikat (%) |
| PctPov | Persentase penduduk county yang hidup di bawah garis kemiskinan (%) |
| PctBlack | Persentase penduduk county yang merupakan kelompok ras kulit hitam (%) |
Variabel respons: PctBach (Persentase
gelar sarjana)
Variabel prediktor: PctFB,
PctPov, PctBlack, PctEld
Pertanyaan penelitian: Apakah faktor-faktor sosial ekonomi (kemiskinan, komposisi etnis, imigran, proporsi lansia) memengaruhi persentase penduduk berpendidikan sarjana, dan apakah pengaruh ini bervariasi secara spasial?
# Konversi SpatialPolygonsDataFrame ke sf
georgia_sf <- st_as_sf(Georgia,coords = c("X", "Y"))
# Lihat struktur data
str(georgia_sf, max.level = 2)
## Classes 'sf' and 'data.frame': 159 obs. of 12 variables:
## $ AreaKey : int 13001 13003 13005 13007 13009 13011 13013 13015 13017 13019 ...
## $ Latitude: num 31.8 31.3 31.6 31.3 33.1 ...
## $ Longitud: num -82.3 -82.9 -82.5 -84.5 -83.3 ...
## $ TotPop90: int 15744 6213 9566 3615 39530 10308 29721 55911 16245 14153 ...
## $ PctRural: num 75.6 100 61.7 100 42.7 100 64.6 75.2 47 66.2 ...
## $ PctBach : num 8.2 6.4 6.6 9.4 13.3 6.4 9.2 9 7.6 7.5 ...
## $ PctEld : num 11.43 11.77 11.11 13.17 8.64 ...
## $ PctFB : num 0.64 1.58 0.27 0.11 1.43 0.34 0.92 0.82 0.33 1.19 ...
## $ PctPov : num 19.9 26 24.1 24.8 17.5 15.1 14.7 10.7 22 19.3 ...
## $ PctBlack: num 20.8 26.9 15.4 51.7 42.4 ...
## $ ID : int 133 158 146 155 79 23 33 24 138 153 ...
## $ geometry:sfc_POINT of length 159; first list element: 'XY' num 941397 3521764
## - attr(*, "sf_column")= chr "geometry"
## - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA NA NA NA NA ...
## ..- attr(*, "names")= chr [1:11] "AreaKey" "Latitude" "Longitud" "TotPop90" ...
# Lihat beberapa baris pertama
head(georgia_sf[, c("PctBach", "PctFB", "PctPov","PctBlack", "PctEld")], 10)
## Simple feature collection with 10 features and 5 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 699011.5 ymin: 3466377 xmax: 941396.6 ymax: 3807616
## CRS: NA
## PctBach PctFB PctPov PctBlack PctEld geometry
## 1 8.2 0.64 19.9 20.76 11.43 POINT (941396.6 3521764)
## 2 6.4 1.58 26.0 26.86 11.77 POINT (895553 3471916)
## 3 6.6 0.27 24.1 15.42 11.11 POINT (930946.4 3502787)
## 4 9.4 0.11 24.8 51.67 13.17 POINT (745398.6 3474765)
## 5 13.3 1.43 17.5 42.39 8.64 POINT (849431.3 3665553)
## 6 6.4 0.34 15.1 3.49 11.37 POINT (819317.3 3807616)
## 7 9.2 0.92 14.7 11.44 10.63 POINT (803747.1 3769623)
## 8 9.0 0.82 10.7 9.21 9.66 POINT (699011.5 3793408)
## 9 7.6 0.33 22.0 31.33 12.81 POINT (863020.8 3520432)
## 10 7.5 1.19 19.3 11.62 11.98 POINT (859915.8 3466377)
# Statistik deskriptif variabel utama
vars_interest <- c("PctBach", "PctFB", "PctPov", "PctBlack", "PctEld")
summary(st_drop_geometry(georgia_sf)[, vars_interest])
## PctBach PctFB PctPov PctBlack
## Min. : 4.20 Min. :0.040 Min. : 2.60 Min. : 0.00
## 1st Qu.: 7.60 1st Qu.:0.415 1st Qu.:14.05 1st Qu.:11.75
## Median : 9.40 Median :0.720 Median :18.60 Median :27.64
## Mean :10.95 Mean :1.131 Mean :19.34 Mean :27.39
## 3rd Qu.:12.00 3rd Qu.:1.265 3rd Qu.:24.65 3rd Qu.:40.06
## Max. :37.50 Max. :6.740 Max. :35.90 Max. :79.64
## PctEld
## Min. : 1.46
## 1st Qu.: 9.81
## Median :12.07
## Mean :11.74
## 3rd Qu.:13.70
## Max. :22.96
# Distribusi variabel dengan histogram
georgia_sf %>%
st_drop_geometry() %>%
select(all_of(vars_interest)) %>%
pivot_longer(everything(), names_to = "Variabel", values_to = "Nilai") %>%
ggplot(aes(x = Nilai)) +
geom_histogram(bins = 20, fill = "steelblue", color = "white") +
facet_wrap(~Variabel, scales = "free") +
labs(title = "Distribusi Variabel Utama",
subtitle = "Data Georgia, 1990",
x = "Nilai", y = "Frekuensi") +
theme_bw()
# Matriks korelasi antar variabel
cor_matrix <- cor(st_drop_geometry(georgia_sf)[, vars_interest],
use = "complete.obs")
round(cor_matrix, 3)
## PctBach PctFB PctPov PctBlack PctEld
## PctBach 1.000 0.672 -0.402 -0.109 -0.458
## PctFB 0.672 1.000 -0.329 -0.112 -0.483
## PctPov -0.402 -0.329 1.000 0.736 0.568
## PctBlack -0.109 -0.112 0.736 1.000 0.297
## PctEld -0.458 -0.483 0.568 0.297 1.000
# Visualisasi matriks korelasi
# install.packages("corrplot") # jika belum terinstal
library(corrplot)
corrplot(cor_matrix, method = "color", type = "upper",
tl.cex = 0.8, addCoef.col = "black", number.cex = 0.7,
title = "Matriks Korelasi Variabel Utama",
mar = c(0, 0, 1, 0))
data("GeorgiaCounties") #akan tersimpan sebagai Gedu.counties
georgia_poly <- st_as_sf(Gedu.counties)
# Lihat nama variabel pada kedua data
names(Georgia)
## [1] "AreaKey" "Latitude" "Longitud" "TotPop90" "PctRural" "PctBach"
## [7] "PctEld" "PctFB" "PctPov" "PctBlack" "ID" "X"
## [13] "Y"
names(georgia_poly)
## [1] "AREA" "PERIMETER" "G_UTM_" "G_UTM_ID" "AREANAME" "AREAKEY"
## [7] "X_COORD" "Y_COORD" "geometry"
class(georgia_poly$AREAKEY)
## [1] "factor"
class(Georgia$AreaKey)
## [1] "integer"
georgia_poly <- georgia_poly %>%
mutate(AREAKEY = as.integer(as.character(AREAKEY)))
# Gabungkan atribut Georgia ke poligon
# (umumnya menggunakan AreaKey)
georgia_map <- georgia_poly %>%
left_join(Georgia, by = c("AREAKEY" = "AreaKey"))
# Cek hasil join
summary(georgia_map$PctBach)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.20 7.60 9.40 10.95 12.00 37.50
# Peta kombinasi: Poligon latar belakang abu-abu + tumpukan titik besar (tmap v4)
map_kombinasi <- tm_shape(georgia_map) +
tm_polygons(fill = "grey92", col = "grey70", lwd = 0.4) + # Background peta abu-abu
tm_shape(georgia_sf) +
tm_dots(
fill = "PctBach",
size = 0.6, # Mengunci ukuran titik menjadi lebih besar dan terlihat jelas
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "YlOrRd"),
fill.legend = tm_legend(title = "PctBach (%)", position = tm_pos_out("right"))
) +
tm_title("Georgia: Persentase Penduduk dengan Gelar Sarjana (1990)", size = 0.85) +
tm_compass(position = tm_pos_in("left", "bottom")) +
tm_scalebar(position = tm_pos_in("right", "bottom"))
map_kombinasi
# Buat peta
tm_shape(georgia_map) +
tm_polygons(fill = "PctBach",
fill.scale = tm_scale_intervals(style = "jenks", n = 5,
values = "YlOrRd"),
fill.legend = tm_legend(title = "PctBach (%)"),
col = "grey40",
lwd = 0.4) +
tm_title("Georgia: Persentase Penduduk dengan Gelar Sarjana (1990)") +
tm_compass(position = c("left", "bottom")) +
tm_scalebar(position = c("right", "bottom")
)
# Peta distribusi variabel prediktor
st_crs(georgia_map) <- 26917
tm_shape(georgia_map) +
tm_polygons(fill = "PctFB",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.blues"),
fill.legend = tm_legend(title = "Persentase (%)"),
col = "grey60", lwd = 0.2) +
tm_title("Georgia: Persentase Penduduk Lahir di Luar Amerika Serikat (1990)") +
tm_scalebar(position = c("right", "bottom")) +
tm_compass(position = c("left", "bottom")) +
tm_layout(legend.outside = TRUE, frame = FALSE)
## [plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
tm_shape(georgia_map) +
tm_polygons(fill = "PctPov",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.reds"),
fill.legend = tm_legend(title = "Persentase (%)"),
col = "grey60", lwd = 0.2) +
tm_title("Georgia: Persentase Penduduk di Bawah Garis Kemiskinan (1990)") +
tm_scalebar(position = c("right", "bottom")) +
tm_compass(position = c("left", "bottom")) +
tm_layout(legend.outside = TRUE, frame = FALSE)
## [plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
tm_shape(georgia_map) +
tm_polygons(fill = "PctBlack",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.purples"),
fill.legend = tm_legend(title = "Persentase (%)"),
col = "grey60", lwd = 0.2) +
tm_title("Georgia: Persentase Penduduk Black (1990)") +
tm_scalebar(position = c("right", "bottom")) +
tm_compass(position = c("left", "bottom")) +
tm_layout(legend.outside = TRUE, frame = FALSE)
## [plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
tm_shape(georgia_map) +
tm_polygons(fill = "PctEld",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.greens"),
fill.legend = tm_legend(title = "Persentase (%)"),
col = "grey60", lwd = 0.2) +
tm_title("Georgia: Persentase Penduduk Lansia (≥ 65 Tahun) (1990)") +
tm_scalebar(position = c("right", "bottom")) +
tm_compass(position = c("left", "bottom")) +
tm_layout(legend.outside = TRUE, frame = FALSE)
## [plot mode] fit legend/component: Some legend items or map compoments do not
## fit well, and are therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
# Model OLS (regresi global)
model_ols <- lm(PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sf)
# Ringkasan model
summary(model_ols)
##
## Call:
## lm(formula = PctBach ~ PctFB + PctPov + PctBlack + PctEld, data = georgia_sf)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12.1414 -2.0934 -0.2113 1.6709 19.9212
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.67113 1.63682 7.741 1.22e-12 ***
## PctFB 2.54521 0.29839 8.530 1.29e-14 ***
## PctPov -0.28291 0.07810 -3.622 0.000396 ***
## PctBlack 0.07685 0.02803 2.742 0.006834 **
## PctEld -0.10531 0.13784 -0.764 0.446047
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.013 on 154 degrees of freedom
## Multiple R-squared: 0.5163, Adjusted R-squared: 0.5037
## F-statistic: 41.09 on 4 and 154 DF, p-value: < 2.2e-16
Interpretasi output OLS:
Model OLS menghasilkan satu set koefisien yang berlaku untuk
seluruh 159 kabupaten. Misalnya, koefisien
PctPov menunjukkan rata-rata perubahan PctBach
untuk setiap kenaikan 1% tingkat kemiskinan, diasumsikan
sama di seluruh wilayah Georgia.
# Plot diagnostik residual
par(mfrow = c(2, 2))
plot(model_ols)
par(mfrow = c(1, 1))
# Uji normalitas residual (Shapiro-Wilk)
shapiro.test(residuals(model_ols))
##
## Shapiro-Wilk normality test
##
## data: residuals(model_ols)
## W = 0.90536, p-value = 1.282e-08
# Uji heteroskedastisitas (Breusch-Pagan)
bptest(model_ols)
##
## studentized Breusch-Pagan test
##
## data: model_ols
## BP = 40.41, df = 4, p-value = 3.56e-08
# Variance Inflation Factor (multikolinieritas)
vif(model_ols)
## PctFB PctPov PctBlack PctEld
## 1.334895 3.148163 2.328246 1.769013
Interpretasi VIF: - VIF < 5: Multikolinieritas dapat ditoleransi - VIF 5–10: Multikolinieritas moderat, perlu perhatian - VIF > 10: Multikolinieritas serius
# Simpan residual dan fitted value
georgia_map$resid_ols <- residuals(model_ols)
georgia_map$fitted_ols <- fitted(model_ols)
# Peta residual OLS
tm_shape(georgia_map) +
tm_polygons(
fill = "resid_ols",
fill.scale = tm_scale_intervals(
style = "jenks",
n = 5,
midpoint = 0,
values = "brewer.rd_bu"
),
fill.legend = tm_legend(title = "Residual OLS"),
col = "grey60",
col_alpha = 0.3,
lwd = 0.2
) +
tm_title("Peta Residual Model OLS") +
tm_scalebar(position = c("right", "bottom")) +
tm_compass(position = c("left", "bottom")) +
tm_layout(
legend.outside = TRUE,
frame = FALSE
)
Pertanyaan: Apakah residual tampak tersebar acak, atau ada pola spasial tertentu? Pola spasial dalam residual mengindikasikan bahwa OLS tidak sepenuhnya mampu menangkap efek spasial yang ada.
# Uji Breusch-Pagan (dari paket lmtest)
bp_test <- bptest(model_ols)
print(bp_test)
##
## studentized Breusch-Pagan test
##
## data: model_ols
## BP = 40.41, df = 4, p-value = 3.56e-08
# Uji Koenker-Bassett yang lebih robust
# Menggunakan koordinat sebagai proksi spasial
georgia_coords <- st_coordinates(st_centroid(georgia_sf))
georgia_sf$x_coord <- georgia_coords[, 1]
georgia_sf$y_coord <- georgia_coords[, 2]
# Regresi residual kuadrat pada koordinat
resid_sq <- residuals(model_ols)^2
bp_spatial <- lm(resid_sq ~ x_coord + y_coord, data = georgia_sf)
summary(bp_spatial)
##
## Call:
## lm(formula = resid_sq ~ x_coord + y_coord, data = georgia_sf)
##
## Residuals:
## Min 1Q Median 3Q Max
## -18.17 -14.70 -11.39 -4.09 379.59
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -3.387e+01 1.145e+02 -0.296 0.768
## x_coord 3.358e-06 3.652e-05 0.092 0.927
## y_coord 1.284e-05 2.776e-05 0.463 0.644
##
## Residual standard error: 42.9 on 156 degrees of freedom
## Multiple R-squared: 0.001398, Adjusted R-squared: -0.0114
## F-statistic: 0.1092 on 2 and 156 DF, p-value: 0.8966
Bagian ini merangkum bukti empiris dari analisis di atas untuk memotivasi penggunaan GWR.
# Rangkuman hasil diagnostik OLS
cat("=== DIAGNOSTIK MODEL OLS ===\n\n")
## === DIAGNOSTIK MODEL OLS ===
cat("R-squared OLS:", round(summary(model_ols)$r.squared, 4), "\n")
## R-squared OLS: 0.5163
cat(" Adjusted R-squared:", round(summary(model_ols)$adj.r.squared, 4), "\n\n")
## Adjusted R-squared: 0.5037
cat("Breusch-Pagan Test (Heteroskedastisitas):\n")
## Breusch-Pagan Test (Heteroskedastisitas):
cat(" p-value:", format.pval(bp_spatial$p.value, digits = 4), "\n\n")
## p-value:
Pemilihan fungsi kernel mempengaruhi bagaimana bobot menurun seiring jarak. Tidak ada aturan baku — pemilihan bergantung pada konteks dan pengujian empiris.
| Kernel | Karakteristik | Kapan Digunakan |
|---|---|---|
| Bisquare | Compact support, kurva lonceng terpotong | Default yang direkomendasikan; efisien secara komputasi |
| Gaussian | Semua pengamatan berkontribusi, penurunan halus | Data sangat padat, tidak ada outlier spasial |
| Exponential | Penurunan cepat dari pusat | Efek lokal yang kuat, komponen jarak eksponensial |
| Tricube | Compact support, lebih “rounded” dari bisquare | Alternatif bisquare untuk permukaan yang lebih halus |
| Boxcar | Semua pengamatan dalam radius = bobot sama | Sangat jarang; untuk area yang homogen |
# Perbandingan AICc untuk berbagai kernel (fixed bandwidth)
# Mengkonversi ke SpatialPolygonsDataFrame untuk GWmodel
georgia_sp <- as_Spatial(georgia_sf)
cat("Membandingkan AICc untuk berbagai fungsi kernel...\n")
## Membandingkan AICc untuk berbagai fungsi kernel...
cat("(Proses ini memerlukan beberapa menit)\n\n")
## (Proses ini memerlukan beberapa menit)
# Fungsi untuk menghitung GWR dengan kernel berbeda
compare_kernels <- function(kernel_type) {
bw <- bw.gwr(PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
approach = "AICc",
kernel = kernel_type,
adaptive = TRUE,
longlat = TRUE)
gwr_fit <- gwr.basic(PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
bw = bw,
kernel = kernel_type,
adaptive = TRUE,
longlat = TRUE)
return(list(kernel = kernel_type, bw = bw,
AICc = gwr_fit$GW.diagnostic$AICc,
R2 = gwr_fit$GW.diagnostic$gw.R2))
}
# Jalankan perbandingan (bisa memakan waktu)
# kernels <- c("bisquare", "gaussian", "exponential", "tricube")
# hasil_kernel <- lapply(kernels, compare_kernels)
#
# # Tampilkan hasil
# df_kernel <- data.frame(
# Kernel = sapply(hasil_kernel, `[[`, "kernel"),
# Bandwidth = sapply(hasil_kernel, `[[`, "bw"),
# AICc = sapply(hasil_kernel, `[[`, "AICc"),
# R2 = sapply(hasil_kernel, `[[`, "R2")
# )
# print(df_kernel[order(df_kernel$AICc), ])
# Untuk modul ini, kita gunakan bisquare (default yang direkomendasikan)
cat("Kernel yang dipilih: bisquare (compact support, direkomendasikan)\n")
## Kernel yang dipilih: bisquare (compact support, direkomendasikan)
Rekomendasi Praktis: Untuk sebagian besar kasus, gunakan kernel bisquare dengan adaptive bandwidth sebagai titik awal. Kernel ini efisien secara komputasi dan memberikan hasil yang stabil.
Bandwidth adalah parameter krusial dalam GWR. Bandwidth yang terlalu kecil menghasilkan koefisien yang sangat fluktuatif (overfitting); bandwidth yang terlalu besar mendekati OLS global.
a. Cross-Validation (CV):
Meminimalkan prediksi leave-one-out cross-validation error:
\[CV = \sum_{i=1}^{n} \left[y_i -
\hat{y}_{\neq i}(h)\right]^2\]
b. AICc (direkomendasikan):
Meminimalkan Corrected Akaike Information Criterion yang
menyeimbangkan kecocokan model dan kompleksitas.
# ====================================================
# Pemilihan bandwidth: ADAPTIVE dengan AICc
# ====================================================
cat("Memilih bandwidth adaptif menggunakan AICc...\n")
## Memilih bandwidth adaptif menggunakan AICc...
bw_adaptive_AICc <- bw.gwr(
PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
approach = "AICc", # metode: "AICc" atau "CV"
kernel = "bisquare",
adaptive = TRUE, # adaptive = jumlah tetangga
longlat = TRUE # koordinat geografis (derajat)
)
## Adaptive bandwidth (number of nearest neighbours): 105 AICc value: 873.0522
## Adaptive bandwidth (number of nearest neighbours): 73 AICc value: 872.1205
## Adaptive bandwidth (number of nearest neighbours): 51 AICc value: 877.0335
## Adaptive bandwidth (number of nearest neighbours): 84 AICc value: 871.3051
## Adaptive bandwidth (number of nearest neighbours): 93 AICc value: 871.2177
## Adaptive bandwidth (number of nearest neighbours): 97 AICc value: 871.4947
## Adaptive bandwidth (number of nearest neighbours): 89 AICc value: 871.3171
## Adaptive bandwidth (number of nearest neighbours): 94 AICc value: 871.4239
## Adaptive bandwidth (number of nearest neighbours): 91 AICc value: 871.4916
## Adaptive bandwidth (number of nearest neighbours): 93 AICc value: 871.2177
cat("Bandwidth adaptif optimal (AICc):", bw_adaptive_AICc, "tetangga\n\n")
## Bandwidth adaptif optimal (AICc): 93 tetangga
# ====================================================
# Pemilihan bandwidth: ADAPTIVE dengan CV
# ====================================================
cat("Memilih bandwidth adaptif menggunakan CV...\n")
## Memilih bandwidth adaptif menggunakan CV...
bw_adaptive_CV <- bw.gwr(
PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
approach = "CV",
kernel = "bisquare",
adaptive = TRUE,
longlat = TRUE
)
## Adaptive bandwidth: 105 CV score: 2625.666
## Adaptive bandwidth: 73 CV score: 2697.361
## Adaptive bandwidth: 126 CV score: 2630.578
## Adaptive bandwidth: 93 CV score: 2618.385
## Adaptive bandwidth: 84 CV score: 2642.148
## Adaptive bandwidth: 97 CV score: 2614.047
## Adaptive bandwidth: 101 CV score: 2619.241
## Adaptive bandwidth: 96 CV score: 2616.531
## Adaptive bandwidth: 99 CV score: 2613.08
## Adaptive bandwidth: 99 CV score: 2613.08
cat("Bandwidth adaptif optimal (CV):", bw_adaptive_CV, "tetangga\n\n")
## Bandwidth adaptif optimal (CV): 99 tetangga
# ====================================================
# Pemilihan bandwidth: FIXED dengan AICc
# ====================================================
cat("Memilih bandwidth fixed menggunakan AICc...\n")
## Memilih bandwidth fixed menggunakan AICc...
bw_fixed_AICc <- bw.gwr(
PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
approach = "AICc",
kernel = "bisquare",
adaptive = FALSE, # fixed = dalam satuan jarak
longlat = TRUE
)
## Fixed bandwidth: 12364.63 AICc value: 873.3223
## Fixed bandwidth: 7643.289 AICc value: 878.4815
## Fixed bandwidth: 15282.58 AICc value: 878.0422
## Fixed bandwidth: 10561.24 AICc value: 871.6523
## Fixed bandwidth: 9446.68 AICc value: 872.2683
## Fixed bandwidth: 11250.07 AICc value: 871.8681
## Fixed bandwidth: 10135.51 AICc value: 871.7524
## Fixed bandwidth: 10824.35 AICc value: 871.6657
## Fixed bandwidth: 10398.63 AICc value: 871.675
## Fixed bandwidth: 10661.74 AICc value: 871.6497
## Fixed bandwidth: 10723.85 AICc value: 871.6519
## Fixed bandwidth: 10623.35 AICc value: 871.6497
cat("Bandwidth fixed optimal (AICc):", round(bw_fixed_AICc, 2), "km (approx)\n\n")
## Bandwidth fixed optimal (AICc): 10661.74 km (approx)
# Ringkasan perbandingan bandwidth
cat("=== RINGKASAN PEMILIHAN BANDWIDTH ===\n")
## === RINGKASAN PEMILIHAN BANDWIDTH ===
cat("Adaptive (AICc):", bw_adaptive_AICc, "tetangga\n")
## Adaptive (AICc): 93 tetangga
cat("Adaptive (CV) :", bw_adaptive_CV, "tetangga\n")
## Adaptive (CV) : 99 tetangga
cat("Fixed (AICc) :", round(bw_fixed_AICc, 2), "km\n")
## Fixed (AICc) : 10661.74 km
cat("\nPilihan untuk analisis: Adaptive bandwidth =",
bw_adaptive_AICc, "tetangga (AICc)\n")
##
## Pilihan untuk analisis: Adaptive bandwidth = 93 tetangga (AICc)
Interpretasi Bandwidth Adaptif: Bandwidth = 50 tetangga berarti setiap estimasi lokal menggunakan 50 kabupaten terdekat. Dengan n = 159, ini menggunakan sekitar 31% data di setiap titik.
# Visualisasi perubahan AICc seiring bandwidth (jika didukung)
# Plot manual untuk memahami trade-off bandwidth
bw_range <- seq(30, 100, by = 5)
# Catatan: loop ini bisa memakan waktu; jalankan untuk n kecil
# aicc_vals <- sapply(bw_range, function(bw) {
# gwr_fit <- gwr.basic(PctBach ~ PctFB + PctPov + PctBlack + PctEld,
# data = georgia_sp,
# bw = bw,
# kernel = "bisquare",
# adaptive = TRUE,
# longlat = TRUE)
# return(gwr_fit$GW.diagnostic$AICc)
# })
#
# plot(bw_range, aicc_vals, type = "b", pch = 19,
# xlab = "Bandwidth (jumlah tetangga)",
# ylab = "AICc",
# main = "Profil AICc vs. Bandwidth")
# abline(v = bw_adaptive_AICc, col = "red", lty = 2)
# legend("topright", legend = "Bandwidth Optimal",
# col = "red", lty = 2)
# ====================================================
# MODEL GWR UTAMA
# ====================================================
gwr_model <- gwr.basic(
formula = PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
bw = bw_adaptive_AICc,
kernel = "bisquare",
adaptive = TRUE,
longlat = TRUE,
)
# Ringkasan komprehensif model GWR
print(gwr_model)
## ***********************************************************************
## * Package GWmodel *
## ***********************************************************************
## Program starts at: 2026-06-04 14:37:32.043969
## Call:
## gwr.basic(formula = PctBach ~ PctFB + PctPov + PctBlack + PctEld,
## data = georgia_sp, bw = bw_adaptive_AICc, kernel = "bisquare",
## adaptive = TRUE, longlat = TRUE)
##
## Dependent (y) variable: PctBach
## Independent variables: PctFB PctPov PctBlack PctEld
## Number of data points: 159
## ***********************************************************************
## * Results of Global Regression *
## ***********************************************************************
##
## Call:
## lm(formula = formula, data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12.1414 -2.0934 -0.2113 1.6709 19.9212
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.67113 1.63682 7.741 1.22e-12 ***
## PctFB 2.54521 0.29839 8.530 1.29e-14 ***
## PctPov -0.28291 0.07810 -3.622 0.000396 ***
## PctBlack 0.07685 0.02803 2.742 0.006834 **
## PctEld -0.10531 0.13784 -0.764 0.446047
##
## ---Significance stars
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Residual standard error: 4.013 on 154 degrees of freedom
## Multiple R-squared: 0.5163
## Adjusted R-squared: 0.5037
## F-statistic: 41.09 on 4 and 154 DF, p-value: < 2.2e-16
## ***Extra Diagnostic information
## Residual sum of squares: 2480.558
## Sigma(hat): 3.974888
## AIC: 900.0487
## AICc: 900.6013
## BIC: 789.8755
## ***********************************************************************
## * Results of Geographically Weighted Regression *
## ***********************************************************************
##
## *********************Model calibration information*********************
## Kernel function: bisquare
## Adaptive bandwidth: 93 (number of nearest neighbours)
## Regression points: the same locations as observations are used.
## Distance metric: Great Circle distance metric is used.
##
## ****************Summary of GWR coefficient estimates:******************
## Min. 1st Qu. Median 3rd Qu. Max.
## Intercept 5.615696 9.053463 11.135097 13.227625 17.6829
## PctFB 1.359774 2.273029 2.684983 3.347688 4.7413
## PctPov -0.758644 -0.466808 -0.312448 -0.174473 0.2040
## PctBlack -0.042651 0.061736 0.084654 0.117802 0.1585
## PctEld -0.418820 -0.200138 -0.088642 0.298300 0.4124
## ************************Diagnostic information*************************
## Number of data points: 159
## Effective number of parameters (2trace(S) - trace(S'S)): 25.77023
## Effective degrees of freedom (n-2trace(S) + trace(S'S)): 133.2298
## AICc (GWR book, Fotheringham, et al. 2002, p. 61, eq 2.33): 871.2177
## AIC (GWR book, Fotheringham, et al. 2002,GWR p. 96, eq. 4.22): 842.7247
## BIC (GWR book, Fotheringham, et al. 2002,GWR p. 61, eq. 2.34): 764.4913
## Residual sum of squares: 1646.393
## R-square value: 0.6789454
## Adjusted R-square value: 0.6163751
##
## ***********************************************************************
## Program stops at: 2026-06-04 14:37:32.049739
Output print(gwr_model) menampilkan beberapa bagian
penting:
# Melihat komponen output
names(gwr_model)
## [1] "GW.arguments" "GW.diagnostic" "lm" "SDF"
## [5] "timings" "this.call" "Ftests"
# Diagnostik model
gwr_model$GW.diagnostic
## $RSS.gw
## [1] 1646.393
##
## $AIC
## [1] 842.7247
##
## $AICc
## [1] 871.2177
##
## $enp
## [1] 25.77023
##
## $edf
## [1] 133.2298
##
## $gw.R2
## [1] 0.6789454
##
## $gwR2.adj
## [1] 0.6163751
##
## $BIC
## [1] 764.4913
# Ekstrak hasil GWR ke dataframe
gwr_results <- as.data.frame(gwr_model$SDF)
names(gwr_results)
## [1] "Intercept" "PctFB" "PctPov" "PctBlack"
## [5] "PctEld" "y" "yhat" "residual"
## [9] "CV_Score" "Stud_residual" "Intercept_SE" "PctFB_SE"
## [13] "PctPov_SE" "PctBlack_SE" "PctEld_SE" "Intercept_TV"
## [17] "PctFB_TV" "PctPov_TV" "PctBlack_TV" "PctEld_TV"
## [21] "Local_R2" "coords.x1" "coords.x2"
# Lihat beberapa baris pertama
head(gwr_results[, c("Intercept", "PctFB", "PctPov",
"PctBlack", "PctEld", "Local_R2")], 10)
## Intercept PctFB PctPov PctBlack PctEld Local_R2
## 1 11.067358 2.142394 -0.6031003 0.14844580 0.37357210 0.7281565
## 2 12.952442 3.089092 -0.2657384 0.06784012 -0.15243942 0.5938488
## 3 8.790850 4.270273 0.1465487 -0.02533626 -0.34820654 0.7075223
## 4 14.947569 2.211147 -0.3827517 0.08099225 -0.10559219 0.5509759
## 5 15.999762 1.763246 -0.4417194 0.08850367 -0.09113261 0.5421244
## 6 9.668907 2.275880 -0.5545197 0.13756207 0.41241701 0.7137955
## 7 13.313892 2.905912 -0.2925062 0.07112972 -0.13168561 0.5776912
## 8 12.618980 3.247004 -0.2391053 0.06638177 -0.17938699 0.6069573
## 9 15.002758 1.694722 -0.5917670 0.13283858 0.07153385 0.6552784
## 10 9.370606 2.297304 -0.4993843 0.13615905 0.38510286 0.7235046
# Gabungkan hasil GWR dengan data spasial
georgia_gwr <- georgia_sf
# Koefisien lokal
georgia_gwr$coef_intercept <- gwr_results$Intercept
georgia_gwr$coef_PctFB <- gwr_results$PctFB
georgia_gwr$coef_PctPov <- gwr_results$PctPov
georgia_gwr$coef_PctBlack <- gwr_results$PctBlack
georgia_gwr$coef_PctEld <- gwr_results$PctEld
# R² lokal dan residual
georgia_gwr$local_R2 <- gwr_results$Local_R2
georgia_gwr$resid_gwr <- gwr_results$residual
georgia_gwr$yhat_gwr <- gwr_results$yhat
# Ringkasan distribusi koefisien lokal
cat("=== RINGKASAN KOEFISIEN LOKAL GWR ===\n\n")
## === RINGKASAN KOEFISIEN LOKAL GWR ===
coef_vars <- c("coef_intercept", "coef_PctFB", "coef_PctPov",
"coef_PctBlack", "coef_PctEld")
for (var in coef_vars) {
vals <- st_drop_geometry(georgia_gwr)[[var]]
cat(sprintf("%-20s | Min: %6.3f Median: %6.3f Max: %6.3f SD: %6.3f\n",
var, min(vals), median(vals), max(vals), sd(vals)))
}
## coef_intercept | Min: 5.616 Median: 11.135 Max: 17.683 SD: 2.893
## coef_PctFB | Min: 1.360 Median: 2.685 Max: 4.741 SD: 0.805
## coef_PctPov | Min: -0.759 Median: -0.312 Max: 0.204 SD: 0.224
## coef_PctBlack | Min: -0.043 Median: 0.085 Max: 0.158 SD: 0.048
## coef_PctEld | Min: -0.419 Median: -0.089 Max: 0.412 SD: 0.259
cat("\n")
cat("Koefisien OLS global (pembanding):\n")
## Koefisien OLS global (pembanding):
print(round(coef(model_ols), 4))
## (Intercept) PctFB PctPov PctBlack PctEld
## 12.6711 2.5452 -0.2829 0.0768 -0.1053
# Metrik OLS
r2_ols <- summary(model_ols)$r.squared
r2adj_ols <- summary(model_ols)$adj.r.squared
aic_ols <- AIC(model_ols)
rss_ols <- sum(residuals(model_ols)^2)
# Metrik GWR
r2_gwr <- gwr_model$GW.diagnostic$gw.R2
r2adj_gwr <- gwr_model$GW.diagnostic$gwR2.adj
aicc_gwr <- gwr_model$GW.diagnostic$AICc
rss_gwr <- sum(gwr_results$residual^2)
# Moran's I residual GWR
georgia_nb <- spdep::poly2nb(georgia_poly, queen = TRUE)
georgia_lw <- spdep::nb2listw(georgia_nb, style = "W", zero.policy = TRUE)
moran_gwr <- moran.test(georgia_gwr$resid_gwr,
georgia_lw,
zero.policy = TRUE)
#Moran's I residual OLS
moran_ols <- moran.test(residuals(model_ols), georgia_lw, zero.policy = TRUE)
cat("=== PERBANDINGAN OLS vs. GWR ===\n\n")
## === PERBANDINGAN OLS vs. GWR ===
cat(sprintf("%-30s %10s %10s\n", "Metrik", "OLS", "GWR"))
## Metrik OLS GWR
cat(rep("-", 52), "\n", sep = "")
## ----------------------------------------------------
cat(sprintf("%-30s %10.4f %10.4f\n", "R-squared", r2_ols, r2_gwr))
## R-squared 0.5163 0.6789
cat(sprintf("%-30s %10.4f %10.4f\n", "Adjusted R-squared", r2adj_ols, r2adj_gwr))
## Adjusted R-squared 0.5037 0.6164
cat(sprintf("%-30s %10.2f %10.2f\n", "AIC / AICc", aic_ols, aicc_gwr))
## AIC / AICc 900.05 871.22
cat(sprintf("%-30s %10.4f %10.4f\n", "RSS (Residual Sum of Sq)", rss_ols, rss_gwr))
## RSS (Residual Sum of Sq) 2480.5579 1646.3926
cat(sprintf("%-30s %10.4f %10.4f\n", "Moran's I Residual",
moran_ols$estimate[1], moran_gwr$estimate[1]))
## Moran's I Residual 0.0378 0.0142
cat(sprintf("%-30s %10s %10s\n", "Moran's I p-value",
ifelse(moran_ols$p.value < 0.001, "<0.001", round(moran_ols$p.value, 4)),
ifelse(moran_gwr$p.value < 0.001, "<0.001", round(moran_gwr$p.value, 4))))
## Moran's I p-value 0.1797 0.3356
# Visualisasi perbandingan residual OLS vs. GWR
# Visualisasi perbandingan residual OLS vs. GWR
par(mfrow = c(1, 2))
# PERBAIKAN: Mengubah georgia_sf menjadi georgia_map
hist(georgia_map$resid_ols, breaks = 20,
main = "Residual OLS", xlab = "Residual",
col = "lightcoral", border = "white")
abline(v = 0, col = "red", lty = 2)
# Menggunakan objek gwr yang sudah sinkron
hist(georgia_gwr$resid_gwr, breaks = 20,
main = "Residual GWR", xlab = "Residual",
col = "lightblue", border = "white")
abline(v = 0, col = "blue", lty = 2)
par(mfrow = c(1, 1))
# Perbandingan fitted vs. actual
ggplot() +
# OLS (PERBAIKAN: Menggunakan georgia_map)
geom_point(data = st_drop_geometry(georgia_map),
aes(x = PctBach, y = fitted_ols, color = "OLS"),
alpha = 0.6, size = 2) +
# GWR
geom_point(data = st_drop_geometry(georgia_gwr),
aes(x = PctBach, y = yhat_gwr, color = "GWR"),
alpha = 0.6, size = 2) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "gray") +
scale_color_manual(values = c("OLS" = "coral", "GWR" = "steelblue")) +
labs(title = "Nilai Fitted vs. Aktual: OLS vs. GWR",
x = "PctBach Aktual (%)",
y = "PctBach Prediksi (%)",
color = "Model") +
theme_bw()
Koefisien lokal GWR \(\hat\beta_k(u_i, v_i)\) diinterpretasikan mirip dengan koefisien OLS, tetapi hanya berlaku untuk lokasi \((u_i, v_i)\):
“Di kabupaten X, setiap kenaikan 1% tingkat kemiskinan (PctPov) dikaitkan dengan perubahan sebesar \(\hat\beta_{PctPov}(u_X, v_X)\)% dalam persentase gelar sarjana (PctBach), dengan memperhitungkan variabel lain yang konstan.”
Tanda koefisien: - Positif (+): Kenaikan prediktor dikaitkan dengan kenaikan respons di lokasi tersebut - Negatif (−): Kenaikan prediktor dikaitkan dengan penurunan respons di lokasi tersebut - Mendekati nol: Variabel tidak berpengaruh signifikan secara lokal
# Tabel ringkasan koefisien lokal
coef_summary <- data.frame(
Variabel = c("Intercept", "PctFB", "PctPov", "PctBlack", "PctEld"),
OLS = round(coef(model_ols), 4),
Min_GWR = round(apply(gwr_results[, c("Intercept","PctFB","PctPov",
"PctBlack","PctEld")], 2, min), 4),
Median_GWR = round(apply(gwr_results[, c("Intercept","PctFB","PctPov",
"PctBlack","PctEld")], 2, median), 4),
Max_GWR = round(apply(gwr_results[, c("Intercept","PctFB","PctPov",
"PctBlack","PctEld")], 2, max), 4),
SD_GWR = round(apply(gwr_results[, c("Intercept","PctFB","PctPov",
"PctBlack","PctEld")], 2, sd), 4)
)
print(coef_summary)
## Variabel OLS Min_GWR Median_GWR Max_GWR SD_GWR
## (Intercept) Intercept 12.6711 5.6157 11.1351 17.6829 2.8930
## PctFB PctFB 2.5452 1.3598 2.6850 4.7413 0.8054
## PctPov PctPov -0.2829 -0.7586 -0.3124 0.2040 0.2242
## PctBlack PctBlack 0.0768 -0.0427 0.0847 0.1585 0.0480
## PctEld PctEld -0.1053 -0.4188 -0.0886 0.4124 0.2586
# Boxplot distribusi koefisien lokal
gwr_coef_long <- gwr_results %>%
select(Intercept, PctFB, PctPov, PctBlack, PctEld) %>%
pivot_longer(everything(), names_to = "Variabel", values_to = "Koefisien")
ggplot(gwr_coef_long, aes(x = Variabel, y = Koefisien, fill = Variabel)) +
geom_boxplot(alpha = 0.7, outlier.size = 1) +
geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
# Tambahkan garis untuk koefisien OLS
geom_point(data = data.frame(
Variabel = c("Intercept", "PctFB", "PctPov", "PctBlack", "PctEld"),
OLS = coef(model_ols)
), aes(y = OLS), color = "black", shape = 18, size = 4) +
scale_fill_brewer(palette = "Set2") +
labs(title = "Distribusi Koefisien Lokal GWR",
subtitle = "Berlian hitam = koefisien OLS global",
x = "Variabel Prediktor",
y = "Nilai Koefisien Lokal") +
theme_bw() +
theme(legend.position = "none")
# 1. Aktifkan mode plot statis
tmap_mode("plot")
# ====================================================
# SINKRONISASI DATA
# Memasukkan kolom koefisien dari georgia_gwr ke georgia_map
# ====================================================
georgia_map$coef_PctFB <- georgia_gwr$coef_PctFB
georgia_map$coef_PctPov <- georgia_gwr$coef_PctPov
georgia_map$coef_PctBlack <- georgia_gwr$coef_PctBlack
georgia_map$coef_PctEld <- georgia_gwr$coef_PctEld
# ====================================================
# PETA CHOROPLETH 1: % Foreign Born
# ====================================================
map_coef_PctFB <- tm_shape(georgia_map) +
tm_polygons(
fill = "coef_PctFB",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.rd_bu", midpoint = 0),
fill.legend = tm_legend(
title = "β(PctFB)",
position = tm_pos_in("left", "bottom"),
frame = TRUE
)
) +
tm_title("Koefisien GWR: % Foreign Born", size = 0.8)
# ====================================================
# PETA CHOROPLETH 2: % Kemiskinan
# ====================================================
map_coef_PctPov <- tm_shape(georgia_map) +
tm_polygons(
fill = "coef_PctPov",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.rd_bu", midpoint = 0),
fill.legend = tm_legend(
title = "β(PctPov)",
position = tm_pos_in("left", "bottom"),
frame = TRUE
)
) +
tm_title("Koefisien GWR: % Kemiskinan", size = 0.8)
# ====================================================
# PETA CHOROPLETH 3: % Black
# ====================================================
map_coef_PctBlack <- tm_shape(georgia_map) +
tm_polygons(
fill = "coef_PctBlack",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.rd_bu", midpoint = 0),
fill.legend = tm_legend(
title = "β(PctBlack)",
position = tm_pos_in("left", "bottom"),
frame = TRUE
)
) +
tm_title("Koefisien GWR: % Black", size = 0.8)
# ====================================================
# PETA CHOROPLETH 4: % Lansia
# ====================================================
map_coef_PctEld <- tm_shape(georgia_map) +
tm_polygons(
fill = "coef_PctEld",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.rd_bu", midpoint = 0),
fill.legend = tm_legend(
title = "β(PctEld)",
position = tm_pos_in("left", "bottom"),
frame = TRUE
)
) +
tm_title("Koefisien GWR: % Lansia", size = 0.8)
# ====================================================
# TAMPILKAN 4 PETA CHOROPLETH BERDAMPINGAN
# ====================================================
tmap_arrange(map_coef_PctFB, map_coef_PctPov,
map_coef_PctBlack, map_coef_PctEld,
ncol = 2)
Berdasarkan analisis, kita dapat memberikan interpretasi seperti berikut:
Contoh interpretasi (bergantung pada hasil aktual):
PctPov (% Kemiskinan): Secara global (OLS), setiap kenaikan 1% kemiskinan dikaitkan dengan penurunan ~X% gelar sarjana. Namun, GWR menunjukkan bahwa di kabupaten-kabupaten metropolitan (Atlanta dan sekitarnya), pengaruh kemiskinan lebih kuat negatif dibanding di wilayah perdesaan.
PctFB (% Foreign Born): Koefisien lokal bervariasi dari negatif di bagian tertentu hingga positif di bagian lain, menunjukkan bahwa pengaruh imigran terhadap pendidikan tidak seragam.
PctBlack (% Black): Pengaruh komposisi etnis bervariasi, mencerminkan heterogenitas historis dalam akses pendidikan antar-wilayah.
georgia_map$local_R2 <- georgia_gwr$local_R2
# ====================================================
# Peta R² Lokal (Choropleth / Poligon Murni tmap v4)
# ====================================================
map_local_R2 <- tm_shape(georgia_map) +
tm_polygons(
fill = "local_R2", # Menggunakan fill untuk poligon
fill.scale = tm_scale_intervals( # Mengelompokkan parameter skala
style = "jenks",
n = 5,
values = "brewer.yl_gn_bu" # Menggunakan standar nama palet v4
),
fill.legend = tm_legend(
title = "R² Lokal",
position = tm_pos_in("left", "bottom"), # Legenda di dalam agar aman dari bug layout
frame = TRUE
)
) +
tm_title("GWR: R² Lokal (Kecocokan Model per Kabupaten)", size = 0.8)
# Tampilkan peta
map_local_R2
Interpretasi R² Lokal: Area dengan R² lokal tinggi menunjukkan bahwa variabel prediktor yang dipilih mampu menjelaskan variasi PctBach dengan baik di area tersebut. R² lokal rendah mengindikasikan bahwa ada variabel penting yang tidak termasuk dalam model, atau hubungannya sangat tidak linear.
georgia_map$resid_gwr <- georgia_gwr$resid_gwr
# ====================================================
# Peta Residual GWR (Choropleth / Poligon Murni tmap v4)
# ====================================================
map_resid_gwr <- tm_shape(georgia_map) +
tm_polygons(
fill = "resid_gwr", # Mewarnai area poligon berdasarkan nilai residual
fill.scale = tm_scale_intervals( # Manajemen skala interval di tmap v4
style = "jenks",
n = 5,
values = "brewer.rd_bu", # Menggunakan standar nama palet v4
midpoint = 0 # Pusat warna (putih/netral) dikunci di angka 0
),
fill.legend = tm_legend(
title = "Residual GWR",
position = tm_pos_in("left", "bottom"), # Legenda di dalam area peta agar aman dari bug layout
frame = TRUE
)
) +
tm_title("Peta Residual Model GWR", size = 0.8)
# Tampilkan peta
map_resid_gwr
georgia_map$resid_ols <- as.numeric(residuals(model_ols))
georgia_map$resid_gwr <- as.numeric(georgia_gwr$resid_gwr)
semua_residual <- c(georgia_map$resid_ols, georgia_map$resid_gwr)
breaks_bersama <- pretty(semua_residual, n = 5)
# Pembuatan peta perbandingan multivariate facet (tmap v4)
peta_perbandingan <- tm_shape(georgia_map) +
tm_polygons(
fill = c("resid_ols", "resid_gwr"),
fill.scale = tm_scale_intervals(
breaks = breaks_bersama,
values = "brewer.rd_bu",
midpoint = 0
),
fill.legend = tm_legend(
title = "Nilai Residual",
position = tm_pos_out("right", "center")
)
) +
tm_facets(ncol = 2)
peta_perbandingan
## [plot mode] legend/component: Some components or legends are too "high" and are
## therefore rescaled.
## ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
Koefisien lokal GWR disertai dengan standard error dan t-value, tetapi interpretasi langsung bermasalah karena: 1. Multiple testing problem: Kita melakukan uji hipotesis di 159 lokasi 2. Dependensi spasial: Pengujian di lokasi yang berdekatan tidak independen
Paket GWmodel menyediakan fungsi
gwr.t.adjust() yang mengkoreksi masalah uji berganda
menggunakan metode Byrne et al. (2016).
# Ekstrak standard error dan t-values dari model GWR
# (diperlukan se.fit = TRUE saat menjalankan gwr.basic)
# Nama kolom standard error
se_cols <- paste0(c("Intercept", "PctFB", "PctPov", "PctBlack", "PctEld"), "_SE")
tv_cols <- paste0("TV_", c("Intercept", "PctFB", "PctPov", "PctBlack", "PctEld"))
# Cek nama kolom yang tersedia
names(gwr_results)
## [1] "Intercept" "PctFB" "PctPov" "PctBlack"
## [5] "PctEld" "y" "yhat" "residual"
## [9] "CV_Score" "Stud_residual" "Intercept_SE" "PctFB_SE"
## [13] "PctPov_SE" "PctBlack_SE" "PctEld_SE" "Intercept_TV"
## [17] "PctFB_TV" "PctPov_TV" "PctBlack_TV" "PctEld_TV"
## [21] "Local_R2" "coords.x1" "coords.x2"
# T-values lokal
if ("PctPov_TV" %in% names(gwr_results)) {
georgia_gwr$tv_PctFB <- gwr_results$PctFB_TV
georgia_gwr$tv_PctPov <- gwr_results$PctPov_TV
georgia_gwr$tv_PctBlack <- gwr_results$PctBlack_TV
georgia_gwr$tv_PctEld <- gwr_results$PctEld_TV
cat("T-values lokal berhasil diekstrak.\n")
}
## T-values lokal berhasil diekstrak.
# Koreksi p-value dengan multiple testing adjustment
gwr_sig <- gwr.t.adjust(gwr_model)
# Lihat struktur output
summary(gwr_sig)
## Length Class Mode
## results 6 -none- list
## SDF 159 SpatialPointsDataFrame S4
# Ekstrak p-values terkoreksi ke data spasial
# Metode Bonferroni atau FDR (tergantung versi GWmodel)
# Menambahkan hasil signifikansi ke dataframe
sig_results <- as.data.frame(gwr_sig$SDF)
if ("PctPov_p" %in% names(sig_results) ||
"PctPov_pval" %in% names(sig_results)) {
# Cek nama kolom p-value
p_col_check <- names(sig_results)[grepl("PctPov", names(sig_results))]
cat("Kolom p-value tersedia:", p_col_check, "\n")
}
## Kolom p-value tersedia: PctPov_t PctPov_p PctPov_p_by PctPov_p_fb PctPov_p_bo PctPov_p_bh
# Kategori signifikansi berdasarkan t-value
# Aturan umum: |t| > 1.96 → p < 0.05
# Untuk multiple testing: gunakan threshold lebih ketat
categorize_sig <- function(t_val) {
case_when(
abs(t_val) > 2.576 ~ "Sangat signifikan (p<0.01)",
abs(t_val) > 1.960 ~ "Signifikan (p<0.05)",
abs(t_val) > 1.645 ~ "Marjinal (p<0.10)",
TRUE ~ "Tidak signifikan"
)
}
if ("PctPov_TV" %in% names(gwr_results)) {
georgia_gwr$sig_PctPov <- categorize_sig(gwr_results$PctPov_TV)
georgia_gwr$sig_PctFB <- categorize_sig(gwr_results$PctFB_TV)
georgia_gwr$sig_PctBlack <- categorize_sig(gwr_results$PctBlack_TV)
georgia_gwr$sig_PctEld <- categorize_sig(gwr_results$PctEld_TV)
# Ringkasan signifikansi
cat("\n=== RINGKASAN SIGNIFIKANSI KOEFISIEN LOKAL ===\n\n")
for (var in c("sig_PctFB", "sig_PctPov", "sig_PctBlack", "sig_PctEld")) {
cat(var, ":\n")
print(table(st_drop_geometry(georgia_gwr)[[var]]))
cat("\n")
}
}
##
## === RINGKASAN SIGNIFIKANSI KOEFISIEN LOKAL ===
##
## sig_PctFB :
##
## Sangat signifikan (p<0.01)
## 159
##
## sig_PctPov :
##
## Marjinal (p<0.10) Sangat signifikan (p<0.01)
## 6 90
## Signifikan (p<0.05) Tidak signifikan
## 21 42
##
## sig_PctBlack :
##
## Marjinal (p<0.10) Sangat signifikan (p<0.01)
## 24 54
## Signifikan (p<0.05) Tidak signifikan
## 29 52
##
## sig_PctEld :
##
## Marjinal (p<0.10) Signifikan (p<0.05) Tidak signifikan
## 33 18 108
Pendekatan umum adalah menampilkan koefisien lokal dengan stippling (titik-titik) atau masking untuk menunjukkan mana yang signifikan dan mana yang tidak.
# Sinkronisasi data ke poligon & filter signifikansi (|t| > 1.96)
georgia_map$tv_PctPov <- gwr_results$PctPov_TV
georgia_map$significant <- abs(georgia_map$tv_PctPov) > 1.96
# Pembuatan peta t-value choropleth (tmap v4)
map_tvalue <- tm_shape(georgia_map) +
tm_polygons(
fill = "tv_PctPov",
fill.scale = tm_scale_intervals(style = "jenks", n = 7, values = "brewer.rd_bu", midpoint = 0),
fill.legend = tm_legend(title = "t-value (PctPov)", position = tm_pos_out("right"))
) +
tm_shape(georgia_map[georgia_map$significant, ]) +
tm_borders(col = "black", lwd = 1.8) +
tm_title("T-values Koefisien Lokal: % Kemiskinan\n(Batas tebal = p < 0.05)", size = 0.85)
map_tvalue
# Membuat kategori gabungan arah + signifikansi (menggunakan PctPov_TV dari hasil sebelumnya)
# Membuat 3 kategori signifikansi berdasarkan t-value
georgia_map$PctPov_sig_cat3 <- case_when(
gwr_results$PctPov_TV < -1.96 ~ "Negatif Signifikan",
gwr_results$PctPov_TV > 1.96 ~ "Positif Signifikan",
TRUE ~ "Tidak Signifikan"
)
# Pembuatan peta choropleth 3 kategori (tmap v4)
map_sig_cat3 <- tm_shape(georgia_map) +
tm_polygons(
fill = "PctPov_sig_cat3",
fill.scale = tm_scale_categorical(values = c(
"Negatif Signifikan" = "#4575b4", # Biru
"Positif Signifikan" = "#d73027", # Merah
"Tidak Signifikan" = "#e0e0e0" # Abu-abu netral
)),
fill.legend = tm_legend(title = "Signifikansi PctPov", position = tm_pos_out("right"))
) +
tm_title("Peta Koefisien × Signifikansi: % Kemiskinan", size = 0.9)
map_sig_cat3
# Sinkronisasi data ke objek poligon georgia_map
georgia_map$local_R2 <- georgia_gwr$local_R2
georgia_map$coef_PctPov <- georgia_gwr$coef_PctPov
# Peta 1: R² Lokal
map1 <- tm_shape(georgia_map) +
tm_polygons(
fill = "local_R2",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.yl_gn_bu"),
fill.legend = tm_legend(title = "R² Lokal", position = tm_pos_out("right"))
) +
tm_title("R² Lokal GWR", size = 0.85)
# Peta 2: Koefisien PctPov
map2 <- tm_shape(georgia_map) +
tm_polygons(
fill = "coef_PctPov",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.rd_bu", midpoint = 0),
fill.legend = tm_legend(title = "β(PctPov)", position = tm_pos_out("right"))
) +
tm_title("Koefisien Lokal: % Kemiskinan", size = 0.85)
# Tampilkan kedua peta berdampingan dengan ukuran sama besar
tmap_arrange(map1, map2, ncol = 2)
Meskipun GWR adalah alat yang sangat berguna, penting untuk memahami keterbatasannya:
Kolinieritas merupakan masalah yang dapat terjadi pada model regresi mana pun, namun urgensinya menjadi jauh lebih tinggi dalam konteks GWR. Hal ini disebabkan karena model GWR mengestimasi ulang parameter pada subset geografis lokal. Pada skala lokal tersebut, peubah-peubah penjelas berpotensi besar memiliki korelasi yang jauh lebih kuat dibandingkan pada skala wilayah studi secara keseluruhan (mengikuti prinsip spasial bahwa hal-hal yang mirip cenderung saling berdekatan). Multikolinieritas lokal ini dapat memicu inflasi varians (variance inflation), yang berdampak pada ketidakstabilan model dan menghasilkan estimasi parameter yang tidak andal atau tidak presisi.
Sebagai langkah awal, kita melakukan diagnostik kolinieritas pada hasil model. Jika pengujian menunjukkan adanya bukti multikolinieritas yang mengkhawatirkan, kita memiliki dua pilihan solusi: mengubah spesifikasi model dengan menghapus peubah penjelas penentu (culprit covariates), atau beralih ke bentuk model yang kebal (robust) terhadap kolinieritas, seperti local ridge regression yang tersedia melalui fungsi gwr.lcr(). Untuk saat ini, kita akan fokus pada tahap diagnostik terlebih dahulu menggunakan fungsi gwr.collin.diagno() yang menghasilkan Condition Number (CN) lokal serta nilai Variance Inflation Factor (VIF) lokal dari model yang telah fit.
# 1. Jalankan fungsi diagnostik kolinieritas lokal GWR
local_cn <- gwr.collin.diagno(
formula = PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
bw = 93,
kernel = "bisquare",
adaptive = TRUE,
longlat = TRUE
)
# 2. Tampilkan ringkasan statistik Condition Number lokal di Console
summary(local_cn$SDF$local_CN)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 12.40 13.93 15.26 15.68 16.87 23.51
# 3. Sinkronisasi nilai CN ke data poligon asli sebagai vektor numerik
georgia_map$cond_num <- as.numeric(local_cn$SDF$local_CN)
# 4. Visualisasi peta choropleth Condition Number menggunakan tmap v4
map_cn <- tm_shape(georgia_map) +
tm_polygons(
fill = "cond_num",
fill.scale = tm_scale_intervals(style = "jenks", n = 5, values = "brewer.or_rd"),
fill.legend = tm_legend(title = "Condition Number", position = tm_pos_out("right"))
) +
tm_title("Multikolinieritas Lokal: Condition Number", size = 0.85)
# Tampilkan peta
map_cn
Interpretasi OutputEvaluasi Nilai Ambang Kritis (Threshold): + Berdasarkan nilai \(\eta_i\), jika \(\eta_i > 30\), hal tersebut mengindikasikan adanya multikolinieritas lokal tingkat moderat. Jika \(\eta_i > 100\), matriks lokal mendekati singular (terjadi multikolinieritas lokal yang sangat serius).
Analisis Nilai Maksimum (Summary): Perhatikan nilai Max pada luaran summary(local_cn\(SDF\)local_CN). Jika nilai maksimum tersebut berada di bawah angka 30, maka pembagi \(\lambda_{\min}\) pada seluruh lokasi tidak ada yang mendekati nol, menandakan struktur data lokal di seluruh kabupaten Georgia aman dari gangguan kolinieritas.
Pola Distribusi Spasial (Peta): Melalui peta choropleth, wilayah dengan warna jingga tua hingga merah menunjukkan area di mana peubah penjelas saling bertumpang tindih secara spasial. Jika wilayah dengan nilai CN > 30 muncul, estimasi koefisien lokal \(\beta(u_i, v_i)\) di area tersebut menjadi tidak stabil, sehingga disarankan untuk menggunakan pendekatan local ridge regression (gwr.lcr()) khusus pada kluster wilayah tersebut.
# ====================================================
# 1. CETAK VIF GLOBAL (OLS)
# ====================================================
cat("=== DIAGNOSTIK MULTIKOLINIERITAS GLOBAL (OLS) ===\n")
## === DIAGNOSTIK MULTIKOLINIERITAS GLOBAL (OLS) ===
vif_global <- car::vif(model_ols)
print(round(vif_global, 3))
## PctFB PctPov PctBlack PctEld
## 1.335 3.148 2.328 1.769
cat("\n")
# ====================================================
# 2. CETAK CONDITION NUMBER LOKAL (GWR)
# ====================================================
cat("=== DIAGNOSTIK MULTIKOLINIERITAS LOKAL (GWR) ===\n")
## === DIAGNOSTIK MULTIKOLINIERITAS LOKAL (GWR) ===
summary(local_cn$SDF$local_CN)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 12.40 13.93 15.26 15.68 16.87 23.51
VIF Global (OLS): Mengukur tingkat keterikatan linear antara satu peubah penjelas tertentu (\(X_k\)) dengan peubah-peubah penjelas lainnya di dalam model. Hasilnya adalah satu nilai untuk setiap peubah \(X\), yang berlaku sama untuk seluruh wilayah studi.
Condition Number Lokal (GWR): Mengukur tingkat ketidakstabilan atau kepelikan numerik dari seluruh sistem matriks koordinat di lokasi spesifik \(i\). Hasilnya adalah satu nilai untuk setiap titik lokasi/kabupaten (\(i\)), yang merangkum kondisi seluruh peubah \(X\) setelah dikenakan pembobotan geografis.
| Keterbatasan | Penjelasan | Solusi/Mitigasi |
|---|---|---|
| Multikolinieritas lokal | Variabel lebih berkorelasi di sub-wilayah | Periksa condition number lokal; hapus variabel kolinear |
| Multiple testing | Uji hipotesis di banyak lokasi sekaligus | Gunakan gwr.t.adjust() untuk koreksi |
| Overfitting | Bandwidth kecil → model terlalu menyesuaikan noise | Pilih bandwidth via AICc; validasi silang |
| Outlier sensitif | Pengamatan ekstrem sangat memengaruhi estimasi lokal | Diagnostik leverage; robust GWR |
| Interpretasi | Koefisien bervariasi ≠ hubungan kausal berbeda | GWR bersifat eksploratif, bukan kausal |
| Ekstrapolasi | Koefisien di tepi wilayah kurang dapat diandalkan | Gunakan lebih banyak data di tepi; catat ketidakpastian |
| Bandwidth stationarity | Satu bandwidth untuk semua variabel | Pertimbangkan Mixed GWR atau MGWR |
Mixed GWR (MGWR): Pengembangan GWR yang memungkinkan bandwidth berbeda untuk setiap variabel prediktor. Jika beberapa variabel bersifat global dan lainnya lokal, Mixed GWR lebih tepat. Tersedia melalui
gwr.mixed()diGWmodel.
Jalankan model GWR dengan tiga jenis kernel berbeda
(bisquare, gaussian, tricube)
menggunakan bandwidth yang sama. Bandingkan AICc dan pola spasial
koefisien yang dihasilkan. Kernel mana yang menghasilkan AICc
terkecil?
Jalankan GWR dengan bandwidth fixed (hasil dari
bw_fixed_AICc) dan bandingkan hasilnya dengan bandwidth
adaptive. Jelaskan perbedaan dalam pola koefisien lokal yang
dihasilkan.
Ulangi seluruh analisis menggunakan MedInc (median
pendapatan) sebagai variabel respons dan PctBach,
PctFB, PctPov, PctBlack sebagai
prediktor. Apakah pola non-stasioneritas sama?
Coba jalankan Mixed GWR menggunakan gwr.mixed() dengan
asumsi bahwa PctEld adalah variabel global dan variabel
lainnya lokal:
# Mixed GWR (beberapa variabel global, lainnya lokal)
gwr_mixed <- gwr.mixed(
PctBach ~ PctFB + PctPov + PctBlack + PctEld,
data = georgia_sp,
fixed.vars = "PctEld", # variabel global
intercept.fixed = FALSE,
bw = bw_adaptive_AICc,
kernel = "bisquare",
adaptive = TRUE,
longlat = TRUE
)
print(gwr_mixed)
Cari dataset spasial dari wilayah Indonesia (misalnya: data Badan Pusat Statistik tingkat kecamatan atau kabupaten) dan terapkan seluruh alur kerja GWR. Beberapa sumber data: - BPS: https://www.bps.go.id/ - Satu Data Indonesia: https://data.go.id/ - PODES (Potensi Desa): data sosial-ekonomi tingkat desa
Comber, L. (2019). INIA International Workshop on Spatial Analysis in R — Session 7: Regression and Spatial Heterogeneity Effects with Geographically Weighted Regression (GWR). RPubs. https://rpubs.com/lexcomber/INIA_Session7
GWmodel Team (2016). Geographically Weighted Regression Practical. RPubs. https://rpubs.com/gwmodel/176883
Kram, M. (2023). EPI 563: Spatial Epidemiology — Week 12: Spatial Regression III: Geographically Weighted Regression. https://mkram01.github.io/EPI563-SpatialEPI/spatial-regression-iii-geographically-weighted-regression.html
Potier, C. (2018). Lab 3: Geographically Weighted Regression — A Case Study of Children’s Social Skill Scores in Vancouver, Canada. GEOB479, University of British Columbia.
Bivand, R. (2022). Geographically Weighted Regression (Package Vignette: spgwr). CRAN. https://cran.r-project.org/web/packages/spgwr/vignettes/GWR.pdf