
Modeling 06: Spatial Models — Autocorrelation, Regression, and Scan Statistics
climasus4r Team
17/10/2026
Source:vignettes/mod-06-espacial.Rmd
mod-06-espacial.RmdObjective
By the end of this tutorial you will be able to:
- Build a Queen spatial weights matrix from municipal
polygons with
sus_mod_spatial_weights(); - Compute and interpret the global Moran’s I and
local LISA clusters (HH/LL/HL/LH) with
sus_mod_spatial_moran()andsus_mod_plot_spatial_moran(); - Fit and compare spatial regression models (SAR,
SEM, SDM, SAC) with
sus_mod_spatial_reg(), extracting coefficients and direct/indirect/total impacts; - Detect geographic clusters of excess cases using
Kulldorff’s scan statistic via
sus_mod_spatial_scan()andsus_mod_plot_spatial_scan().
This tutorial covers the spatial analysis stage of the climasus4r pipeline — the one that precedes the Bayesian spatial models (Tutorial 07) and follows the Machine Learning models (Tutorial 05).
Scientific context
Why does the spatial dimension matter in environmental health?
Health data collected in neighboring municipalities are rarely independent of one another. Spatial dependence emerges from shared factors (climate, pollution, access to services, social behavior) that vary smoothly in space. Ignoring it produces inefficient estimators, incorrect confidence intervals, and, ultimately, mistaken inferences about the exposure–outcome association (Anselin, 1988; Bivand, Pebesma & Gomez-Rubio, 2013).
Classical spatial analysis in epidemiology involves three questions:
- Is there spatial dependence? (autocorrelation tests)
- Where are the clusters? (LISA, Kulldorff scan)
- Does the effect of an exposure spread to neighboring municipalities? (spillovers; spatial regression)
Note on CRS and units. The functions
sus_mod_spatial_weights()andsus_mod_spatial_moran()acceptsfobjects in any CRS, but thesnapparameter ofpoly2nb()is interpreted in the units of the CRS used. For a geographic CRS (degrees, e.g. SIRGAS 2000 / EPSG:4674, thegeobrdefault), the valuesnap = 1e-3corresponds to ≈ 0.001° ≈ 100 m, adequate for closing small gaps at the boundaries of IBGE municipal polygons. For CRS projected in meters (e.g. SIRGAS2000 / UTM), values between1and100meters are more appropriate.MAUP (Modifiable Areal Unit Problem). The results of this stage depend on the aggregation scale adopted (municipality, micro-region, state). A Moran’s I calculated at the municipal level may differ significantly from one calculated at the micro-region level, even with the same raw data. This is due to MAUP (Openshaw & Taylor, 1979): the shape and size of spatial units influences every derived indicator. It is recommended to check the robustness of results at at least two scales before drawing inferences (Fotheringham & Wong, 1991).
Moran’s I
Global Moran’s I (Moran, 1950) measures whether high (or low) values tend to occur close to one another. It is defined as:
where is the number of spatial units, is the total sum of spatial weights, is the value of the variable of interest in unit , is the global mean, and is the spatial weight between units and (with ).
With row-standardized weights
(style = "W"), each
,
where
is the number of neighbors of
,
and
.
Thus the spatial lag
is simply the weighted average of the values at the neighbors.
Values of close to indicate positive clustering (spatial similarity); indicates spatial dispersion (units with high values surrounded by low ones, and vice versa); indicates a random distribution.
Inference is performed via Monte Carlo permutation —
sus_mod_spatial_moran() uses spdep::moran.mc()
for the global test and spdep::localmoran_perm() for the
local LISA tests.
LISA — Local Indicators of Spatial Association
LISA indicators (Anselin, 1995) decompose the global I into individual contributions from each unit, allowing identification of hotspots (HH: high surrounded by high), coldspots (LL: low surrounded by low), and spatial outliers (HL and LH). The classification uses the Moran diagram ( vs. , the spatial lag of ):
| Quadrant | Interpretation | ||
|---|---|---|---|
| HH | > 0 | > 0 | Hotspot |
| LL | < 0 | < 0 | Coldspot |
| HL | > 0 | < 0 | High outlier in a low region |
| LH | < 0 | > 0 | Low outlier in a high region |
| NS | — | — | Not significant |
Spatial regression models
When spatial autocorrelation is confirmed, OLS models are inadequate.
climasus4r implements four model families via spatialreg
(Bivand & Piras, 2015):
| Model | Abbreviation | Parameter | Simplified equation |
|---|---|---|---|
| Spatial Autoregressive | SAR | ||
| Spatial Error | SEM | ||
| Spatial Durbin | SDM | + | |
| Spatial Autocorrelation | SAC | , |
For SAR/SDM/SAC models, the total effect of a covariate is decomposed into direct impact (own unit) + indirect impact (spillover to neighbors) = total impact (LeSage & Pace, 2009).
Kulldorff’s scan statistic
Kulldorff’s method (1997) imposes circular windows of varying radius over the map and, for each candidate window , computes the likelihood ratio (LR) under the Poisson model, only when the internal rate exceeds the external rate ():
where and are, respectively, the observed and expected cases inside the window, and and the corresponding values outside the window. The window with the highest LR is the most likely cluster; its p-value is obtained by comparison with the empirical distribution of maximum LR values under Monte Carlo permutations (under the null hypothesis of a uniform distribution of cases proportional to population).
The function sus_mod_spatial_scan() delegates the
computation to SpatialEpi::kulldorff(), which requires
geographic coordinates (longitude/latitude, WGS 84). For this reason,
the polygon centroids are reprojected to EPSG:4326 internally before the
calculation.
Data used
The guiding case is: “Temperature and health outcomes in older adults (60+) in the São Paulo Metropolitan Region, 2014–2019” (respiratory causes J00–J99).
For this stage we use:
| Object | File | Content |
|---|---|---|
rmsp_sf |
dados/caso_espacial.rds |
RMSP sf with n_obitos and pop
per municipality |
mod_weights |
dados/mod_weights.rds |
Queen weights built in this tutorial |
If caso_espacial.rds is absent or incomplete, the
generation script synthesizes a minimal, realistic panel for the RMSP
with 39 municipalities, preserving plausible spatial gradients for
didactic purposes.
IBGE municipality code. climasus4r uses the 7-digit IBGE code as the unique identifier for municipalities (e.g.
3550308for São Paulo-SP). The first two digits identify the state (35 = São Paulo) and the following five identify the municipality within the state. Make sure that thecode_municolumn in yoursffollows this pattern —geobralready provides it correctly. 6-digit codes (the old standard) must be converted before using thesus_mod_spatial_*()functions.
Complete pipeline
Load the package and the data before any analysis. The paths below
assume the script is run from the package root
(climasus4r/), which is where the
scripts/modelagem_06_espacial.R script saves its
artifacts.
library(climasus4r)
library(dplyr)
# Dados espaciais da RMSP (gerados por scripts/modelagem_06_espacial.R)
# Caminhos relativos à raiz do pacote (não à pasta vignettes-pt/).
rmsp_sf <- if (file.exists("vignettes-pt/dados/caso_espacial.rds")) {
obj <- readRDS("vignettes-pt/dados/caso_espacial.rds")
# Converter para sf e agregar por município (média do período)
if (requireNamespace("sf", quietly = TRUE) &&
"geom" %in% names(obj) &&
inherits(obj[["geom"]], "sfc")) {
sf_obj <- sf::st_as_sf(obj)
dplyr::group_by(sf_obj, code_muni) |>
dplyr::summarise(
n_obitos = mean(n_obitos, na.rm = TRUE),
name_muni = dplyr::first(name_muni),
pop = mean(pop, na.rm = TRUE),
temp_med = mean(temp_med, na.rm = TRUE),
.groups = "drop"
)
} else {
message("Objeto sf não encontrado; verifique caso_espacial.rds.")
NULL
}
} else {
message("Execute scripts/modelagem_06_espacial.R para gerar os dados.")
NULL
}
# Calcular taxa de mortalidade por 100 mil habitantes
if (!is.null(rmsp_sf) && !"taxa_obitos" %in% names(rmsp_sf)) {
rmsp_sf$taxa_obitos <- rmsp_sf$n_obitos / rmsp_sf$pop * 1e5
}Step 1 — Build the spatial weights matrix
Queen vs. Rook contiguity. Queen contiguity
considers two municipalities neighbors when their polygons share
a vertex or an edge (8 directions). Rook contiguity restricts
neighborhood to municipalities that share an edge (4
directions). For IBGE municipal polygons, where municipalities may touch
at only a single point, Queen contiguity is more appropriate and is the
package default (queen = TRUE).
Row standardization (style = "W"). With
this normalization, each weight
(where
is the number of neighbors of
),
so that
for every unit
with neighbors. This makes the spatial lag
easy to interpret as an average of the values at the
neighbors and is the default style for Moran’s I and SAR/SEM
models.
mod_weights <- sus_mod_spatial_weights(
municipalities = rmsp_sf,
style = "W", # row-standardised: sum(w_ij) = 1 para cada i
queen = TRUE, # contiguidade Queen (vértice ou aresta)
snap = 1e-3, # tolerância para gaps (em graus, CRS SIRGAS2000)
zero_policy = TRUE, # permite ilhas espaciais (sem vizinho)
return_matrix = FALSE, # não retorna a matriz densa W (economia de memória)
lang = "pt",
verbose = TRUE
)
print(mod_weights)
# Salvar para reuso em tutoriais subsequentes (Tutorial 07 — Bayes Espacial)
save_tbl(mod_weights, "mod_weights")Step 2 — Global spatial autocorrelation + LISA
# Dados tabulares sem geometria (sus_mod_spatial_moran aceita data.frame ou
# climasus_df; a coluna code_muni deve estar presente)
df_tabular <- sf::st_drop_geometry(rmsp_sf)
# A taxa já foi calculada no passo de carregamento; verificar e recalcular
# se necessário
if (!"taxa_obitos" %in% names(df_tabular)) {
df_tabular$taxa_obitos <- df_tabular$n_obitos / df_tabular$pop * 1e5
}
moran_resultado <- sus_mod_spatial_moran(
df = df_tabular,
outcome = "taxa_obitos", # coluna numérica de desfecho (arg: "outcome")
W = mod_weights, # climasus_weights do passo anterior
municipalities = NULL, # NULL: usa todas as linhas na ordem de W
permutations = 999L,
alpha = 0.05,
adjust_p = "fdr", # correção FDR (Benjamini-Hochberg)
lang = "pt",
verbose = TRUE
)
print(moran_resultado)
# Mapa LISA de clusters (HH/LL/HL/LH/NS)
sus_mod_plot_spatial_moran(
x = moran_resultado,
municipalities = rmsp_sf,
type = "map",
alpha = 0.05,
lang = "pt"
)
# Diagrama de dispersão de Moran (z vs. Wz)
sus_mod_plot_spatial_moran(
x = moran_resultado,
type = "scatter",
lang = "pt"
)
# Ambos os painéis lado a lado (requer patchwork)
sus_mod_plot_spatial_moran(
x = moran_resultado,
municipalities = rmsp_sf,
type = "both",
lang = "pt"
)Step 3 — Spatial regression (SAR / SEM / SDM / SAC)
# Garantir que df_reg não contém geometria (sus_mod_spatial_reg descarta
# automaticamente, mas é boa prática passar um data.frame puro)
df_reg <- sf::st_drop_geometry(rmsp_sf)
# Verificar / calcular taxa
if (!"taxa_obitos" %in% names(df_reg)) {
df_reg$taxa_obitos <- df_reg$n_obitos / df_reg$pop * 1e5
}
# Modelo SAR (Spatial Lag) — rho: spillover do desfecho entre municípios
# Estimado via spatialreg::lagsarlm() com método de ML exato ("eigen")
reg_sar <- sus_mod_spatial_reg(
df = df_reg,
formula = taxa_obitos ~ temp_med,
W = mod_weights,
model = "lag", # SAR: y = rho * W*y + X*beta + epsilon
method = "eigen", # ML exato; use "LU" ou "Chebyshev" para n > 2.000
zero_policy = TRUE,
lang = "pt",
verbose = TRUE
)
print(reg_sar)
# Impactos direto/indireto/total (calculados internamente com R = 200 simulações)
# $impacts é NULL para modelos SEM (sem lag do desfecho)
reg_sar$impacts
# Diagnóstico: I de Moran nos resíduos — deve ser não-significativo se o modelo
# capturou a autocorrelação espacial adequadamente
reg_sar$moran_residuals
# Modelo SEM (Spatial Error) — lambda: erro espacialmente autocorrelacionado
# Indicado quando a autocorrelação é devida a variáveis omitidas espacialmente
# estruturadas (e.g. poluição não mensurada, gradientes socioeconômicos)
reg_sem <- sus_mod_spatial_reg(
df = df_reg,
formula = taxa_obitos ~ temp_med,
W = mod_weights,
model = "error", # SEM: y = X*beta + u; u = lambda * W*u + epsilon
lang = "pt",
verbose = FALSE
)
# Comparação de AIC: menor AIC = melhor ajuste (penalizando complexidade)
# OLS ignora autocorrelação; SAR/SEM incorporam de formas distintas
data.frame(
modelo = c("OLS", "SAR", "SEM"),
AIC = c(reg_sar$lm_aic, reg_sar$aic, reg_sem$aic)
)
# Modelo SDM (Spatial Durbin) — rho + covariáveis defasadas espacialmente
# Estimado via lagsarlm(Durbin = TRUE): inclui W*X além do W*y
# Recomendado quando há razão para acreditar que covariáveis de municípios
# vizinhos também afetam o desfecho (e.g. temperatura regional)
reg_sdm <- sus_mod_spatial_reg(
df = df_reg,
formula = taxa_obitos ~ temp_med,
W = mod_weights,
model = "durbin", # SDM: y = rho*W*y + X*beta + W*X*theta + epsilon
lang = "pt",
verbose = FALSE
)
reg_sdm$impacts # direto, indireto e total por covariável
# Modelo SAC (rho + lambda) — modelo mais geral; lag do desfecho E erro espacial
# Estimado via spatialreg::sacsarlm(); usa a mesma matriz W para ambos
# os componentes por padrão
reg_sac <- sus_mod_spatial_reg(
df = df_reg,
formula = taxa_obitos ~ temp_med,
W = mod_weights,
model = "sac", # SAC: y = rho*W*y + X*beta + u; u = lambda*W*u + epsilon
lang = "pt",
verbose = FALSE
)
reg_sac$rho # parâmetro de lag do desfecho
reg_sac$lambda # parâmetro de erro espacialStep 4 — Cluster detection: Kulldorff scan
# sus_mod_spatial_scan() requer um data.frame com code_muni, cases e population.
# Os centroides dos polígonos são reprojetados para WGS 84 (EPSG:4326)
# internamente para calcular as distâncias usadas pelas janelas circulares.
df_scan <- data.frame(
code_muni = as.character(rmsp_sf$code_muni),
cases = as.integer(round(rmsp_sf$n_obitos)),
population = as.integer(rmsp_sf$pop),
stringsAsFactors = FALSE
)
scan_resultado <- sus_mod_spatial_scan(
df = df_scan,
cases = "cases",
population = "population",
municipalities = rmsp_sf,
expected = NULL, # NULL → Poisson simples (taxa global × pop_i)
max_pop_frac = 0.5, # janela máxima contém ≤ 50% da pop. total
n_simulations = 999L, # para publicação use 9999L
alpha = 0.05,
lang = "pt",
verbose = TRUE
)
print(scan_resultado)
# Cluster mais provável: location_ids, RR, log_lik, p_value
scan_resultado$most_likely_cluster
# Clusters secundários (lista de listas, mesma estrutura)
scan_resultado$secondary_clusters
# Mapa de Risco Relativo (escala contínua divergente)
sus_mod_plot_spatial_scan(
x = scan_resultado,
municipalities = rmsp_sf,
show_rr = TRUE,
alpha = 0.05,
lang = "pt"
)
# Mapa categórico (mais provável / secundário / fundo)
sus_mod_plot_spatial_scan(
x = scan_resultado,
municipalities = rmsp_sf,
show_rr = FALSE,
alpha = 0.05,
lang = "pt"
)Function reference
sus_mod_spatial_weights() — Spatial weights matrix
Purpose. Builds a climasus_weights
object (a list subclass) with the spatial neighborhood structure
required by all other spatial models in climasus4r.
Main arguments:
| Argument | Default | Meaning |
|---|---|---|
municipalities |
— |
sf with municipal polygons |
style |
"W" |
Normalization: "W" (row-standardized), "B"
(binary), "C", "U", "S",
"minmax"
|
queen |
TRUE |
TRUE = Queen (vertex or edge); FALSE =
Rook (edge only) |
snap |
NULL → 1e-3
|
Tolerance for boundary gaps |
zero_policy |
TRUE |
Allow islands (municipalities with no neighbor) |
return_matrix |
FALSE |
Return the dense matrix () |
Return value (climasus_weights):
$listw — objeto spdep::listw pronto para modelagem
$nb — lista de vizinhos (spdep::nb)
$n_regions — número total de regiões
$n_islands — número de ilhas (sem vizinhos)
$island_ids — códigos das ilhas (vetor de caracteres, vazio se nenhuma)
$W — matriz densa W n×n (NULL se return_matrix = FALSE)
$style — estilo de normalização usado
$call — chamada original
Practical tip. For IBGE data with a geographic CRS (SIRGAS2000 / EPSG:4674), use
snap = 1e-3(default). For polygons in a projected CRS (meters), adjustsnapto 1–100 m. Municipalities with no neighbors (islands, e.g. Fernando de Noronha) do not cause an error withzero_policy = TRUE, but result in anNAspatial lag — check$island_ids. Usestyle = "B"(binary) only when you want to weight by the presence of a neighbor relationship without normalizing by the number of neighbors (e.g. in ICAR-type Bayesian models).
sus_mod_spatial_moran() — Global Moran’s I + LISA
Purpose. Tests global spatial autocorrelation via Moran’s I (through Monte Carlo permutation) and classifies each unit into a LISA quadrant.
Main arguments:
| Argument | Default | Meaning |
|---|---|---|
df |
— |
data.frame or climasus_df with
code_muni and the outcome column |
outcome |
— | Name of the numeric outcome column
(e.g. "taxa_obitos") |
W |
— |
climasus_weights object from
sus_mod_spatial_weights()
|
municipalities |
NULL |
Vector of code_muni values to filter/reorder
df
|
permutations |
999L |
Monte Carlo permutations (nsim in
spdep::moran.mc) |
alpha |
0.05 |
Significance level for LISA classification |
adjust_p |
"fdr" |
Multiple-testing correction: "fdr",
"bonferroni", "none"
|
Return value
(climasus_spatial_moran):
$global — data.frame com I, E.I, Var.I, Z.I, p_value, p_simulated
$local — data.frame com code_muni, Ii, Z.Ii, p_raw, p_adj, quadrant
$n_HH — número de hotspots (HH)
$n_LL — número de coldspots (LL)
$n_HL — número de outliers HL
$n_LH — número de outliers LH
$outcome_name — nome da coluna de desfecho
$call — chamada original
About
p_valuevsp_simulated. Thep_valuein the$globalslot is the asymptotic p-value (normal distribution).p_simulatedis the Monte Carlo permutation p-value — preferable for small samples (n < 30 municipalities) or skewed distributions. For the local LISA tests ($local), the p-values are already conditional-permutation based (spdep::localmoran_perm()), corrected using the method specified inadjust_p.
sus_mod_plot_spatial_moran() — LISA visualization
Purpose. Produces a LISA choropleth map and/or a
Moran scatterplot from a climasus_spatial_moran object.
Available types (type=):
type |
Description | Requires municipalities
|
|---|---|---|
"map" |
HH/LL/HL/LH/NS choropleth map | Yes |
"scatter" |
vs. scatterplot | No |
"both" |
Both side by side via patchwork | Yes |
Return value: a ggplot object (or a
named list list(map, scatter) if patchwork is not available
for type = "both").
sus_mod_spatial_reg() — Spatial regression
Purpose. Fits SAR/SEM/SDM/SAC maximum-likelihood
models via the spatialreg package, reporting coefficients,
spatial parameters, impacts, and residual Moran’s I.
Available models (model=):
model |
Family | Spatial parameter | Estimated via |
|---|---|---|---|
"lag" |
SAR | spatialreg::lagsarlm() |
|
"error" |
SEM | spatialreg::errorsarlm() |
|
"durbin" |
SDM | + | spatialreg::lagsarlm(Durbin=TRUE) |
"sac" |
SAC | + | spatialreg::sacsarlm() |
Main arguments:
| Argument | Default | Meaning |
|---|---|---|
df |
— |
data.frame or climasus_df (sf
geometry is discarded automatically) |
formula |
— | Standard R formula (outcome ~ cov1 + cov2) |
W |
— |
climasus_weights object from
sus_mod_spatial_weights()
|
model |
"lag" |
Model family (see table above) |
method |
"eigen" |
Estimation method: "eigen" (exact ML),
"LU", "Chebyshev", "MC"
|
zero_policy |
TRUE |
Allow islands (municipalities with no neighbors) |
lang |
"pt" |
Message language |
verbose |
TRUE |
Show progress messages |
Return value
(climasus_spatial_reg):
$model — tipo de modelo ("lag", "error", "durbin", "sac")
$model_label — rótulo legível ("SAR (Spatial Lag)", ...)
$coefficients — data.frame: term, estimate, std_error, z_value, p_value
$rho — parâmetro de lag espacial ρ (NULL para SEM)
$lambda — parâmetro de erro espacial λ (NULL para SAR/SDM)
$impacts — data.frame: term, direct, indirect, total
(calculado com R = 200 via spatialreg::impacts();
NULL para SEM, onde os impactos = coeficientes OLS)
$aic — AIC do modelo espacial
$lm_aic — AIC do baseline OLS (mesma fórmula, mesmos dados)
$moran_residuals — lista: I, p_value, z (teste de Moran nos resíduos)
$fitted — valores ajustados
$residuals — resíduos do modelo
$call — chamada original
Residual diagnostics. The
$moran_residualselement contains the result ofspdep::moran.test()applied to the model’s residuals. A non-significant p-value (> 0.05) indicates that the spatial model adequately absorbed the spatial autocorrelation. If the residual Moran’s I remains significant even after SAR/SEM, consider the SDM (spatially lagged covariates) or a hierarchical Bayesian model (Tutorial 07).
sus_mod_spatial_scan() — Kulldorff scan
Purpose. Applies Kulldorff’s circular scan statistic to detect the most likely cluster and secondary clusters of excess cases, with Monte Carlo inference.
Main arguments:
| Argument | Default | Meaning |
|---|---|---|
df |
— |
data.frame with code_muni,
cases, and population columns |
cases |
— | Name of the case-count column (integers ≥ 0) |
population |
— | Name of the population-at-risk column |
municipalities |
— |
sf with polygons and code_muni
|
expected |
NULL |
Name of the expected-count column (NULL: global rate × pop_i) |
max_pop_frac |
0.5 |
Maximum fraction of the total population in a single window |
n_simulations |
999L |
Monte Carlo simulations (use 9999L for
publication) |
alpha |
0.05 |
Significance level for secondary clusters |
lang |
"pt" |
Message language |
verbose |
TRUE |
Show progress messages |
Return value
(climasus_spatial_scan):
$most_likely_cluster — lista: location_ids (code_muni), observed, expected,
RR (razão de verossimilhança de excesso), log_lik, p_value
$secondary_clusters — lista de listas com a mesma estrutura
$n_clusters — total de clusters significativos (incluindo o mais provável)
$data — tibble: code_muni, cases, population, expected, in_mlc
$meta — parâmetros: cases_col, population_col, max_pop_frac,
n_simulations, alpha, n_municipalities, call_time
$call — chamada original
CRS and centroids. The function
sus_mod_spatial_scan()usessf::st_centroid()after reprojecting the polygons to WGS 84 (EPSG:4326), sinceSpatialEpi::kulldorff()requires longitude/latitude coordinates. Themunicipalitiesobject may be in any CRS — the reprojection is performed internally. The scan window is circular in geographic space (lat/lon), not in projected space.
sus_mod_plot_spatial_scan() — Cluster map
Purpose. Renders a choropleth map of the Kulldorff scan results with continuous or categorical RR encoding.
Argument show_rr:
show_rr |
Encoding | Scale |
|---|---|---|
TRUE (default) |
Cluster Relative Risk (continuous) | Diverging gradient (navy–white–red, centered at RR = 1) |
FALSE |
Cluster label (categorical) | Discrete colors per cluster |
Return value: a ggplot object.
Illustrated results
Figure 1 — LISA cluster map of respiratory mortality (RMSP)
The map below shows the LISA classification of each RMSP municipality based on the average respiratory mortality rate for the period 2014–2019. Municipalities in red (HH) form spatial hotspots — they show an elevated rate and are surrounded by neighbors with an equally elevated rate.

