BAB I PENDAHULUAN

Latar Belakang

Analisis pola titik spasial menjadi alat penting dalam penelitian keruangan untuk memahami bagaimana objek-titik tersebar di ruang geografis dan bagaimana pola tersebut terbentuk. Titik-titik ini bisa berupa lokasi fasilitas publik, lokasi titik api, ataupun kejadian kejadian spasial lainnya yang dapat dimapping secara koordinat. Melalui analisis ini, peneliti dapat membedakan apakah sebaran titik bersifat acak (random), seragam (uniform), atau mengelompok (clustered), yang masing-masing memiliki implikasi terhadap proses spasial yang mendasarinya (Piani, Dwinata & Mandefa, 2023).

Metodologi analisis pola titik spasial sering menggunakan perangkat lunak SIG/GIS dan teknik statistik spasial seperti analisis tetangga terdekat (nearest neighbor), indeks autokorelasi spasial, atau estimasi kerapatan titik (kernel density). Contohnya, penelitian tentang sebaran SPBU di Kota Jakarta Timur menemukan bahwa lokasi-lokasi SPBU cenderung membentuk pola pengelompokan (cluster) dan jarak antar titik relatif dekat satu sama lain (Piani, Dwinata & Mandefa, 2023).

Pentingnya analisis pola titik spasial di Indonesia juga terlihat dalam konteks kebencanaan dan lingkungan, misalnya dalam pemetaan titik api atau hotspot kebakaran hutan yang menunjukkan pola pengelompokan di wilayah tertentu (Ballo, 2023). Hasil-hasil semacam ini membantu pembuat kebijakan dan perencana ruang untuk menentukan prioritas intervensi atau pengendalian wilayah berdasarkan pola spasial yang terbentuk.Dengan demikian, melalui pendekatan analisis pola titik spasial, peneliti dan praktisi dapat memperoleh pemahaman yang lebih sistematis tentang distribusi titik, mendeteksi anomali atau hot-spots, serta merumuskan strategi penanganan yang sesuai berdasarkan bukti spasial.

Rumusan Masalah

  1. Bagaimana cara menentukan pola titik spasial dengan menggunakan R?
  2. Bagaimana cara menganalisis pola titik dengan metode Kuadran dan Nearest-Neighbor pada R?

Tujuan

  1. Mahasiswa mampu menentukan pola titik spasial dengan menggunakan R
  2. Mahasiswa mampu menganalisis pola titik dengan metode Kuadran dan Nearest-Neighbor

Batasan Masalah

  1. Gunakan Metode Kuadran pada data cells dari paket spatstat.data untuk mengetahui apakah pola sebaran titik bersifat acak, seragam, atau mengelompok. Hitung nilai VMR dan lakukan uji kuadran, lalu interpretasikan hasilnya.
  2. Gunakan metode Nearest Neighbor pada data quakes dari paket datasets untuk melihat apakah sebaran titik gempa bersifat acak, seragam, atau mengelompok. Hitung nilai ITT/NNI dan lakukan uji NN, lalu interpretasikan hasilnya.

BAB II PEMBAHASAN

Metode Kuadran

Input Library

library(spatstat.data)
## Warning: package 'spatstat.data' was built under R version 4.5.2
library(spatstat.geom)
## Warning: package 'spatstat.geom' was built under R version 4.5.2
## Loading required package: spatstat.univar
## Warning: package 'spatstat.univar' was built under R version 4.5.2
## spatstat.univar 3.1-4
## spatstat.geom 3.6-0
library(spatstat)
## Warning: package 'spatstat' was built under R version 4.5.2
## Loading required package: spatstat.random
## Warning: package 'spatstat.random' was built under R version 4.5.2
## spatstat.random 3.4-2
## Loading required package: spatstat.explore
## Warning: package 'spatstat.explore' was built under R version 4.5.2
## Loading required package: nlme
## spatstat.explore 3.5-3
## Loading required package: spatstat.model
## Warning: package 'spatstat.model' was built under R version 4.5.2
## Loading required package: rpart
## spatstat.model 3.4-2
## Loading required package: spatstat.linnet
## Warning: package 'spatstat.linnet' was built under R version 4.5.2
## spatstat.linnet 3.3-2
## 
## spatstat 3.4-1 
## For an introduction to spatstat, type 'beginner'

