Analisis pola titik spasial merupakan salah satu pendekatan penting dalam analisis spasial yang berfokus pada distribusi atau penyebaran titik-titik suatu fenomena di ruang geografis. Titik-titik tersebut dapat merepresentasikan berbagai objek atau kejadian, seperti lokasi pohon dalam hutan, persebaran penyakit, maupun titik kejadian gempa bumi. Tujuan utama dari analisis ini adalah untuk memahami apakah pola sebaran titik tersebut bersifat acak (random), teratur (uniform), atau mengelompok (clustered) (Illian et al., 2008). Melalui analisis pola titik, peneliti dapat memperoleh pemahaman yang lebih mendalam mengenai proses-proses spasial yang mendasari fenomena di dunia nyata serta membantu dalam pengambilan keputusan berbasis data spasial (Bivand, Pebesma, & Gómez-Rubio, 2013).
Dalam praktiknya, bahasa pemrograman R menjadi salah satu alat utama yang digunakan dalam analisis pola titik spasial karena memiliki kemampuan statistik yang kuat serta dukungan berbagai paket analisis, seperti spatstat, sf, dan spdep (Baddeley, Rubak, & Turner, 2015). Paket spatstat, misalnya, memungkinkan pengguna untuk melakukan visualisasi pola titik, menghitung intensitas sebaran, serta melakukan berbagai uji statistik seperti Metode Kuadran, Nearest Neighbor Analysis, maupun fungsi K-Ripley (Baddeley & Turner, 2005). Kemampuan R dalam menangani data spasial menjadikannya alat yang efisien, fleksibel, dan mudah direproduksi untuk keperluan analisis ilmiah (R Core Team, 2025).
Analisis pola titik spasial memiliki peran penting dalam berbagai bidang seperti geografi, ekologi, epidemiologi, hingga kebencanaan. Dalam konteks ekologi, misalnya, metode ini digunakan untuk menganalisis persebaran populasi tumbuhan atau hewan di suatu kawasan (Illian et al., 2008), sedangkan dalam bidang kebencanaan dapat digunakan untuk memahami sebaran titik gempa guna mengidentifikasi wilayah berisiko tinggi (Baddeley et al., 2015). Dengan demikian, penerapan analisis pola titik spasial menggunakan program R tidak hanya memberikan pemahaman statistik semata, tetapi juga mendukung pengambilan keputusan berbasis spasial yang akurat, objektif, dan ilmiah (Bivand et al., 2013).
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'
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)
## thispkg <- sub(".*/([^/]*)/data$", "\\1", p)
## thispkg <- sub("_.*$", "", thispkg)
## thispkg <- paste0("package:", thispkg)
## 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: 0x000001d3583b1990>
## <environment: namespace:utils>
Gambar tersebut menyajikan hasil visualisasi pola sebaran titik (point pattern) dari dataset cells, yang diperoleh dari library spatstat.data dalam perangkat lunak R. Secara substantif, titik-titik tersebut merepresentasikan lokasi spasial objek yang tersebar di dalam suatu domain pengamatan berbentuk persegi.Berdasarkan inspeksi visual, titik-titik tersebut tampak tersebar dengan dispersi yang relatif seragam di seluruh area pengamatan. Tidak teramati adanya agregasi (cluster) yang jelas maupun area kosong (gap) yang signifikan, yang mengindikasikan adanya homogenitas sebaran. Hal ini memunculkan hipotesis awal bahwa pola sebaran titik pada data cells cenderung bersifat teratur (regular atau uniform).Pola teratur pada data cells mengindikasikan bahwa setiap titik mempertahankan jarak antar-titik yang relatif seimbang, seolah-olah terdapat suatu jarak minimal yang dipertahankan antarposisi objek.Hipotesis deskriptif ini selanjutnya akan diverifikasi dan diperkuat melalui analisis kuantitatif menggunakan teknik statistik spasial, seperti Metode Kuadran atau Rasio Varians terhadap Rerata (Variance-to-Mean Ratio, VMR). Secara teoritis, pola sebaran yang seragam akan menghasilkan nilai VMR yang secara signifikan lebih kecil dari 1 (\(VMR < 1\)), yang akan menjadi fokus pada bagian analisis berikutnya.
Gambar diatas menampilkan hasil dekomposisi area pengamatan dataset cells menjadi sejumlah kuadran (quadrats), dimana tiap kuadran memuat informasi kuantitas titik yang dinotasikan dengan angka berwarna merah. Angka yang disajikan secara spesifik merefleksikan frekuensi (count) titik yang terkandung didalam batas spasial kuadran tersebut.Berdasarkan inspeksi visual terhadap distribusi frekuensi, teramati bahwa jumlah titik disetiap kuadran menunjukkan variabilitas yang relatif rendah (seimbang), dengan kisaran umum antara 1 hingga 3 titik. Pola ini menunjukkan tidak adanya kuadran dengan kepadatan yang sangat tinggi (hyper-dense) maupun kuadran yang secara ekstrem kosong (void). Observasi ini menegaskan bahwa sebaran titik cenderung homogen (merata) di seluruh domain pengamatan.Secara statistik, kondisi ini menyediakan bukti empiris awal yang mendukung hipotesis pola sebaran yang teratur. Hal ini dapat dikonfirmasi secara kuantitatif melalui perhitungan Rasio Varians terhadap Rerata (Variance-to-Mean Ratio, VMR). Nilai VMR yang mendekati 1 atau lebih kecil dari 1 (\(VMR \leq 1\)) mengindikasikan bahwa variasi frekuensi antar-kuadran adalah rendah, sehingga pola sebaran bersifat teratur (regular) dan tidak menunjukkan sifat acak (random) yang signifikan.Hal ini secara implisit menunjukkan bahwa titik-titik dalam data cells memiliki jarak antar-titik yang relatif konsisten, mencerminkan adanya keteraturan inheren dalam mekanisme penyebarannya. Analisis VMR ini akan digunakan untuk memvalidasi secara formal bahwa pola sebaran titik pada dataset cells menunjukkan kecenderungan seragam (regular pattern) dan bukan pola acak atau mengelompok.
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 relatif kecil dibandingkan dengan rata-ratanya, yang mengindikasikan pola sebaran titik pada data cells bersifat lebih teratur atau seragam daripada acak. Dalam analisis pola titik spasial, nilai VMR kurang dari 1 mengarah pada pola yang tidak acak dan tidak mengelompok, melainkan tersebar dengan jarak yang relatif konsisten antar titik. Dengan demikian, nilai VMR ini memperkuat kesimpulan bahwa titik-titik dalam dataset cells menunjukkan pola sebaran yang uniform, mencerminkan keteraturan spasial dalam distribusi titik-titik tersebut.
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) menggunakan perhitungan kuadrat (quadrat counts) menunjukkan nilai statistik X² = 9,1905 dengan derajat kebebasan (df) = 24 dan p-value = 0,005679. Karena nilai p lebih kecil dari taraf signifikansi umum (misalnya 0,05), maka H₀ yang menyatakan bahwa sebaran bersifat acak (random) ditolak. Dengan demikian, dapat disimpulkan bahwa pola sebaran sel (cells) tidak acak secara spasial, melainkan menunjukkan adanya pola tertentu, seperti mengelompok (clustered) atau teratur (regular). Analisis ini dilakukan dengan menggunakan grid berukuran 5 x 5 kuadrat.
library(spatstat.data)
library(spatstat.geom)
library(spatstat)
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
x <- quakes$long
y <- quakes$lat
range_x <- range(x)
range_y <- range(y)
## Warning: data contain duplicated points
Gambar tersebut menunjukkan sebaran titik gempa (quakes) yang menggambarkan lokasi kejadian gempa pada suatu wilayah studi. Dari pola visual yang tampak, titik-titik gempa tidak tersebar secara merata di seluruh area, melainkan terkonsentrasi atau mengelompok (clustered) di beberapa bagian tertentu, terutama di bagian tengah dan barat peta. Pola ini menunjukkan bahwa aktivitas gempa lebih sering terjadi di zona-zona tertentu yang kemungkinan berkaitan dengan patahan geologis atau aktivitas tektonik lokal. Dengan demikian, distribusi spasial titik gempa menunjukkan kecenderungan tidak acak, melainkan membentuk pola pengelompokan di wilayah yang memiliki potensi seismik lebih tinggi.
nnd <- nndist(quakes_ppp)
mean_nnd <- mean(nnd)
lambda <- intensity(quakes_ppp)
expected_mean <- 1 / (2 * sqrt(lambda))
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) yang diperoleh sebesar 0,4146535 menunjukkan bahwa jarak rata-rata antar titik lebih kecil dibandingkan dengan jarak yang diharapkan pada sebaran acak. Karena nilai NNI < 1, hal ini mengindikasikan bahwa pola sebaran titik tidak acak, melainkan cenderung mengelompok (clustered). Dengan kata lain, objek-objek dalam data memiliki kecenderungan untuk berada berdekatan satu sama lain daripada tersebar secara merata di seluruh area studi.
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 Clark-Evans test pada data quakes_ppp menunjukkan nilai R = 0,41465 dengan p-value < 2.2e-16. Karena nilai p jauh lebih kecil dari 0,05, maka hipotesis nol (H₀) yang menyatakan bahwa pola sebaran bersifat acak (Complete Spatial Randomness) ditolak. Nilai R yang lebih kecil dari 1 menunjukkan bahwa jarak rata-rata antar titik lebih pendek daripada jarak yang diharapkan pada sebaran acak. Dengan demikian, dapat disimpulkan bahwa pola sebaran titik dalam data bersifat mengelompok (clustered), bukan acak atau teratur.
Penentuan pola titik spasial (spatial point pattern) dalam lingkungan R diawali dengan proses impor dan preparasi data ke dalam format objek titik, yang umumnya menggunakan paket-paket seperti spatstat.data, spatstat.geom, atau sf. Setelah data tervalidasi, dilakukan visualisasi awal menggunakan fungsi seperti plot() guna memperoleh gambaran deskriptif awal mengenai dispersi titik—apakah cenderung acak (random), teratur (uniform), atau mengelompok (clustered). Observasi visual ini kemudian menjadi dasar untuk verifikasi melalui analisis kuantitatif menggunakan metode statistik spasial yang bertujuan untuk mengonfirmasi karakteristik pola tersebut secara objektif.
Analisis kuantitatif pola titik dengan Metode Kuadran dan Metode Nearest Neighbor dilakukan untuk menilai tingkat keteraturan atau pengelompokan secara formal. Pada Metode Kuadran, area pengamatan dibagi dan jumlah titik dihitung menggunakan quadratcount(), diikuti perhitungan VMR sebagai indikator: \(VMR < 1\) untuk pola teratur, \(VMR = 1\) untuk pola acak, dan \(VMR > 1\) untuk pola mengelompok. Signifikansi diuji melalui uji Chi-kuadrat (quadrat.test()). Sementara itu, Metode Nearest Neighbor menghitung jarak rata-rata antar titik terdekat (nndist()). Pola diukur melalui NNI dan diuji dengan Clark-Evans (clarkevans.test()), di mana \(NNI < 1\) mengindikasikan mengelompok, \(NNI \approx 1\) acak, dan \(NNI > 1\) teratur. Kedua metode ini memungkinkan identifikasi dan interpretasi pola spasial secara komprehensif.
Berdasarkan implementasi dua pendekatan tersebut, teridentifikasi bahwa dataset menunjukkan pola sebaran yang berbeda. Pada data cells, hasil observasi visual, perhitungan VMR sebesar 0,3829, dan uji Chi-kuadrat yang signifikan (\(p-value < 0,05\)) secara konsisten menegaskan bahwa sebaran titik bersifat teratur (uniform pattern), mengimplikasikan jarak antar-titik yang relatif seragam. Sebaliknya, pada data quakes, nilai NNI sebesar 0,4146 dan uji Clark-Evans yang signifikan (\(p-value < 0,05\)) mengindikasikan pola sebaran yang mengelompok (clustered pattern), di mana titik-titik terkonsentrasi di wilayah tertentu. Hasil ini memperkuat bahwa analisis statistik spasial di R, melalui metode Kuadran dan Nearest Neighbor, merupakan alat yang efektif untuk membedakan dan memahami fenomena distribusi geografis di dunia nyata.
Baddeley, A., Rubak, E., & Turner, R. (2015). Spatial Point Patterns: Methodology and Applications with R. Chapman and Hall/CRC Press.
Baddeley, A., & Turner, R. (2005). spatstat: An R package for analyzing spatial point patterns. Journal of Statistical Software, 12(6), 1–42.
Bivand, R. S., Pebesma, E., & Gómez-Rubio, V. (2013). Applied Spatial Data Analysis with R (2nd ed.). Springer.
Illian, J., Penttinen, A., Stoyan, H., & Stoyan, D. (2008). Statistical Analysis and Modelling of Spatial Point Patterns. John Wiley & Sons.
R Core Team. (2025). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing. Retrieved from https://www.r-project.org/