Skip to contents

Specify a conditional autoregressive (CAR) spatial random effect. Supports both intrinsic CAR (ICAR) and proper CAR variants.

Usage

spatial_car(
  adjacency,
  level = c("group", "obs"),
  group_var = NULL,
  proper = FALSE,
  shared = TRUE,
  parameterization = c("standard", "collapsed")
)

Arguments

adjacency

Adjacency matrix (sparse or dense). A symmetric matrix where entry (i,j) is 1 if areas i and j are neighbors, 0 otherwise.

level

Level at which spatial structure applies:

  • "group": Spatial effect at the grouping variable level (e.g., sites). Requires group_var to be specified.

  • "obs": Spatial effect at the observation level.

group_var

Name of the grouping variable in data (required if level = "group").

proper

Logical; if FALSE (default), uses Intrinsic CAR (ICAR) with rho = 1 fixed. If TRUE, uses proper CAR with rho estimated. See Details.

shared

Logical; if TRUE (default), spatial effect enters both numerator and denominator linear predictors identically.

parameterization

Parameterization of the spatial random effect. Either "standard" (default) or "collapsed" to marginalize the spatial variance for improved mixing in sparse-graph regimes.

Value

A ratiod_spatial object

Details

The CAR model specifies that:

$$\phi_i | \phi_{-i} \sim N\left(\rho \frac{\sum_{j \sim i} \phi_j}{n_i}, \frac{\sigma^2}{n_i}\right)$$

where \(n_i\) is the number of neighbors of area i and \(j \sim i\) denotes that j is a neighbor of i.

This leads to a precision matrix: $$Q = \tau (D - \rho W)$$

where D is the diagonal matrix of neighbor counts and W is the adjacency matrix.

ICAR (proper = FALSE, default)

  • Sets rho = 1 (fixed)

  • Improper prior (rank-deficient Q)

  • Requires sum-to-zero constraint for identifiability

  • Simpler: one fewer parameter to estimate

  • Standard choice for disease mapping

  • Equivalent to RW1 on a graph

Proper CAR (proper = TRUE)

  • Estimates rho in (0, 1) from data

  • Proper prior (integrates to 1)

  • rho measures spatial autocorrelation strength

  • rho -> 0: approaches independence (IID)

  • rho -> 1: approaches ICAR

  • More flexible but additional parameter to estimate

  • Prior: rho ~ Beta(1, 1) (uniform on (0, 1))

See also

spatial_bym2() for decomposed spatial + IID effects, spatial_gp() for continuous spatial effects

Examples

# Create adjacency matrix for 10 regions (chain structure)
adj <- matrix(0, 10, 10)
for (i in 1:9) {
  adj[i, i+1] <- adj[i+1, i] <- 1
}

# ICAR (default, rho = 1 fixed)
icar <- spatial_car(adj, level = "group", group_var = "site")
print(icar)
#> tulpaRatio spatial specification
#> ===========================
#> 
#> Type: ICAR (Intrinsic CAR) 
#> Level: group 
#> Spatial units: 10 
#> Shared: Yes (enters both processes) 
#> Group variable: site 
#>   (rho fixed at 1, sum-to-zero constraint applied)

# Proper CAR (rho estimated)
proper_car <- spatial_car(adj, level = "group", group_var = "site",
                          proper = TRUE)
print(proper_car)
#> tulpaRatio spatial specification
#> ===========================
#> 
#> Type: Proper CAR 
#> Level: group 
#> Spatial units: 10 
#> Shared: Yes (enters both processes) 
#> Group variable: site 
#> Rho bounds: [0, 1]
#>   (spatial autocorrelation parameter, estimated from data)

# \donttest{
# Generate synthetic data with spatial structure
set.seed(123)
n_sites <- 10
n_per_site <- 5
df <- data.frame(
  site = rep(1:n_sites, each = n_per_site),
  x = rnorm(n_sites * n_per_site),
  count = rpois(n_sites * n_per_site, 20),
  effort = rgamma(n_sites * n_per_site, shape = 5, rate = 1)
)

# ICAR model (standard disease mapping approach)
fit_icar <- tratio(
  count | effort ~ x,
  data = df,
  family = ratiod_poisson_gamma(),
  spatial = spatial_car(adj, level = "group", group_var = "site"),
  mode = "hmc",
  control = list(iter = 200, warmup = 100, chains = 1)
)
#> Inference: Exact (Tier 1)
#>   Backend: hmc
#> Fitting ratio model...
#>   Family: poisson_gamma
#>   Observations: 50
#>   Iterations: 200 (warmup: 100)
#> Running NUTS sampler...
#>   Parameters: 16
#>   Iterations: 200 (warmup: 100)
#>   Chains: 1 (cores: 1)
#>   Spatial: icar (10 units)

# Proper CAR model (estimate spatial autocorrelation)
fit_car <- tratio(
  count | effort ~ x,
  data = df,
  family = ratiod_poisson_gamma(),
  spatial = spatial_car(adj, level = "group", group_var = "site",
                        proper = TRUE),
  mode = "hmc",
  control = list(iter = 200, warmup = 100, chains = 1)
)
#> Inference: Exact (Tier 1)
#>   Backend: hmc
#> Fitting ratio model...
#>   Family: poisson_gamma
#>   Observations: 50
#>   Iterations: 200 (warmup: 100)
#> Running NUTS sampler...
#>   Parameters: 17
#>   Iterations: 200 (warmup: 100)
#>   Chains: 1 (cores: 1)
#>   Spatial: car_proper (10 units)

# Extract rho from proper CAR
summary(fit_car)  # Shows rho_spatial parameter
#> ratio model summary
#> ===================
#> 
#> Inference: Exact (Tier 1) via hmc
#> Family: poisson_gamma 
#> 
#> Fixed effects (numerator):
#>    parameter   mean    sd   2.5% 97.5%  rhat ess_bulk
#>  beta_num[1]  3.025 0.043  2.937 3.094 1.135        6
#>  beta_num[2] -0.029 0.028 -0.086 0.022 1.015       51
#> 
#> Fixed effects (denominator):
#>      parameter  mean    sd   2.5% 97.5%  rhat ess_bulk
#>  beta_denom[1] 1.609 0.066  1.494 1.736 1.037       25
#>  beta_denom[2] 0.002 0.070 -0.110 0.173 0.996       68
#> 
#> Variance components:
#>    parameter    mean     sd   2.5%   97.5%  rhat ess_bulk
#>  rho_spatial   0.483  0.296  0.059   0.936 1.019       19
#>        shape   4.855  0.879  3.264   6.584 0.998       51
#>  tau_spatial 194.159 99.607 46.585 408.022 1.376       37
#> 
#> Diagnostics:
#>   Divergences: 0 
#>   Avg. acceptance: 0.928 
#>   Chains: 1 
#>   Iterations: 200 
#>   Warmup: 100 
# }