Computes various Local Indicators of Spatial Association (LISA) statistics, including univariate and bivariate local Moran's I, Empirical Bayes local Moran's I, univariate and multivariate local Geary's C, and Getis-Ord G and G* statistics. The methods follow Anselin (1995), Getis and Ord (1992), and Anselin (2019). Leverages a high-performance, plain-C backend with optional 'OpenMP' multi-core support for fast permutation-based pseudo-p-value calculation. Accepts any 'spdep' listw spatial weight matrix, including custom and non-contiguity weights. Uses sample standardisation (n-1) and 'rgeoda'-style permutation p-values. Output cluster codes match 'rgeoda' conventions, including the Isolated category for observations without neighbours.
Fast, reproducible Local Indicators of Spatial Association (LISA) with arbitrary spatial weights.
fastLISA computes seven families of LISA statistics with a plain-C backend,
optional OpenMP multi-threading, and a modern xoshiro256++ random number
generator for permutation-based inference. It accepts any spdep listw
spatial weights object — including custom and non-contiguity (e.g.
distance-decay) weights — and returns compact, inspectable, spdep-compatible
matrices.
The two established R tools force a trade-off:
listw and integrates with the R spatial ecosystem,
but its conditional-permutation inference runs largely in R and is slow on
large maps.fastLISA closes the gap:
listw weights, so
distance-decay and other non-binary schemes are respected (unlike rgeoda).iseed the pseudo-p-values are identical
regardless of n.cores — a guarantee neither spdep nor rgeoda offers.spdep-style classes
and cluster/quadrant attributes, not opaque pointers.| Function | Statistic |
|---|---|
local_moran() |
Univariate local Moran's I |
local_moran_bv() |
Bivariate local Moran's I |
local_moran_eb() |
Empirical-Bayes-rate local Moran's I |
local_geary() |
Univariate local Geary's C |
local_multigeary() |
Multivariate local Geary's C |
local_g() |
Getis-Ord local G |
local_gstar() |
Getis-Ord local G* |
Each returns the observed statistic, a permutation z-score, and a pseudo
p-value (folded for Moran/G/G*, tail-adaptive for Geary), with optional
permutation-moment columns. Cluster codes follow rgeoda conventions,
including an Isolated category for observations with no neighbours.
Install the released version from CRAN:
install.packages("fastLISA")
Or the development version from source (requires a C99 compiler; OpenMP is used when available):
# install.packages("remotes")
remotes::install_github("lizhongc/fastLISA")
Or from a local clone:
R CMD INSTALL fastLISA
spdep is suggested for constructing listw weights and for the examples.
library(spdep)
library(fastLISA)
nb <- cell2nb(7, 7) # 49 cells on a 7 x 7 grid
lw <- nb2listw(nb, style = "W") # row-standardised weights
x <- as.numeric(seq_len(49)) # a simple gradient
res <- local_moran(x, lw, nsim = 999L, iseed = 1L, n.cores = 1L)
head(res)
attr(res, "cluster") # High-High / Low-Low / outliers / Isolated ...
Custom (e.g. distance-decay) weights are passed through unchanged:
coords <- as.matrix(expand.grid(x = 1:7, y = 1:7)) # 49 grid points
dnb <- dnearneigh(coords, 0, 2) # neighbours within distance 2
glist <- lapply(nbdists(dnb, coords), function(d) exp(-d)) # distance decay
lw_exp <- nb2listw(dnb, glist = glist, style = "B")
res_exp <- local_g(x, lw_exp, nsim = 999L, iseed = 1L)
All functions share the same interface: nsim permutations, an optional integer
iseed for reproducibility, a significance cutoff p.value, n.cores
(default 1L; raise it to use multiple OpenMP threads), and p.method to choose
the pseudo-p-value rule — the standard "count" (default), or spdep's
ties-averaged "rank", which differ only under exact ties.
Because the RNG is re-seeded per observation rather than per thread, the same
iseed yields bit-identical pseudo-p-values whether you run on 1 core or many:
a <- local_moran(x, lw, nsim = 999L, iseed = 42L, n.cores = 1L)
b <- local_moran(x, lw, nsim = 999L, iseed = 42L, n.cores = 8L)
identical(c(a), c(b)) # TRUE -- same statistics and pseudo-p-values
(c() strips attributes; the full objects differ only in the recorded call,
which stores the n.cores value you passed.)
See the package help (?local_moran, ?local_g, ?local_geary, ...) and the package vignette:
vignette("fastLISA")
GPL-3.