TUGAS PRAKTIKUM 2
1. Library
2. Memuat Data
Variabel yang diinterpolasi: zinc (konsentrasi seng pada tanah).
data(meuse) # 155 titik observasi
data(meuse.grid) # grid lokasi yang akan diprediksi
# Konversi ke objek sf (CRS: Amersfoort / RD New = EPSG 28992)
meuse_sf <- st_as_sf(meuse, coords = c("x", "y"), crs = 28992, remove = FALSE)
grid_sf <- st_as_sf(meuse.grid, coords = c("x", "y"), crs = 28992, remove = FALSE)
head(meuse_sf)## Simple feature collection with 6 features and 14 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 181025 ymin: 333260 xmax: 181390 ymax: 333611
## Projected CRS: Amersfoort / RD New
## x y cadmium copper lead zinc elev dist om ffreq soil lime
## 1 181072 333611 11.7 85 299 1022 7.909 0.00135803 13.6 1 1 1
## 2 181025 333558 8.6 81 277 1141 6.983 0.01222430 14.0 1 1 1
## 3 181165 333537 6.5 68 199 640 7.800 0.10302900 13.0 1 1 1
## 4 181298 333484 2.6 81 116 257 7.655 0.19009400 8.0 1 2 0
## 5 181307 333330 2.8 48 117 269 7.480 0.27709000 8.7 1 2 0
## 6 181390 333260 3.0 61 137 281 7.791 0.36406700 7.8 1 2 0
## landuse dist.m geometry
## 1 Ah 50 POINT (181072 333611)
## 2 Ah 30 POINT (181025 333558)
## 3 Ah 150 POINT (181165 333537)
## 4 Ga 270 POINT (181298 333484)
## 5 Ah 380 POINT (181307 333330)
## 6 Ga 470 POINT (181390 333260)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 113.0 198.0 326.0 469.7 674.5 1839.0
3. Eksplorasi Data
ggplot(meuse_sf) +
geom_sf(aes(color = zinc), size = 2.5) +
scale_color_viridis_c(option = "C") +
labs(title = "Sebaran Observasi Zinc (Meuse)", color = "Zinc (ppm)") +
theme_minimal()
Dari grafik di atas, dapat diketahui bahwa data berbentuk skewed ke
kanan. - Sebagian besar lokasi punya kadar zinc relatif rendah,
kira-kira di bawah 500 ppm. - Sebagian kecil lokasi punya kadar sangat
tinggi (di atas 1.200 ppm), yang kemungkinan besar adalah titik-titik
yang dekat dengan sungai atau sumber pencemar. Frekuensinya hanya 1-3
titik per kelas, jadi bisa dianggap pencilan atau nilai ekstrem. -
Rata-rata (mean) akan lebih besar dari median karena tertarik oleh
nilai-nilai ekstrem di ekor kanan.
4. Fungsi Prediksi untuk Setiap Metode
Satu fungsi dipakai untuk semua metode agar bisa dipakai untuk peta dan cross validation.
- Closest Observation: nilai prediksi = nilai titik terdekat (1 tetangga).
- NN (Nearest Neighbour): rata-rata
ktetangga terdekat (bobot sama,idp = 0). - IDW: Inverse Distance Weighting dengan power
idp = 2. - Kriging: Ordinary Kriging dengan model variogram hasil fitting.
# Variogram empiris
v_emp <- variogram(zinc ~ 1, meuse_sf)
# Fitting model variogram (spherical)
sill_awal <- max(v_emp$gamma)
v_fit <- fit.variogram(
v_emp,
model = vgm(psill = 0.7 * sill_awal, model = "Sph",
range = 900, nugget = 0.3 * sill_awal)
)
v_fit## model psill range
## 1 Nug 24816.48 0.0000
## 2 Sph 134756.29 831.3829
Variogram zinc menunjukkan adanya autokorelasi spasial yang jelas:
semivariansi naik seiring bertambahnya jarak (titik yang berdekatan
memiliki nilai zinc yang mirip, sedangkan titik yang berjauhan semakin
berbeda), lalu mendatar pada sekitar 160.000 (sill) di jarak kira-kira
800 m (range), sehingga di luar jarak tersebut observasi dianggap tidak
lagi saling berkorelasi. Model spherical yang di-fit mengikuti
titik-titik empiris dengan cukup baik, dengan nilai nugget sekitar
25.000 yang menandakan adanya variasi pada skala sangat kecil atau galat
pengukuran. Efeknya pada interpolasi: struktur spasial yang kuat ini
membuat Kriging layak digunakan karena bobot tetangganya ditentukan oleh
pola variogram, bukan sekadar jarak seperti pada IDW, sehingga Kriging
cenderung menghasilkan RMSE yang lebih kecil. Hanya titik dalam radius
sekitar 800 m yang efektif berkontribusi pada prediksi, dan nugget yang
tidak nol membuat hasil Kriging sedikit lebih halus (smooth) dibanding
metode yang sekadar meniru nilai terdekat seperti Closest
Observation.
k_nn <- 5 # jumlah tetangga untuk NN
p_idw <- 2 # power IDW
pred_dasar <- function(train, test, metode) {
switch(metode,
closest = idw(zinc ~ 1, train, test, nmax = 1,
idp = 1, debug.level = 0)$var1.pred,
nn = idw(zinc ~ 1, train, test, nmax = k_nn,
idp = 0, debug.level = 0)$var1.pred,
idw = idw(zinc ~ 1, train, test,
idp = p_idw, debug.level = 0)$var1.pred,
kriging = krige(zinc ~ 1, train, test,
model = v_fit, debug.level = 0)$var1.pred
)
}
# Ensemble: rata-rata dari 3 metode (NN, IDW, Kriging)
metode_ensemble <- c("nn", "idw", "kriging")
pred_ensemble <- function(train, test) {
hasil <- sapply(metode_ensemble, function(m) pred_dasar(train, test, m))
if (is.null(dim(hasil))) hasil <- matrix(hasil, nrow = 1)
rowMeans(hasil)
}5. Interpolasi ke Seluruh Grid
hasil_grid <- data.frame(
x = meuse.grid$x,
y = meuse.grid$y,
Closest_Observation = pred_dasar(meuse_sf, grid_sf, "closest"),
NN = pred_dasar(meuse_sf, grid_sf, "nn"),
IDW = pred_dasar(meuse_sf, grid_sf, "idw"),
Kriging = pred_dasar(meuse_sf, grid_sf, "kriging")
)
# Ensemble = rata-rata NN, IDW, dan Kriging
hasil_grid$Ensemble <- rowMeans(hasil_grid[, c("NN", "IDW", "Kriging")])
head(hasil_grid)## x y Closest_Observation NN IDW Kriging Ensemble
## 1 181180 333740 1022 681.2 633.6864 762.1218 692.3361
## 2 181140 333700 1022 681.2 712.5450 823.7930 739.1793
## 3 181180 333700 1022 681.2 654.1617 758.4210 697.9276
## 4 181220 333700 640 681.2 604.4422 695.7806 660.4743
## 5 181100 333660 1022 681.2 857.2558 899.3148 812.5902
## 6 181140 333660 1022 681.2 755.5061 822.1090 752.9384
6. Visualisasi Peta Hasil Interpolasi
peta_long <- hasil_grid %>%
pivot_longer(cols = -c(x, y), names_to = "Metode", values_to = "Zinc") %>%
mutate(Metode = factor(Metode,
levels = c("Closest_Observation", "NN", "IDW", "Ensemble", "Kriging")))
ggplot(peta_long, aes(x = x, y = y, fill = Zinc)) +
geom_tile() +
coord_equal() +
facet_wrap(~ Metode, ncol = 3) +
scale_fill_viridis_c(option = "C") +
labs(title = "Hasil Interpolasi Zinc Berdasarkan Metode",
fill = "Zinc (ppm)", x = "X", y = "Y") +
theme_minimal()7. Cross Validation (Leave-One-Out)
Setiap titik dikeluarkan satu per satu, diprediksi menggunakan titik lainnya, lalu dibandingkan dengan nilai aslinya.
n <- nrow(meuse_sf)
metode_dasar <- c("closest", "nn", "idw", "kriging")
cv_pred <- matrix(NA, nrow = n, ncol = length(metode_dasar),
dimnames = list(NULL, metode_dasar))
for (i in 1:n) {
train <- meuse_sf[-i, ]
test <- meuse_sf[i, ]
for (m in metode_dasar) {
cv_pred[i, m] <- pred_dasar(train, test, m)
}
}
cv_df <- as.data.frame(cv_pred)
cv_df$ensemble <- rowMeans(cv_df[, metode_ensemble]) # NN, IDW, Kriging
cv_df$observasi <- meuse_sf$zinc
head(cv_df)## closest nn idw kriging ensemble observasi
## 1 1141 558.0 793.8598 890.6618 747.5072 1022
## 2 1022 702.0 727.3774 868.8288 766.0687 1141
## 3 1022 634.4 605.2803 661.2713 633.6505 640
## 4 640 511.6 477.0037 465.8510 484.8182 257
## 5 281 269.2 368.8423 268.9481 302.3301 269
## 6 269 248.8 347.1991 235.1268 277.0420 281
8. Perhitungan dan Perbandingan RMSE
rmse <- function(obs, pred) sqrt(mean((obs - pred)^2))
tabel_rmse <- data.frame(
Metode = c("Closest Observation", "NN", "IDW", "Ensemble", "Kriging"),
RMSE = c(rmse(cv_df$observasi, cv_df$closest),
rmse(cv_df$observasi, cv_df$nn),
rmse(cv_df$observasi, cv_df$idw),
rmse(cv_df$observasi, cv_df$ensemble),
rmse(cv_df$observasi, cv_df$kriging))
) %>%
arrange(RMSE)
tabel_rmse## Metode RMSE
## 1 Kriging 224.7995
## 2 Ensemble 247.1178
## 3 NN 263.9874
## 4 IDW 278.2734
## 5 Closest Observation 309.9685
Berdasarkan niali RMSE yang didapatkan, Kriging merupakan metode terbaik (RMSE = 224,80), diikuti Ensemble (247,12), NN (263,99), IDW (278,27), dan Closest Observation (309,97). Hal ini menunjukkan bahwa pemanfaatan struktur autokorelasi spasial melalui variogram memberikan prediksi yang lebih akurat dibandingkan metode yang hanya mempertimbangkan jarak.
ggplot(tabel_rmse, aes(x = reorder(Metode, RMSE), y = RMSE, fill = Metode)) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = round(RMSE, 2)), vjust = -0.4) +
labs(title = "Perbandingan RMSE (Leave-One-Out Cross Validation)",
x = "Metode", y = "RMSE") +
theme_minimal()cv_df %>%
pivot_longer(cols = c(closest, nn, idw, ensemble, kriging),
names_to = "Metode", values_to = "Prediksi") %>%
ggplot(aes(x = observasi, y = Prediksi)) +
geom_point(alpha = 0.6) +
geom_abline(slope = 1, intercept = 0, color = "red") +
facet_wrap(~ Metode) +
labs(title = "Observasi vs Prediksi (LOOCV)",
x = "Observasi", y = "Prediksi") +
theme_minimal()9. Kesimpulan
terbaik <- tabel_rmse$Metode[1]
cat("Metode dengan RMSE terkecil:", terbaik,
"dengan RMSE =", round(tabel_rmse$RMSE[1], 2), "\n")## Metode dengan RMSE terkecil: Kriging dengan RMSE = 224.8
Berdasarkan hasil Leave-One-Out Cross Validation, Kriging merupakan metode interpolasi terbaik untuk data zinc pada meuse dengan RMSE terkecil (224,80), diikuti Ensemble (247,12), NN (263,99), IDW (278,27), dan Closest Observation (309,97). Keunggulan Kriging disebabkan oleh adanya autokorelasi spasial yang kuat pada variogram, yang dimanfaatkan untuk menentukan bobot tetangga secara lebih tepat dibanding metode yang hanya mempertimbangkan jarak. Ensemble mampu mengungguli NN dan IDW, tetapi tidak mengungguli Kriging, sehingga penggabungan metode tidak memberi perbaikan ketika salah satu komponennya jauh lebih akurat. Dengan demikian, Kriging direkomendasikan untuk menginterpolasi zinc pada data ini.