Figure 2 — Moran scatterplot
The scatterplot positions each municipality in the plane (, ): the slope of the regression line corresponds to the global Moran’s I. Points in the upper-right (HH) and lower-left (LL) quadrants indicate positive clustering; points in the cross quadrants (HL, LH) are spatial outliers.

Table 1 — Global Moran’s I
| I | E.I | Var.I | Z.I | p_value | p_simulated |
|---|---|---|---|---|---|
| 0.30348 | -0.0263158 | 0.0074095 | 3.831345 | 6.37e-05 | 0.002 |
Figure 3 — Direct, indirect, and total impacts (SAR)
In the SAR model, the coefficient of a covariate does not directly represent the effect on the outcome — because the matrix propagates any shock through the entire neighbor network. The impacts are decomposed into (LeSage & Pace, 2009):
- Direct impact: average effect of the covariate in the municipality itself;
- Indirect impact (spillover): average effect in neighboring municipalities, mediated by and the structure of ;
- Total impact = direct + indirect.
The package uses spatialreg::impacts() with R = 200
simulations (Monte Carlo reference distribution) to build the confidence
intervals.

Table 2 — SAR model coefficients
| term | estimate | std_error | z_value | p_value |
|---|---|---|---|---|
| (Intercept) | -314.51778 | 119.820191 | -2.624915 | 0.0086671 |
| temp_med | 28.53836 | 5.725513 | 4.984419 | 0.0000006 |
Table 3 — AIC comparison (OLS / SAR / SEM)
The choice between OLS, SAR, and SEM can be guided by the AIC (Akaike information criterion). The model with the lowest AIC (penalizing complexity) is preferable. A substantial AIC reduction in SAR or SEM relative to OLS confirms that spatial autocorrelation is relevant.
| modelo | AIC |
|---|---|
| OLS | 442.51 |
| SAR | 440.57 |
| SEM | 444.38 |
Table 4 — Diagnostic: Moran’s I on residuals (SAR)
After fitting the SAR model, Moran’s I on the residuals should be non-significant, indicating that spatial autocorrelation was adequately captured. A residual Moran’s I that remains significant suggests insufficient specification and points toward more complex models (SDM or hierarchical Bayes).
| I | z | p_value |
|---|---|---|
| -0.110034 | -0.959 | 0.8312 |
Figure 4 — Relative Risk map (Kulldorff, continuous RR)
The map below shows the RR for each municipality belonging to a significant cluster detected by the Kulldorff scan. Municipalities in intense red belong to the cluster with the greatest excess risk. Municipalities with no color (light gray) are part of the background — they do not belong to any cluster.
Artefato indisponível — rode
Rscript scripts/modelagem_06_espacial.R(a partir da raiz do pacote) para gerá-lo.
Figure 5 — Categorical cluster map (Kulldorff)
The categorical version visually distinguishes the most likely cluster from secondary clusters and the background, facilitating communication with health managers who need to identify priority intervention regions.
Artefato indisponível — rode
Rscript scripts/modelagem_06_espacial.R(a partir da raiz do pacote) para gerá-lo.
References
Anselin, L. (1988). Spatial Econometrics: Methods and Models. Kluwer Academic Publishers.
Anselin, L. (1995). Local indicators of spatial association — LISA. Geographical Analysis, 27(2), 93–115.
Bivand, R. S., Pebesma, E., & Gomez-Rubio, V. (2013). Applied Spatial Data Analysis with R (2nd ed.). Springer.
Bivand, R. S., & Piras, G. (2015). Comparing implementations of estimation methods for spatial econometrics. Journal of Statistical Software, 63(18), 1–36.
Bivand, R. S., & Wong, D. W. S. (2018). Comparing implementations of global indicators of spatial association. TEST, 27(3), 716–748.
Fotheringham, A. S., & Wong, D. W. S. (1991). The modifiable areal unit problem in multivariate statistical analysis. Environment and Planning A, 23(7), 1025–1044.
Kulldorff, M. (1997). A spatial scan statistic. Communications in Statistics — Theory and Methods, 26(6), 1481–1496.
Kulldorff, M., & Nagarwalla, N. (1995). Spatial disease clusters: detection and inference. Statistics in Medicine, 14(8), 799–810.
LeSage, J., & Pace, R. K. (2009). Introduction to Spatial Econometrics. CRC Press / Taylor & Francis.
Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23.
Openshaw, S., & Taylor, P. J. (1979). A million or so correlation coefficients: three experiments on the modifiable areal unit problem. In N. Wrigley (Ed.), Statistical Applications in the Spatial Sciences (pp. 127–144). Pion.
Tiefelsdorf, M., Griffith, D. A., & Boots, B. (1999). A variance- stabilizing coding scheme for spatial link matrices. Environment and Planning A, 31(1), 165–180.