Input Data

data(cells)
data
## function (..., list = character(), package = NULL, lib.loc = NULL, 
##     verbose = getOption("verbose"), envir = .GlobalEnv, overwrite = TRUE) 
## {
##     fileExt <- function(x) {
##         db <- grepl("\\.[^.]+\\.(gz|bz2|xz)$", x)
##         ans <- sub(".*\\.", "", x)
##         ans[db] <- sub(".*\\.([^.]+\\.)(gz|bz2|xz)$", "\\1\\2", 
##             x[db])
##         ans
##     }
##     my_read_table <- function(...) {
##         lcc <- Sys.getlocale("LC_COLLATE")
##         on.exit(Sys.setlocale("LC_COLLATE", lcc))
##         Sys.setlocale("LC_COLLATE", "C")
##         read.table(...)
##     }
##     stopifnot(is.character(list))
##     names <- c(as.character(substitute(list(...))[-1L]), list)
##     if (!is.null(package)) {
##         if (!is.character(package)) 
##             stop("'package' must be a character vector or NULL")
##     }
##     paths <- find.package(package, lib.loc, verbose = verbose)
##     if (is.null(lib.loc)) 
##         paths <- c(path.package(package, TRUE), if (!length(package)) getwd(), 
##             paths)
##     paths <- unique(normalizePath(paths[file.exists(paths)]))
##     paths <- paths[dir.exists(file.path(paths, "data"))]
##     dataExts <- tools:::.make_file_exts("data")
##     if (length(names) == 0L) {
##         db <- matrix(character(), nrow = 0L, ncol = 4L)
##         for (path in paths) {
##             entries <- NULL
##             packageName <- if (file_test("-f", file.path(path, 
##                 "DESCRIPTION"))) 
##                 basename(path)
##             else "."
##             if (file_test("-f", INDEX <- file.path(path, "Meta", 
##                 "data.rds"))) {
##                 entries <- readRDS(INDEX)
##             }
##             else {
##                 dataDir <- file.path(path, "data")
##                 entries <- tools::list_files_with_type(dataDir, 
##                   "data")
##                 if (length(entries)) {
##                   entries <- unique(tools::file_path_sans_ext(basename(entries)))
##                   entries <- cbind(entries, "")
##                 }
##             }
##             if (NROW(entries)) {
##                 if (is.matrix(entries) && ncol(entries) == 2L) 
##                   db <- rbind(db, cbind(packageName, dirname(path), 
##                     entries))
##                 else warning(gettextf("data index for package %s is invalid and will be ignored", 
##                   sQuote(packageName)), domain = NA, call. = FALSE)
##             }
##         }
##         colnames(db) <- c("Package", "LibPath", "Item", "Title")
##         footer <- if (missing(package)) 
##             paste0("Use ", sQuote(paste("data(package =", ".packages(all.available = TRUE))")), 
##                 "\n", "to list the data sets in all *available* packages.")
##         else NULL
##         y <- list(title = "Data sets", header = NULL, results = db, 
##             footer = footer)
##         class(y) <- "packageIQR"
##         return(y)
##     }
##     paths <- file.path(paths, "data")
##     for (name in names) {
##         found <- FALSE
##         for (p in paths) {
##             tmp_env <- if (overwrite) 
##                 envir
##             else new.env()
##             if (file_test("-f", file.path(p, "Rdata.rds"))) {
##                 rds <- readRDS(file.path(p, "Rdata.rds"))
##                 if (name %in% names(rds)) {
##                   found <- TRUE
##                   if (verbose) 
##                     message(sprintf("name=%s:\t found in Rdata.rds", 
##                       name), domain = NA)
##                   objs <- rds[[name]]
##                   lazyLoad(file.path(p, "Rdata"), envir = tmp_env, 
##                     filter = function(x) x %in% objs)
##                   break
##                 }
##                 else if (verbose) 
##                   message(sprintf("name=%s:\t NOT found in names() of Rdata.rds, i.e.,\n\t%s\n", 
##                     name, paste(names(rds), collapse = ",")), 
##                     domain = NA)
##             }
##             files <- list.files(p, full.names = TRUE)
##             files <- files[grep(name, files, fixed = TRUE)]
##             if (length(files) > 1L) {
##                 o <- match(fileExt(files), dataExts, nomatch = 100L)
##                 paths0 <- dirname(files)
##                 paths0 <- factor(paths0, levels = unique(paths0))
##                 files <- files[order(paths0, o)]
##             }
##             if (length(files)) {
##                 for (file in files) {
##                   if (verbose) 
##                     message("name=", name, ":\t file= ...", .Platform$file.sep, 
##                       basename(file), "::\t", appendLF = FALSE, 
##                       domain = NA)
##                   ext <- fileExt(file)
##                   if (basename(file) != paste0(name, ".", ext)) 
##                     found <- FALSE
##                   else {
##                     found <- TRUE
##                     switch(ext, R = , r = {
##                       library("utils")
##                       sys.source(file, chdir = TRUE, envir = tmp_env)
##                     }, RData = , rdata = , rda = load(file, envir = tmp_env), 
##                       TXT = , txt = , tab = , tab.gz = , tab.bz2 = , 
##                       tab.xz = , txt.gz = , txt.bz2 = , txt.xz = assign(name, 
##                         my_read_table(file, header = TRUE, as.is = FALSE), 
##                         envir = tmp_env), CSV = , csv = , csv.gz = , 
##                       csv.bz2 = , csv.xz = assign(name, my_read_table(file, 
##                         header = TRUE, sep = ";", as.is = FALSE), 
##                         envir = tmp_env), found <- FALSE)
##                   }
##                   if (found) 
##                     break
##                 }
##                 if (verbose) 
##                   message(if (!found) 
##                     "*NOT* ", "found", domain = NA)
##             }
##             if (found) 
##                 break
##         }
##         if (!found) {
##             warning(gettextf("data set %s not found", sQuote(name)), 
##                 domain = NA)
##         }
##         else if (!overwrite) {
##             for (o in ls(envir = tmp_env, all.names = TRUE)) {
##                 if (exists(o, envir = envir, inherits = FALSE)) 
##                   warning(gettextf("an object named %s already exists and will not be overwritten", 
##                     sQuote(o)))
##                 else assign(o, get(o, envir = tmp_env, inherits = FALSE), 
##                   envir = envir)
##             }
##             rm(tmp_env)
##         }
##     }
##     invisible(names)
## }
## <bytecode: 0x0000016b34f91620>
## <environment: namespace:utils>

