Tugas Praktikum Regspas 9

Persiapan Data

Library

library(sp)        # data 'meuse'
library(sf)        # objek spasial (sf)
library(terra)     # raster & voronoi
library(gstat)     # IDW, NN, variogram, kriging
library(dismo)     # kfold
library(automap)   # autofit variogram
library(dplyr)
library(tidyr)
library(ggplot2)
library(viridis)
library(tmap)
library(patchwork) # menyusun beberapa peta
# Memuat data meuse
data(meuse)
data(meuse.riv)

# Konversi ke sf (koordinat x,y; CRS RD New = 28992)
d <- st_as_sf(meuse, coords = c("x", "y"), crs = 28992)

# Peubah yang diinterpolasi
d$vble <- d$zinc

# Convex hull dari titik pengamatan
map <- st_sf(geometry = st_convex_hull(st_union(d)))

# Konversi data sungai Meuse
riv_sf <- st_sf(geometry = st_sfc(st_linestring(meuse.riv), crs = 28992))

summary(d$zinc)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   113.0   198.0   326.0   469.7   674.5  1839.0
library(sf)
data(meuse.grid)   # reset ke data.frame asli
meuse.grid <- st_as_sf(meuse.grid, coords = c("x", "y"), crs = 28992)
# Fungsi bantu: titik prediksi -> raster -> peta ggplot
to_rast <- function(sf_obj, col) {
  rasterize(vect(sf_obj), grid, field = col, fun = "mean")
}
peta_rast <- function(r, judul, nama = "Zinc", lim = NULL) {
  df <- as.data.frame(r, xy = TRUE); names(df)[3] <- "val"
  ggplot(df, aes(x, y, fill = val)) + geom_raster() + coord_equal() +
    scale_fill_viridis(name = nama, limits = lim) +
    theme_bw() + ggtitle(judul) +
    theme(axis.title = element_blank(), axis.text = element_blank(),
          axis.ticks = element_blank())
}
lim_zinc <- range(d$zinc)   # skala warna sama untuk semua peta

Peta Data Zinc

bb <- st_bbox(d)   # kotak pembatas titik data

ggplot() +
  geom_sf(data = map, fill = "grey95", alpha = 0.5) +
  geom_sf(data = riv_sf, colour = "#9fc5e8", linewidth = 1) +
  geom_sf(data = d, aes(colour = vble), size = 2) +
  coord_sf(xlim = c(bb["xmin"], bb["xmax"]),
           ylim = c(bb["ymin"], bb["ymax"]),
           expand = TRUE) +
  scale_colour_viridis(name = "Zinc (ppm)") +
  theme_bw() + ggtitle("Sebaran Kadar Zinc di Data meuse")

Grid Raster

grid <- rast(map, nrows = 100, ncols = 100)
xy   <- xyFromCell(grid, 1:ncell(grid))
coop <- st_as_sf(as.data.frame(xy), coords = c("x", "y"), crs = st_crs(map))
coop <- st_filter(coop, map)

qtm(coop)

Metode Deterministik

Closest Observation (voronoi)

# Membuat diagram Voronoi dari lokasi properti
v <- voronoi(x = vect(d), bnd = map)
plot(v)
# Menampilkan diagram Voronoi dengan harga properti
points(vect(d), cex = 0.5)

# Prediction
v <- st_as_sf(v)
tm_shape(v) + tm_fill(col = "vble", palette = "viridis", alpha = 0.6)

resp <- st_intersection(v, coop)
resp$pred <- resp$vble
pred <- rasterize(resp, grid, field = "pred", fun = "mean")
c1<-tm_shape(pred) + tm_raster(alpha = 0.6, palette = "viridis")

# Tampilkan peta
c1

Nearest Neighbors

res <- gstat(formula = vble ~ 1, locations = d, nmax = 5, set = list(idp = 0))

resp <- predict(res, coop)
## [inverse distance weighted interpolation]
resp$x <- st_coordinates(resp)[,1]
resp$y <- st_coordinates(resp)[,2]

resp$pred <- resp$var1.pred

pred <- rasterize(resp, grid, field = "pred", fun = "mean")
c3<-tm_shape(pred) + tm_raster(alpha = 0.6, palette = "viridis")
c3

Invers Distance Weight

library(gstat)

# Menerapkan IDW menggunakan semua lokasi properti
res <- gstat(formula = vble ~ 1, locations = d, nmax = nrow(d), set = list(idp = 1))

