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"),
  center = TRUE
)

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.

center

Logical; if TRUE (default), the field's mean is removed on its way into the linear predictor, so the intercept carries the level and the field carries deviations from it. The prior still reads the uncentred field. center = FALSE requires proper = TRUE and leaves the mean in the linear predictor, where it is jointly identified with the intercept: on a 36-unit fixture the two then correlate at -0.977 and the intercept's bulk ESS is 71 of 2000 against 1953 under the default, for the same posterior on the level. An intrinsic field (proper = FALSE) has no such choice, since its mean is unidentified until it is removed.

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 = 400, chains = 1, seed = 1)
)

# 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 = 400, chains = 1, seed = 1)
)

# 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
#>  num:(Intercept)  3.019 0.030  2.961 3.073 1.014      159
#>            num:x -0.017 0.036 -0.085 0.046 1.004      180
#> 
#> Fixed effects (denominator):
#>          parameter  mean    sd   2.5% 97.5%  rhat ess_bulk
#>  denom:(Intercept) 1.605 0.070  1.491 1.764 0.998      170
#>            denom:x 0.028 0.072 -0.105 0.183 1.006      108
#> 
#> Variance components:
#>    parameter    mean      sd   2.5%   97.5%  rhat ess_bulk
#>  rho_spatial   0.470   0.285  0.019   0.961 1.002       96
#>        shape   4.759   0.845  3.213   6.448 1.017       70
#>  tau_spatial 217.785 135.142 57.799 549.838 1.000       40
#> 
#> Diagnostics:
#>   Divergences: 0 
#>   Avg. acceptance: 0.899 
#>   Chains: 1 
#>   Iterations: 400 
#>   Warmup: 200 
#>   R-hat > 1.01 for 2 parameter(s), largest 1.017 (shape).
#>   Bulk ESS < 100 for 3 parameter(s), smallest 40 (tau_spatial).
#>   Run longer chains or reparameterise before using these estimates.
# }