Tugas Prak Regpas 9

Kezia Imanuella Victoria

2026-11-10

Library

library(sp)
## Warning: package 'sp' was built under R version 4.5.3
library(sf)
## Warning: package 'sf' was built under R version 4.5.3
## Linking to GEOS 3.14.1, GDAL 3.12.1, PROJ 9.7.1; sf_use_s2() is TRUE
library(terra)
## Warning: package 'terra' was built under R version 4.5.3
## terra 1.9.34
library(gstat)
## Warning: package 'gstat' was built under R version 4.5.3
library(dismo)
## Warning: package 'dismo' was built under R version 4.5.3
## Loading required package: raster
## Warning: package 'raster' was built under R version 4.5.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.2
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:raster':
## 
##     intersect, select, union
## The following objects are masked from 'package:terra':
## 
##     intersect, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.2
library(viridis)
## Warning: package 'viridis' was built under R version 4.5.3
## Loading required package: viridisLite
## Warning: package 'viridisLite' was built under R version 4.5.2
library(patchwork)
## Warning: package 'patchwork' was built under R version 4.5.2
## 
## Attaching package: 'patchwork'
## The following object is masked from 'package:raster':
## 
##     area
## The following object is masked from 'package:terra':
## 
##     area

Data

data(meuse)
data(meuse.grid)
 
meuse$logzinc <- log(meuse$zinc)
 
d    <- st_as_sf(meuse,      coords = c("x", "y"), crs = 28992)
coop <- st_as_sf(meuse.grid, coords = c("x", "y"), crs = 28992)

semua_titik <- as.data.frame(rbind(st_coordinates(d), st_coordinates(coop)))
map <- st_as_sf(semua_titik, coords = c("X", "Y"), crs = 28992) %>%
  st_combine() %>%
  st_convex_hull() %>%
  st_sf()
 
ggplot() +
  geom_sf(data = coop, color = "grey85", size = 0.4) +
  geom_sf(data = d, aes(color = logzinc), size = 1.8) +
  scale_color_viridis(name = "log(zinc)") +
  theme_bw()

Fungsi prediksi per metode

rmse <- function(observed, predicted) sqrt(mean((observed - predicted)^2))
 
K_NEIGHBOR <- 5   # jumlah tetangga untuk NN
IDP_IDW    <- 1   # pangkat jarak IDW (materi memakai 1)
 

pred_closest <- function(train, newdata) {
  train$logzinc[st_nearest_feature(newdata, train)]
}
 
pred_idw <- function(train, newdata) {
  g <- gstat(formula = logzinc ~ 1, locations = train,
             nmax = nrow(train), set = list(idp = IDP_IDW))
  predict(g, newdata, debug.level = 0)$var1.pred
}
 
pred_nn <- function(train, newdata) {
  g <- gstat(formula = logzinc ~ 1, locations = train,
             nmax = K_NEIGHBOR, set = list(idp = 0))
  predict(g, newdata, debug.level = 0)$var1.pred
}
 
fit_variogram_sph <- function(train) {
  v <- variogram(logzinc ~ 1, data = train)
  fit.variogram(v, model = vgm(psill = 0.5, model = "Sph",
                               range = 900, nugget = 0.1))
}
 
pred_kriging <- function(train, newdata) {
  fv <- fit_variogram_sph(train)
  krige(logzinc ~ 1, locations = train, newdata = newdata,
        model = fv, debug.level = 0)$var1.pred
}

Closest Observation (Voronoi)

vor <- voronoi(x = vect(d), bnd = vect(map)) %>% st_as_sf()
 
ggplot(vor) +
  geom_sf(aes(fill = logzinc), color = "white", linewidth = 0.1) +
  geom_sf(data = d, size = 0.5) +
  scale_fill_viridis(name = "log(zinc)") +
  theme_bw()

coop$closest <- pred_closest(d, coop)