# Mendapatkan prediksi harga untuk lokasi yang belum teramati
resp <- predict(res, coop)
## [inverse distance weighted interpolation]
resp$x <- st_coordinates(resp)[,1]
resp$y <- st_coordinates(resp)[,2]
resp$pred <- resp$var1.pred

# Membuat peta prediksi harga dengan metode IDW
pred <- rasterize(resp, grid, field = "pred", fun = "mean")
c2<-tm_shape(pred) + tm_raster(alpha = 0.6, palette = "viridis")

# Tampilkan peta
c2

Pendekatan ensambel

#Closestobservation(Voronoi)
v<-voronoi(x=vect(d),bnd= map)
v<-st_as_sf(v)
p1<-st_intersection(v,coop)$vble

#IDW
gs<-gstat(formula=vble~1,locations= d,nmax= nrow(d),
set= list(idp=1))
p2<-predict(gs,coop)$var1.pred
## [inverse distance weighted interpolation]
#Nearestneighbors
nn<-gstat(formula=vble~1,locations= d,nmax= 5,
set= list(idp=0))
p3<-predict(nn,coop)$var1.pred
## [inverse distance weighted interpolation]
#Ensemble(equalweights)
weights<-c(1/3,1/3,1/3)
p4<-p1*weights[1]+p2*weights[2]+p3*weights[3]
resp<-data.frame(x=st_coordinates(coop)[,1], y=st_coordinates(coop)[,2], pred=p4)

resp<-st_as_sf(resp,coords= c("x","y"),crs= st_crs(map))
pred<-rasterize(resp,grid, field= "pred",fun= "mean")
c4<-tm_shape(pred)+tm_raster(alpha= 0.6,palette="viridis")
c4

# Gabungkan semua plot dalam satu frame
tmap_arrange(c1, c2, c3, c4, ncol = 2)

Metode Stikastik

kringing

Eksplorasi Variogram

# Variogram Cloud

# Variogram dengan cloud plot
vc <- variogram(log(zinc) ~ 1, d, cloud = TRUE)
plot(vc)

# Variogram dengan plot standar
v <- variogram(log(zinc) ~ 1, data = d)
plot(v)

Pemodelan Variogram

# Menentukan model variogram awal dengan parameter psill, model, range, dan nugget
vinitial <- vgm(psill = 0.5, model = "Sph", range = 900, nugget = 0.1)

# Memvisualisasikan variogram dengan model awal (vinitial) dan batas cutoff 1000
plot(v, vinitial, cutoff = 1000, cex = 1.5)

# Menyesuaikan variogram dengan model "Sph" menggunakan data v dan parameter
fv<-fit.variogram(object=v,model= vgm(psill= 0.5,model= "Sph",range= 900,nugget= 0.1))
fv
##   model      psill    range
## 1   Nug 0.05066017   0.0000
## 2   Sph 0.59060556 897.0044
plot(v,fv, cex= 1.5)

Autofit Variogram

library(automap)
# Autofit variogram untuk data log-zinc
afvg <- autofitVariogram(log(zinc) ~ 1, d)

# Plot hasil
plot(afvg)

Interpolasi Kringing

library(ggplot2)
library(viridis)
# Membuat objek gstat dengan model variogram hasil fitting (fv) untuk data zinc
k <- gstat(formula = log(zinc) ~ 1, data = d, model = fv)

# Melakukan prediksi variabel pada grid menggunakan model gstat yang sudah dibuat
kpred <- predict(k, meuse.grid)
## [using ordinary kriging]

Visualisasi

k     <- gstat(formula = log(zinc) ~ 1, data = d, model = fv)
kpred <- predict(k, coop, debug.level = 0)

# Transformasi balik ke skala zinc agar sebanding dengan metode lain
kpred$pred <- exp(kpred$var1.pred + kpred$var1.var / 2)

ggplot() +
  geom_sf(data = kpred, aes(colour = var1.pred)) +
  geom_sf(data = d, shape = 4) +
  scale_colour_viridis(name = "Prediksi\nlog(zinc)") +
  theme_bw() + ggtitle("Peta Prediksi Kriging (skala log)")

# Peta Varians
ggplot() +
  geom_sf(data = kpred, aes(colour = var1.var)) +
  geom_sf(data = d, shape = 4) +
  scale_colour_viridis(name = "Varians") +
  theme_bw() + ggtitle("Peta Varians Kriging")