Pola Sebaran Titik - Data Cells

Gambar tersebut memperlihatkan hasil visualisasi pola persebaran titik dari dataset cells yang berasal dari paket spatstat.data pada perangkat lunak R. Secara umum, titik-titik ini menggambarkan posisi objek yang tersebar di dalam suatu bidang pengamatan berbentuk persegi. Berdasarkan pengamatan visual, tampak bahwa titik-titik tersebut tersebar dengan jarak yang relatif merata di seluruh area, tanpa menunjukkan adanya penumpukan (cluster) yang nyata maupun area kosong yang dominan. Kondisi ini mengindikasikan bahwa pola sebaran titik pada data cells cenderung memiliki karakter teratur atau seragam (uniform). Interpretasi awal tersebut dapat dikonfirmasi melalui analisis kuantitatif menggunakan Metode Kuadran atau Variance-to-Mean Ratio (VMR), di mana nilai VMR yang lebih kecil dari 1 menunjukkan pola yang seragam. Dalam kasus data cells, keteraturan ini mencerminkan bahwa setiap titik memiliki jarak antar-titik yang relatif seimbang, seakan-akan terdapat jarak minimum yang dijaga antarposisinya. Oleh karena itu, baik dari hasil pengamatan visual maupun analisis statistik, dapat disimpulkan bahwa pola persebaran titik pada dataset cells tidak bersifat acak atau mengelompok, melainkan memperlihatkan kecenderungan pola spasial yang teratur dan seragam.

Membagi bidang pengamatan menjadi kuadran 5x5