IDW & Nearest Neighbors

coop$idw <- pred_idw(d, coop)
coop$nn  <- pred_nn(d, coop)

Ensemble

inverse_rmse_weights <- function(train, k = 5) {
  inner <- kfold(nrow(train), k = k)
  p <- matrix(NA_real_, nrow(train), 3)
  for (j in 1:k) {
    tr <- train[inner != j, ]
    te <- train[inner == j, ]
    p[inner == j, ] <- cbind(pred_closest(tr, te),
                             pred_idw(tr, te),
                             pred_nn(tr, te))
  }
  w <- 1 / apply(p, 2, function(m) rmse(train$logzinc, m))
  w / sum(w)
}
 
pred_ensemble <- function(train, newdata, w = inverse_rmse_weights(train)) {
  w[1] * pred_closest(train, newdata) +
    w[2] * pred_idw(train, newdata) +
    w[3] * pred_nn(train, newdata)
}
 
w_full <- inverse_rmse_weights(d)
names(w_full) <- c("closest", "idw", "nn")
w_full   # bobot ensemble pada seluruh data
##   closest       idw        nn 
## 0.3307573 0.2819060 0.3873367
coop$ensemble <- w_full["closest"] * coop$closest +
  w_full["idw"] * coop$idw +
  w_full["nn"] * coop$nn

Ordinary Kriging

v_emp <- variogram(logzinc ~ 1, data = d)
fv    <- fit_variogram_sph(d)
fv
##   model      psill    range
## 1   Nug 0.05066017   0.0000
## 2   Sph 0.59060556 897.0044
plot(v_emp, fv, cex = 1.5)

krig <- gstat(formula = logzinc ~ 1, data = d, model = fv)
kp   <- predict(krig, coop)
## [using ordinary kriging]
coop$kriging <- kp$var1.pred
coop$krig_var <- kp$var1.var

Peta perbandingan semua metode

peta <- function(kolom, judul) {
  ggplot(coop) +
    geom_sf(aes(color = .data[[kolom]]), size = 0.7, shape = 15) +
    scale_color_viridis(name = "log(zinc)", limits = range(d$logzinc)) +
    labs(title = judul) +
    theme_bw()
}
 
(peta("closest", "Closest Observation") | peta("nn", "Nearest Neighbors")) /
(peta("idw", "IDW") | peta("ensemble", "Ensemble")) /
(peta("kriging", "Ordinary Kriging") | plot_spacer()) +
  plot_layout(guides = "collect")

ggplot(coop) +
  geom_sf(aes(color = krig_var), size = 0.7, shape = 15) +
  geom_sf(data = d, size = 0.6) +
  scale_color_viridis(name = "Varians kriging", option = "magma") +
  theme_bw()

5-fold Cross Validation

set.seed(123)
K  <- 5
kf <- kfold(nrow(d), k = K)    # fold yang sama dipakai semua metode
 
metode <- c("Closest", "IDW", "NN", "Ensemble", "Kriging")
rmse_cv <- matrix(NA_real_, nrow = K, ncol = length(metode),
                  dimnames = list(paste0("fold", 1:K), metode))
 
for (k in 1:K) {
  train <- d[kf != k, ]
  test  <- d[kf == k, ]
 
  p_closest <- pred_closest(train, test)
  p_idw     <- pred_idw(train, test)
  p_nn      <- pred_nn(train, test)
  p_ens     <- pred_ensemble(train, test)
  p_krig    <- pred_kriging(train, test)
 
  rmse_cv[k, ] <- c(rmse(test$logzinc, p_closest),
                    rmse(test$logzinc, p_idw),
                    rmse(test$logzinc, p_nn),
                    rmse(test$logzinc, p_ens),
                    rmse(test$logzinc, p_krig))
}
 