pred_kriging <- to_rast(kpred, "pred")
c5 <- peta_rast(pred_kriging, "Kriging (back-transform)", lim = lim_zinc)
c5

Interpretasi Peta

Pola umum sebaran zinc serupa pada semua metode: konsentrasi tinggi berada di dekat sungai Meuse dan menurun menjauhi sungai. Perbedaan utama ada pada tingkat kehalusan. Closest Observation menghasilkan peta paling kasar dengan batas tegas antar poligon Voronoi. IDW dan NN lebih halus karena memakai beberapa tetangga. NN dengan k = 5 memberi pola yang lebih “berbintik” dibanding IDW. Ensemble tampil sebagai kompromi dari ketiga metode.

Kriging memberi gradasi yang paling halus dan kontinu karena bobot tetangga ditentukan oleh struktur variogram.

Evaluasi

set.seed(123)

# Fungsi untuk menghitung RMSE
RMSE <- function(observed, predicted) {
  sqrt(mean((observed - predicted)^2))
}

# Pembagian data untuk K-fold
kf <- kfold(nrow(d), k = 5)

# Vectors to store the RMSE values obtained with each method
rmse1 <- rep(NA, 5) # Closest observation
rmse2 <- rep(NA, 5) # IDW
rmse3 <- rep(NA, 5) # Nearest neighbors
rmse4 <- rep(NA, 5) # Ensemble
rmse5 <- rep(NA, 5)
for(k in 1:5){
#Splitdataintest andtrain
test<-d[kf== k,]
train<-d[kf !=k,]


#Closestobservation
v<-voronoi(x=vect(train), bnd= map)
v<-st_as_sf(v)
p1<-st_intersection(v,test)$vble
rmse1[k] <-RMSE(test$vble,p1)

#IDW
gs<-gstat(formula=vble ~1,locations= train,
nmax=nrow(train), set= list(idp=1))
p2 <-predict(gs,test)$var1.pred
rmse2[k] <-RMSE(test$vble,p2)

#Nearestneighbors
nn<-gstat(formula=vble~1,locations= train,
nmax=5,set= list(idp=0))
p3 <-predict(nn,test)$var1.pred
rmse3[k] <-RMSE(test$vble,p3)

#Ensemble(weightsareinverseRMSEsolowerRMSEhigherweight)
w<-1/c(rmse1[k],rmse2[k],rmse3[k])
weights<-w/sum(w)
p4<-p1*weights[1]+p2*weights[2]+p3*weights[3]
rmse4[k] <-RMSE(test$vble,p4)

#Kringing
train_sp <- as(train, "Spatial") 
  afvg_train <- autofitVariogram(log(zinc) ~ 1, train_sp)
  
  k_train <- gstat(formula = log(zinc) ~ 1, data = train, 
                   model = afvg_train$var_model)
  p5_log <- predict(k_train, test)$var1.pred
  
  p5_back <- exp(p5_log)
  
  rmse5[k] <- RMSE(test$vble, p5_back)
}
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
# Hasil RMSE
data.frame(closest.obs= rmse1,IDW= rmse2,
nearest.neigh= rmse3,ensemble= rmse4, Kringing=rmse5)
##   closest.obs      IDW nearest.neigh ensemble Kringing
## 1    309.9009 282.3744      265.3339 250.9364 190.2728
## 2    385.8027 277.6231      275.7933 260.7226 221.7091
## 3    323.5046 438.7651      364.2145 337.4435 325.1786
## 4    237.6379 323.2493      255.5252 242.7105 207.8869
## 5    299.4034 329.9387      294.7488 281.7473 249.2541
# Rata rata RMSE
data.frame(
  closest.obs = mean(rmse1), 
  IDW = mean(rmse2), 
  nearest.neigh = mean(rmse3),
  kringing = mean(rmse5),
  ensemble = mean(rmse4))
##   closest.obs      IDW nearest.neigh kringing ensemble
## 1    311.2499 330.3901      291.1231 238.8603 274.7121

Kesimpulan

Berdasarkan RMSE rata-rata 5-fold cross-validation, metode terbaik adalah Kringing (RMSE = 238.86), diikuti Ensemble (RMSE = 274.71) dan Nearest Neighbors (k-NN) (RMSE = 291.12) serta Closest Observation (RMSE = 311.25). Metode dengan error terbesar adalah IDW (RMSE = 330.39).