Gambar di atas menampilkan hasil pembagian area pengamatan dari data cells ke dalam sejumlah kuadran, di mana setiap kuadran menunjukkan jumlah titik yang ditandai dengan angka berwarna merah. Angka-angka tersebut merepresentasikan banyaknya titik dalam masing-masing kuadran. Berdasarkan hasil visualisasi, terlihat bahwa jumlah titik di setiap kuadran relatif seimbang, umumnya berada pada kisaran 1 hingga 3 titik, tanpa adanya kuadran yang terlalu padat maupun benar-benar kosong. Pola tersebut mengindikasikan bahwa sebaran titik dalam area pengamatan bersifat merata atau seragam. Secara statistik, temuan ini dapat diperkuat melalui analisis Variance-to-Mean Ratio (VMR), di mana nilai VMR yang mendekati atau lebih kecil dari 1 menandakan rendahnya variasi antar-kuadran serta menunjukkan pola sebaran yang teratur dan tidak acak. Dengan kata lain, titik-titik dalam data cells memiliki jarak antarposisi yang relatif konstan, mencerminkan adanya keteraturan dalam penyebarannya. Oleh karena itu, baik berdasarkan pengamatan visual maupun hasil analisis kuantitatif, dapat disimpulkan bahwa pola sebaran titik pada dataset cells bersifat teratur (regular pattern) dan tidak memperlihatkan tanda-tanda pengelompokan atau keacakan yang berarti.

Menghitung nilai Variance-to-Mean Ratio (VMR)

counts <- as.vector(quad)
mean_count <- mean(counts)
var_count <- var(counts)
VMR <- var_count / mean_count
cat("Nilai Variance-to-Mean Ratio (VMR):", VMR, "\n")
## Nilai Variance-to-Mean Ratio (VMR): 0.3829365

Nilai Variance-to-Mean Ratio (VMR) sebesar 0,3829 menunjukkan bahwa variasi jumlah titik antar-kuadran tergolong kecil dibandingkan dengan nilai rata-ratanya. Hal ini mengindikasikan bahwa pola persebaran titik pada data cells cenderung lebih teratur atau seragam daripada bersifat acak. Dalam konteks analisis pola titik spasial, nilai VMR yang berada di bawah 1 menandakan pola sebaran yang tidak acak maupun mengelompok, melainkan tersusun dengan jarak antar-titik yang relatif konstan. Oleh karena itu, hasil perhitungan VMR tersebut memperkuat kesimpulan bahwa titik-titik pada dataset cells memiliki pola sebaran yang uniform, yang mencerminkan adanya keteraturan spasial dalam distribusinya.

Uji Kuadran (Chi-Square Test)

quadrat.test(cells, nx = 5, ny = 5)
## Warning: Some expected counts are small; chi^2 approximation may be inaccurate
## 
##  Chi-squared test of CSR using quadrat counts
## 
## data:  cells
## X2 = 9.1905, df = 24, p-value = 0.005679
## alternative hypothesis: two.sided
## 
## Quadrats: 5 by 5 grid of tiles

Hasil uji Chi-kuadrat terhadap pola sebaran CSR (Complete Spatial Randomness) berdasarkan analisis quadrat counts menghasilkan nilai statistik X² = 9,1905 dengan derajat kebebasan (df) = 24 serta p-value = 0,005679. Karena nilai p lebih kecil dari taraf signifikansi umum (α = 0,05), maka hipotesis nol (H₀) yang menyatakan bahwa sebaran titik bersifat acak (random) ditolak. Dengan demikian, dapat disimpulkan bahwa pola sebaran pada data cells tidak bersifat acak secara spasial, melainkan menunjukkan adanya pola tertentu, baik berupa pengelompokan (clustered) maupun keteraturan (regular). Uji ini dilakukan dengan menggunakan pembagian grid berukuran 5 × 5 kuadrat.

Metode Nearest Neighbor

Input Library

library(spatstat.data)
library(spatstat.geom)
library(spatstat)

Input Data Gempa