round(rmse_cv, 4)
##       Closest    IDW     NN Ensemble Kriging
## fold1  0.6327 0.5496 0.4958   0.4702  0.4281
## fold2  0.5987 0.5828 0.4943   0.4718  0.4183
## fold3  0.6328 0.7843 0.6516   0.6330  0.5055
## fold4  0.4874 0.6333 0.5316   0.4907  0.4198
## fold5  0.5593 0.6293 0.4791   0.4768  0.3840
hasil <- data.frame(metode    = metode,
                    rmse_rata = colMeans(rmse_cv),
                    rmse_sd   = apply(rmse_cv, 2, sd)) %>%
  arrange(rmse_rata)
hasil
##            metode rmse_rata    rmse_sd
## Kriging   Kriging 0.4311590 0.04487027
## Ensemble Ensemble 0.5085005 0.07005186
## NN             NN 0.5304872 0.07039087
## Closest   Closest 0.5821996 0.06101586
## IDW           IDW 0.6358382 0.08991205
ggplot(hasil, aes(x = reorder(metode, rmse_rata), y = rmse_rata)) +
  geom_col(fill = "grey35", width = 0.6) +
  geom_errorbar(aes(ymin = rmse_rata - rmse_sd, ymax = rmse_rata + rmse_sd),
                width = 0.15) +
  geom_text(aes(label = round(rmse_rata, 3)), vjust = -0.6, hjust = 1.4) +
  labs(x = NULL, y = "RMSE rata-rata 5-fold CV (skala log zinc)") +
  theme_bw()

Berdasarkan hasil evaluasi 5-fold Cross Validation pada data meuse (skala log zinc), diperoleh nilai rata-rata Root Mean Square Error (RMSE) dan simpangan baku untuk masing-masing metode interpolasi sebagai berikut:

  • Kriging (RMSE Rata-rata: 0.4312, SD: 0.0449)
    Interpretasi: Metode Kriging menghasilkan nilai RMSE rata-rata paling kecil dibanding seluruh metode lainnya. Hal ini menunjukkan bahwa Kriging memberikan tingkat akurasi prediksi yang paling tinggi dan stabil (memiliki deviasi standar terendah). Keunggulan ini terjadi karena Kriging memperhitungkan struktur spasial secara geostatistik melalui analisis variogram.

  • Ensemble (RMSE Rata-rata: 0.5085, SD: 0.0701)
    Interpretasi: Metode Ensemble menduduki peringkat kedua terbaik. Penggabungan beberapa model terbukti mampu memperbaiki performa dibandingkan sebagian besar metode tunggal (seperti NN, Closest, dan IDW), memberikan alternatif prediktor yang cukup handal dan seimbang.

  • Nearest Neighbor / NN (RMSE Rata-rata: 0.5305, SD: 0.0704)
    Interpretasi: Metode NN berada di posisi menengah, menunjukkan performa yang lebih baik daripada IDW dan Closest Observation, namun masih kalah akurat dibandingkan pendekatan geostatistik (Kriging) dan Ensemble.

  • Closest Observation (RMSE Rata-rata: 0.5822, SD: 0.0610)
    Interpretasi: Metode ini hanya mengambil pengamatan terdekat tanpa mempertimbangkan tren jarak bobot yang lebih luas atau struktur spasial, sehingga menghasilkan error yang lebih tinggi.

  • IDW / Inverse Distance Weighting (RMSE Rata-rata: 0.6358, SD: 0.0891)
    Interpretasi: IDW mencatatkan nilai RMSE rata-rata tertinggi dan variasi error (SD) yang paling besar di antara kelima metode. Hal ini mengindikasikan bahwa untuk sebaran data meuse ini, IDW kurang optimal dalam menangkap variasi spasial kadar zinc dibandingkan metode lainnya.

Kesimpulan: Secara keseluruhan, Kriging adalah metode interpolasi terbaik untuk dataset meuse pada pengujian ini karena menghasilkan error terkecil dan paling konsisten di setiap fold pengujian.