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
## Warning: package 'rpart' was built under R version 4.5.2
## 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)
## 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: 0x000001f97220e378>
## <environment: namespace:utils>
Gambar tersebut menampilkan hasil visualisasi pola sebaran titik dari dataset cells yang diambil dari paket spatstat.data pada program R. Secara umum, titik-titik tersebut merepresentasikan lokasi objek yang tersebar di dalam suatu area pengamatan berbentuk persegi. Berdasarkan hasil pengamatan visual, titik-titik tampak tersebar dengan jarak yang relatif seragam di seluruh area, tanpa adanya penumpukan (cluster) yang jelas maupun area kosong yang signifikan. Hal ini menunjukkan indikasi awal bahwa pola sebaran titik pada data cells cenderung bersifat teratur (uniform). Interpretasi ini dapat diperkuat dengan analisis kuantitatif menggunakan Metode Kuadran atau Variance-to-Mean Ratio (VMR), di mana nilai VMR yang lebih kecil dari 1 menandakan pola yang seragam. Dalam konteks data cells, pola yang teratur ini menggambarkan bahwa setiap titik memiliki jarak antar-titik yang relatif seimbang, seolah-olah terdapat jarak minimum yang dijaga antarposisi titik. Dengan demikian, dapat disimpulkan bahwa berdasarkan pengamatan visual maupun hasil perhitungan statistik, pola sebaran titik pada dataset cells tidak bersifat acak maupun mengelompok, tetapi menunjukkan kecenderungan pola spasial yang teratur atau seragam.
Gambar di atas menunjukkan hasil pembagian area pengamatan data cells menjadi beberapa kuadran dengan masing-masing kuadran berisi jumlah titik yang ditampilkan dalam angka berwarna merah. Setiap angka menunjukkan jumlah titik yang terdapat pada kuadran tersebut. Dari hasil visualisasi terlihat bahwa jumlah titik di setiap kuadran relatif seimbang, umumnya berkisar antara 1 hingga 3 titik, tanpa adanya kuadran yang memiliki kepadatan sangat tinggi maupun kuadran yang kosong secara ekstrem. Pola ini menunjukkan bahwa sebaran titik cenderung merata (seragam) di seluruh area pengamatan. Secara statistik, kondisi ini dapat dikonfirmasi melalui perhitungan Variance-to-Mean Ratio (VMR), di mana nilai VMR yang mendekati atau lebih kecil dari 1 menunjukkan bahwa variasi antar-kuadran rendah dan pola sebaran bersifat teratur atau tidak acak. Hal ini berarti titik-titik dalam data cells memiliki jarak yang relatif konsisten satu sama lain, menunjukkan adanya keteraturan dalam proses penyebarannya. Dengan demikian, berdasarkan hasil pengamatan visual maupun pendekatan kuantitatif, dapat disimpulkan bahwa pola sebaran titik pada dataset cells bersifat seragam (regular pattern) dan tidak menunjukkan indikasi pengelompokan atau keacakan yang signifikan.
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.
Menentukan pola titik spasial menggunakan R, langkah pertama yang dilakukan adalah mengimpor dan menyiapkan data spasial dalam bentuk objek titik (point pattern), misalnya menggunakan paket spatstat.data, spatstat.geom, atau sf. Setelah data siap, dilakukan visualisasi pola sebaran titik menggunakan fungsi seperti plot() untuk mendapatkan gambaran awal apakah titik-titik tersebut tampak acak (random), teratur (uniform), atau mengelompok (clustered). Selanjutnya, dilakukan analisis kuantitatif menggunakan metode statistik spasial untuk mengonfirmasi pola tersebut secara objektif.
Sementara itu, analisis pola titik dengan metode Kuadran dan Nearest Neighbor pada R dilakukan untuk menilai tingkat keteraturan atau pengelompokan titik secara lebih formal. Pada Metode Kuadran, area pengamatan dibagi menjadi beberapa bagian kecil (kuadran), kemudian dihitung jumlah titik di setiap kuadran menggunakan fungsi quadratcount(). Nilai Variance-to-Mean Ratio (VMR) dihitung untuk melihat variasi antar-kuadran; jika VMR < 1 berarti pola bersifat teratur, jika VMR = 1 berarti acak, dan jika VMR > 1 berarti mengelompok. Selanjutnya dilakukan uji Chi-kuadrat (quadrat.test()) untuk menguji signifikansi pola tersebut. Sedangkan pada Metode Nearest Neighbor, analisis dilakukan dengan menghitung jarak rata-rata antar titik terdekat menggunakan fungsi nndist(), kemudian dibandingkan dengan jarak yang diharapkan dari sebaran acak melalui perhitungan Nearest Neighbor Index (NNI) dan uji Clark-Evans (clarkevans.test()). Nilai NNI < 1 menunjukkan pola mengelompok, NNI ≈ 1 menunjukkan pola acak, dan NNI > 1 menunjukkan pola teratur. Dengan demikian, kedua metode ini memungkinkan peneliti untuk mengidentifikasi dan menginterpretasikan pola spasial titik secara visual maupun statistik menggunakan R.
Berdasarkan hasil analisis pola titik spasial menggunakan dua pendekatan, yaitu Metode Kuadran dan Metode Nearest Neighbor, dapat disimpulkan bahwa masing-masing dataset menunjukkan karakteristik pola sebaran yang berbeda. Pada data cells, hasil pengamatan visual, perhitungan Variance-to-Mean Ratio (VMR) sebesar 0,3829, serta uji Chi-Kuadrat (p-value < 0,05) menunjukkan bahwa sebaran titik bersifat teratur (uniform pattern). Artinya, titik-titik dalam data tersebut memiliki jarak yang relatif seragam satu sama lain dan tidak menunjukkan adanya pengelompokan. Sebaliknya, pada data quakes, hasil perhitungan Nearest Neighbor Index (NNI) sebesar 0,4146 dan uji Clark-Evans (p-value < 0,05) mengindikasikan bahwa pola sebaran titik bersifat mengelompok (clustered pattern), di mana titik-titik gempa cenderung terkonsentrasi di wilayah tertentu. Dengan demikian, analisis ini menunjukkan bahwa pendekatan statistik spasial dalam R, melalui metode Kuadran dan Nearest Neighbor, mampu secara efektif mengidentifikasi dan membedakan pola sebaran titik apakah bersifat acak, seragam, atau mengelompok. Hasil ini memperkuat pentingnya penggunaan analisis pola titik spasial dalam memahami fenomena distribusi geografis berbagai kejadian 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/