data(quakes)
head(quakes)
##      lat   long depth mag stations
## 1 -20.42 181.62   562 4.8       41
## 2 -20.62 181.03   650 4.2       15
## 3 -26.00 184.10    42 5.4       43
## 4 -17.97 181.66   626 4.1       19
## 5 -20.42 181.96   649 4.0       11
## 6 -19.68 184.31   195 4.0       12

Mengambil koordinat (longitude dan latitude)

x <- quakes$long
y <- quakes$lat

Membuat point pattern object (ppp)

range_x <- range(x)
range_y <- range(y)
## Warning: data contain duplicated points

Gambar tersebut memperlihatkan persebaran titik gempa (quakes) yang merepresentasikan lokasi terjadinya gempa bumi di wilayah kajian. Berdasarkan pola visual yang tampak, titik-titik tersebut tidak tersebar secara merata di seluruh area, melainkan cenderung terkonsentrasi atau membentuk kelompok (clustered) pada beberapa bagian tertentu, terutama di wilayah tengah dan barat peta. Pola tersebut mengindikasikan bahwa aktivitas seismik lebih dominan terjadi di zona-zona spesifik yang kemungkinan berkaitan dengan keberadaan patahan geologis atau aktivitas tektonik setempat. Dengan demikian, distribusi spasial titik gempa tidak bersifat acak, tetapi menunjukkan pola pengelompokan di daerah dengan potensi seismik yang lebih tinggi.

Hitung jarak tetangga terdekat (Nearest Neighbor Distance)

nnd <- nndist(quakes_ppp)
mean_nnd <- mean(nnd)

Hitung Expected Mean Distance (E(d)) untuk pola acak

lambda <- intensity(quakes_ppp)
expected_mean <- 1 / (2 * sqrt(lambda))

Hitung Nearest Neighbor Index (NNI)

NNI <- mean_nnd / expected_mean
cat("Nilai Nearest Neighbor Index (NNI):", NNI, "\n")
## Nilai Nearest Neighbor Index (NNI): 0.4146535

Nilai Nearest Neighbor Index (NNI) sebesar 0,4146535 menunjukkan bahwa jarak rata-rata antar titik lebih kecil daripada jarak yang diharapkan pada pola sebaran acak. Karena nilai NNI berada di bawah 1, hal ini menandakan bahwa pola sebaran titik tidak bersifat acak, melainkan menunjukkan kecenderungan untuk mengelompok (clustered). Dengan demikian, objek-objek dalam dataset cenderung berdekatan satu sama lain, bukan tersebar secara merata di seluruh wilayah pengamatan.

Uji Nearest Neighbor (Clark-Evans test)

clarkevans.test(quakes_ppp, correction="none")
## 
##  Clark-Evans test
##  No edge correction
##  Z-test
## 
## data:  quakes_ppp
## R = 0.41465, p-value < 2.2e-16
## alternative hypothesis: two-sided

Hasil uji Clark-Evans terhadap data quakes_ppp menghasilkan nilai R = 0,41465 dengan p-value < 2.2e-16. Karena nilai p jauh lebih kecil dari tingkat signifikansi 0,05, maka hipotesis nol (H₀) yang menyatakan bahwa pola sebaran bersifat acak (Complete Spatial Randomness) ditolak. Nilai R < 1 mengindikasikan bahwa jarak rata-rata antar titik lebih pendek dibandingkan jarak yang diharapkan pada sebaran acak. Oleh karena itu, dapat disimpulkan bahwa pola sebaran titik dalam dataset menunjukkan kecenderungan mengelompok (clustered), bukan acak maupun teratur.

DAFTAR PUSTAKA

Piani, K. D., Dwinata, I. F., & Mandefa, U. (2023). Analisis pola sebaran spasial stasiun pengisian bahan bakar (SPBU) Kota Jakarta Timur. Jurnal Sains Geografi, 1(1), 33–46.

Ballo, A. (2023). Analisis spasial titik kebakaran hutan dan lahan di Kota Kupang dan sekitarnya dengan metode kernel density. Jurnal Penelitian Geografi, 11(2), 119–127.

Utomo, D. L. (2023). Analisis spatial autocorrelation pada kampung reforma agraria di Kabupaten Buleleng. Jurnal Pertanahan, 13(2), 101–108.