Tugas Regresi Spasial Praktikum 9
Persiapan Data
## Linking to GEOS 3.14.1, GDAL 3.12.1, PROJ 9.7.1; sf_use_s2() is TRUE
## terra 1.9.34
## Loading required package: raster
## Loading required package: viridisLite
data(meuse)
data(meuse.grid)
# Mengubah data menjadi sf
meuse <- st_as_sf(meuse, coords = c("x", "y"), crs = 28992)
meuse.grid <- st_as_sf(meuse.grid, coords = c("x", "y"), crs = 28992)
# Data pengamatan
d <- meuse
# Titik yang akan diprediksi
coop <- meuse.grid
# Memberikan ID pada setiap titik prediksi
coop$id <- seq_len(nrow(coop))
# Membuat batas wilayah yang mencakup data pengamatan dan seluruh titik prediksi
map <- st_as_sfc(
st_bbox(
st_union(c(st_geometry(d), st_geometry(coop)))
)
) |> st_sf()
# Membuat raster template
grid <- rast(
ext(vect(map)),
resolution = 40,
crs = "EPSG:28992"
)Eksplorasi Data
Persebaran Kandungan Timbal (Lead)
tm_shape(d) +
tm_dots(
col = "lead",
palette = "viridis",
size = 0.3,
title = "Lead"
) +
tm_layout(
title = "Persebaran Kandungan Lead",
legend.outside = TRUE
)##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_dots()`: migrate the argument(s) related to the scale of the
## map variable `fill` namely 'palette' (rename to 'values') to fill.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_dots()`: use 'fill' for the fill color of polygons/symbols
## (instead of 'col'), and 'col' for the outlines (instead of 'border.col').
## [tm_dots()] Argument `title` unknown.
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Lokasi Data Pengamatan dan Titik Prediksi
tm_shape(map) +
tm_borders(col = "black") +
tm_shape(coop) +
tm_dots(
col = "grey70",
size = 0.02,
alpha = 0.5
) +
tm_shape(d) +
tm_dots(
col = "lead",
palette = "viridis",
size = 0.3,
title = "Lead"
) +
tm_layout(
title = "Lokasi Data Pengamatan dan Titik Prediksi",
legend.outside = TRUE
)##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_dots()`: use `fill_alpha` instead of `alpha`.
## [tm_dots()] Argument `title` unknown.
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
## [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.
Statistik Deskriptif
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 37.0 72.5 123.0 153.4 207.0 654.0
## [1] 111.3201
## [1] 12392.15
Closest Observation
Metode Closest Observation menggunakan diagram Voronoi. Setiap lokasi prediksi memperoleh nilai dari titik pengamatan yang berada pada wilayah Voronoi yang memuat lokasi tersebut.
# Membuat diagram Voronoi
v <- terra::voronoi(
x = vect(d),
bnd = vect(map)
)
# Mengubah menjadi sf
v <- st_as_sf(v)
# Menampilkan diagram Voronoi
tm_shape(v) +
tm_fill(
col = "lead",
palette = "viridis",
alpha = 0.6
) +
tm_layout(title = "Closest Observation - Lead")##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_polygons()`: migrate the argument(s) related to the scale of
## the map variable `fill` namely 'palette' (rename to 'values') to fill.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_polygons()`: use `fill_alpha` instead of `alpha`.
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
# Menyimpan hasil prediksi
resp_co$pred <- resp_co$lead
# Membuat raster hasil prediksi
pred_co <- rasterize(
vect(resp_co),
grid,
field = "pred",
fun = "mean"
)
c1 <- tm_shape(pred_co) +
tm_raster(
alpha = 0.6,
palette = "viridis",
title = "Prediksi Lead"
) +
tm_layout(title = "Closest Observation")##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_raster()`: migrate the argument(s) related to the scale of the
## map variable `col` namely 'palette' (rename to 'values') to col.scale =
## tm_scale(<HERE>).[v3->v4] `tm_raster()`: use `col_alpha` instead of `alpha`.[v3->v4] `tm_raster()`: migrate the argument(s) related to the legend of the
## map variable `col` namely 'title' to 'col.legend = tm_legend(<HERE>)'[v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Inverse Distance Weighting (IDW)
# Membentuk model IDW
gs <- gstat(
formula = lead ~ 1,
locations = d,
nmax = nrow(d),
set = list(idp = 1)
)
# Melakukan prediksi
resp_idw <- predict(gs, coop)## [inverse distance weighted interpolation]
# Menyimpan hasil prediksi
resp_idw$pred <- resp_idw$var1.pred
# Membuat raster hasil prediksi
pred_idw <- rasterize(
vect(resp_idw),
grid,
field = "pred",
fun = "mean"
)
c2 <- tm_shape(pred_idw) +
tm_raster(
alpha = 0.6,
palette = "viridis",
title = "Prediksi Lead"
) +
tm_layout(title = "Inverse Distance Weighting")##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_raster()`: migrate the argument(s) related to the scale of the
## map variable `col` namely 'palette' (rename to 'values') to col.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_raster()`: use `col_alpha` instead of `alpha`.
## [v3->v4] `tm_raster()`: migrate the argument(s) related to the legend of the
## map variable `col` namely 'title' to 'col.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Nearest Neighbors
Metode Nearest Neighbors menggunakan lima titik pengamatan terdekat.
Dengan idp = 0, bobot setiap titik tetangga dibuat
sama.
# Membentuk model Nearest Neighbors
nn <- gstat(
formula = lead ~ 1,
locations = d,
nmax = 5,
set = list(idp = 0)
)
# Melakukan prediksi
resp_nn <- predict(nn, coop)## [inverse distance weighted interpolation]
# Menyimpan hasil prediksi
resp_nn$pred <- resp_nn$var1.pred
# Membuat raster hasil prediksi
pred_nn <- rasterize(
vect(resp_nn),
grid,
field = "pred",
fun = "mean"
)
c3 <- tm_shape(pred_nn) +
tm_raster(
alpha = 0.6,
palette = "viridis",
title = "Prediksi Lead"
) +
tm_layout(title = "Nearest Neighbors")##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_raster()`: migrate the argument(s) related to the scale of the
## map variable `col` namely 'palette' (rename to 'values') to col.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_raster()`: use `col_alpha` instead of `alpha`.
## [v3->v4] `tm_raster()`: migrate the argument(s) related to the legend of the
## map variable `col` namely 'title' to 'col.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Ensemble
Metode Ensemble menggabungkan hasil prediksi dari Closest Observation, IDW, dan Nearest Neighbors dengan bobot yang sama, yaitu masing-masing sepertiga (1/3)
# Menentukan bobot yang sama
weights <- c(1/3, 1/3, 1/3)
# Closest Observation
# Mencocokkan prediksi berdasarkan ID titik prediksi
v2 <- v
v2$pred_co <- v2$lead
resp_co_ensemble <- st_intersection(
v2["pred_co"],
coop["id"]
)## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
p1 <- resp_co_ensemble$pred_co[
match(coop$id, resp_co_ensemble$id)
]
# IDW
gs <- gstat(
formula = lead ~ 1,
locations = d,
nmax = nrow(d),
set = list(idp = 1)
)
p2 <- predict(gs, coop)$var1.pred## [inverse distance weighted interpolation]
# Nearest Neighbors
nn <- gstat(
formula = lead ~ 1,
locations = d,
nmax = 5,
set = list(idp = 0)
)
p3 <- predict(nn, coop)$var1.pred## [inverse distance weighted interpolation]
# Memastikan semua titik memperoleh prediksi
stopifnot(
length(p1) == nrow(coop),
!anyNA(p1),
!anyNA(p2),
!anyNA(p3)
)
# Menggabungkan hasil prediksi
p4 <- p1 * weights[1] +
p2 * weights[2] +
p3 * weights[3]
# Menyimpan hasil prediksi ke data titik
resp_ensemble <- coop
resp_ensemble$pred <- p4
# Membuat raster hasil prediksi
pred_ensemble <- rasterize(
vect(resp_ensemble),
grid,
field = "pred",
fun = "mean"
)
c4 <- tm_shape(pred_ensemble) +
tm_raster(
alpha = 0.6,
palette = "viridis",
title = "Prediksi Lead"
) +
tm_layout(title = "Ensemble")##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_raster()`: migrate the argument(s) related to the scale of the
## map variable `col` namely 'palette' (rename to 'values') to col.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_raster()`: use `col_alpha` instead of `alpha`.
## [v3->v4] `tm_raster()`: migrate the argument(s) related to the legend of the
## map variable `col` namely 'title' to 'col.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Kriging
Menghitung Experimental Variogram
# Menghitung experimental variogram
v_kriging <- variogram(lead ~ 1, d)
# Menampilkan experimental variogram
plot(
v_kriging,
main = "Experimental Variogram Lead"
)Fitting Model Variogram
Model variogram yang digunakan adalah Spherical. Nilai awal sill dan nugget ditentukan berdasarkan varians data lead, sedangkan range awal ditetapkan sebesar 900 meter.
# Menentukan nilai awal berdasarkan varians lead
nilai_var <- var(d$lead)
# Menyesuaikan model variogram Spherical
fv <- fit.variogram(
object = v_kriging,
model = vgm(
psill = 0.8 * nilai_var,
model = "Sph",
range = 900,
nugget = 0.2 * nilai_var
)
)
# Menampilkan hasil fitting
fv## model psill range
## 1 Nug 3024.205 0.0000
## 2 Sph 12412.918 906.6834
# Menampilkan plot experimental variogram dan model
plot(
v_kriging,
fv,
main = "Fitting Variogram Lead"
)Membentuk Model Ordinary Kriging dan Prediksi
# Membentuk model Ordinary Kriging
model_kriging <- gstat(
formula = lead ~ 1,
data = d,
model = fv
)
# Melakukan prediksi pada titik prediksi
kpred <- predict(model_kriging, coop)## [using ordinary kriging]
# Menyimpan hasil prediksi
kpred$pred <- kpred$var1.pred
# Membuat raster hasil prediksi
pred_kriging <- rasterize(
vect(kpred),
grid,
field = "pred",
fun = "mean"
)
c5 <- tm_shape(pred_kriging) +
tm_raster(
alpha = 0.6,
palette = "viridis",
title = "Prediksi Lead"
) +
tm_layout(title = "Ordinary Kriging")##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_raster()`: migrate the argument(s) related to the scale of the
## map variable `col` namely 'palette' (rename to 'values') to col.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_raster()`: use `col_alpha` instead of `alpha`.
## [v3->v4] `tm_raster()`: migrate the argument(s) related to the legend of the
## map variable `col` namely 'title' to 'col.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Varians Prediksi Kriging
# Menyimpan varians prediksi
kpred$varians <- kpred$var1.var
# Membuat raster varians prediksi
var_kriging <- rasterize(
vect(kpred),
grid,
field = "varians",
fun = "mean"
)
tm_shape(var_kriging) +
tm_raster(
palette = "viridis",
title = "Varians"
) +
tm_layout(
title = "Varians Prediksi Kriging",
legend.outside = TRUE
)##
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_raster()`: migrate the argument(s) related to the scale of the
## map variable `col` namely 'palette' (rename to 'values') to col.scale =
## tm_scale(<HERE>).
## [v3->v4] `tm_raster()`: migrate the argument(s) related to the legend of the
## map variable `col` namely 'title' to 'col.legend = tm_legend(<HERE>)'
## [v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`
Perbandingan Peta Hasil Interpolasi
## [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.
Cross Validation
Cross Validation dilakukan menggunakan 5-Fold Cross Validation. Pada setiap iterasi, empat fold digunakan sebagai data training dan satu fold digunakan sebagai data testing. Evaluasi dilakukan menggunakan Root Mean Square Error (RMSE).
Persiapan Cross Validation
# Menentukan seed
set.seed(123)
# Fungsi RMSE
RMSE <- function(observed, predicted) {
sqrt(mean((observed - predicted)^2))
}
# Membagi data menjadi 5 fold
kf <- dismo::kfold(nrow(d), k = 5)
# Menyimpan nilai RMSE setiap metode
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) # KrigingProses 5-Fold Cross Validation
for(k in 1:5){
# Membagi data training dan testing
test <- d[kf == k, ]
train <- d[kf != k, ]
# Memberikan ID pada data testing
test$id <- seq_len(nrow(test))
# 1. Closest Observation
v_cv <- terra::voronoi(
x = vect(train),
bnd = vect(map)
)
v_cv <- st_as_sf(v_cv)
# Menyimpan nilai lead sebagai prediksi
v_cv$pred_co <- v_cv$lead
# Mengambil prediksi pada lokasi data testing
resp_cv <- st_intersection(
v_cv["pred_co"],
test["id"]
)
# Mencocokkan prediksi berdasarkan ID data testing
p1 <- resp_cv$pred_co[
match(test$id, resp_cv$id)
]
# Memastikan seluruh data testing memperoleh prediksi
stopifnot(
length(p1) == nrow(test),
!anyNA(p1)
)
rmse1[k] <- RMSE(test$lead, p1)
# 2. IDW
gs <- gstat(
formula = lead ~ 1,
locations = train,
nmax = nrow(train),
set = list(idp = 1)
)
p2 <- predict(gs, test)$var1.pred
rmse2[k] <- RMSE(test$lead, p2)
# 3. Nearest Neighbors
nn <- gstat(
formula = lead ~ 1,
locations = train,
nmax = 5,
set = list(idp = 0)
)
p3 <- predict(nn, test)$var1.pred
rmse3[k] <- RMSE(test$lead, p3)
# 4. Ensemble (Equal Weights)
weights <- c(1/3, 1/3, 1/3)
p4 <- p1 * weights[1] +
p2 * weights[2] +
p3 * weights[3]
rmse4[k] <- RMSE(test$lead, p4)
# 5. Kriging
vgram <- variogram(lead ~ 1, train)
nilai_var_train <- var(train$lead)
fv_cv <- fit.variogram(
object = vgram,
model = vgm(
psill = 0.8 * nilai_var_train,
model = "Sph",
range = 900,
nugget = 0.2 * nilai_var_train
)
)
model_kriging_cv <- gstat(
formula = lead ~ 1,
data = train,
model = fv_cv
)
p5 <- predict(model_kriging_cv, test)$var1.pred
rmse5[k] <- RMSE(test$lead, p5)
}## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
## [inverse distance weighted interpolation]
## [inverse distance weighted interpolation]
## [using ordinary kriging]
RMSE Setiap Fold
hasil_rmse <- data.frame(
Fold = 1:5,
Closest_Observation = rmse1,
IDW = rmse2,
Nearest_Neighbors = rmse3,
Ensemble = rmse4,
Kriging = rmse5
)
hasil_rmse## Fold Closest_Observation IDW Nearest_Neighbors Ensemble Kriging
## 1 1 105.11729 81.66033 81.45935 78.82838 71.46859
## 2 2 128.23290 92.91140 95.95009 94.40308 88.59842
## 3 3 109.12659 147.16314 127.58901 121.44324 112.53338
## 4 4 74.41817 90.20712 75.37686 68.78230 66.52148
## 5 5 81.93270 84.51001 69.80773 69.93459 62.85488
Rata-rata RMSE Setiap Metode
rata_rmse <- data.frame(
Metode = c(
"Closest Observation",
"IDW",
"Nearest Neighbors",
"Ensemble",
"Kriging"
),
RMSE = c(
mean(rmse1),
mean(rmse2),
mean(rmse3),
mean(rmse4),
mean(rmse5)
)
)
# Mengurutkan metode berdasarkan RMSE terkecil
rata_rmse <- rata_rmse[
order(rata_rmse$RMSE),
]
rata_rmse## Metode RMSE
## 5 Kriging 80.39535
## 4 Ensemble 86.67831
## 3 Nearest Neighbors 90.03661
## 2 IDW 99.29040
## 1 Closest Observation 99.76553
Metode Kriging merupakan metode yang paling baik untuk mengestimasi nilai lead pada data meuse karena menghasilkan nilai RMSE paling kecil. Sementara itu, metode Closest Observation menghasilkan RMSE terbesar, sehingga memiliki tingkat kesalahan prediksi paling tinggi. Metode Ensemble juga menunjukkan hasil yang cukup baik karena menempati posisi kedua setelah Kriging