--- title: "**Dependence-Robust Inference in gdpar (Axis 2)**" subtitle: "Making the uncertainty honest under temporal and spatial dependence, without modelling it (Block 9, Axis 2)" author: "**José Mauricio Gómez Julián**" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true toc_depth: 3 vignette: > %\VignetteIndexEntry{Dependence-Robust Inference in gdpar (Axis 2)} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( echo = TRUE, message = FALSE, warning = FALSE, collapse = TRUE, comment = "#>", eval = FALSE ) ``` # **1. What this vignette covers** gdpar's Path 1 estimates — Empirical-Bayes (`gdpar_eb`) or full-Bayes (`gdpar`) — assume the observations are **conditionally independent** given the mean structure. When the data carry **temporal** (serial) or **spatial** autocorrelation, that assumption is violated: the point estimates remain consistent if the mean structure is correctly specified, but the model-based (posterior / Laplace) standard errors are **too narrow** and the intervals **under-cover**. Sections 2–3 use the Empirical-Bayes path; Section 4 shows the identical workflow on a full-Bayes fit. Axis 2 of Block 9 is the *inferential* response to this. It is deliberately **not** a model of the dependence: > **Honest scope.** gdpar does **not** model the correlated noise or the spatial > random field (that is Axis 1 / a later modelling block, deferred and > evidence-gated). Axis 2 only makes the *inference* robust to dependence. The > stance is the working-independence + robust-variance estimator of > Liang & Zeger (1986): the **point estimates are unchanged**; only the reported > uncertainty is re-estimated to be dependence-robust. Two symmetric pairs of functions, sharing one internal refit engine: | Dependence | Diagnostic | Robust SE / intervals | |---|---|---| | **Temporal** | `gdpar_dependence_diagnostic()` | `gdpar_dependence_robust()` | | **Spatial** | `gdpar_spatial_dependence_diagnostic()` | `gdpar_spatial_dependence_robust()` | The workflow is always the same: **diagnose first**, and only if dependence is flagged, **re-estimate the uncertainty**. # **2. The temporal pair (recap)** ```{r temporal} library(gdpar) set.seed(1) n <- 150 x <- rnorm(n) # AR(1) errors: serial dependence the working-independence fit ignores. y <- 1 + 0.5 * x + as.numeric(stats::arima.sim(list(ar = 0.6), n)) df <- data.frame(x = x, y = y, t = seq_len(n)) fit <- gdpar_eb(y ~ x, amm = amm_spec(a = ~ x), data = df, chains = 2, iter_warmup = 300, iter_sampling = 300) # Step 1 — diagnose. Lag-1 autocorrelation, Durbin-Watson, Ljung-Box. gdpar_dependence_diagnostic(fit, index = df$t) # Step 2 — if flagged, re-estimate the uncertainty by a temporal block bootstrap. gdpar_dependence_robust(fit, data = df, index = df$t, B = 199, seed = 1) ``` The robust table reports, per coefficient, the `estimate` (unchanged), the `model_se`, the bootstrap `robust_se`, their ratio `se_ratio` and percentile `ci_lower` / `ci_upper`. A `se_ratio > 1` means the model-based SE understates the dependence-robust SE. **The block length.** By default `block_length = NULL` uses the rate-optimal `round(n^(1/3))` (it fixes only the *rate*). You may fix an integer manually, or let the data choose it: ```{r temporal-auto} # Data-driven block length: the Politis-White (2004) automatic selector, # computed from the residuals (no extra refit), with the rate as fallback. gdpar_dependence_robust(fit, data = df, index = df$t, block_length = "auto", B = 199, seed = 1) ``` `"auto"` runs the canonical Politis & White (2004) rule (Patton, Politis & White 2009 correction): it reads the residual autocorrelations, finds the lag beyond which they are negligible, and returns `b_opt = (2 ĝ² / D)^(1/3) n^(1/3)` with the overlapping-block constant `D = (4/3) spec²`. Stronger serial dependence gives a longer block; white-noise residuals give unit blocks; a degenerate series falls back to the rate. The chosen value and method are reported in `block_length` and `block_length_method`. (The selector assumes the fitted parameter count is small relative to `n`.) # **3. The spatial pair** The spatial functions replace exactly two pieces of the temporal machinery — the **statistic** (lag-1 autocorrelation becomes **Moran's I**) and the **resampling** (1-D contiguous blocks become **2-D spatial blocks**) — and reuse everything else. ## 3.1. Diagnostic: Moran's I ```{r spatial-diagnostic} set.seed(2) n <- 200 gx <- runif(n); gy <- runif(n) # spatial coordinates x <- rnorm(n) # An omitted smooth spatial trend lands in the residuals. y <- 1 + 0.5 * x + 3 * (gx + gy) + rnorm(n, sd = 0.3) df <- data.frame(x = x, y = y) fit_sp <- gdpar_eb(y ~ x, amm = amm_spec(a = ~ x), data = df, chains = 2, iter_warmup = 300, iter_sampling = 300) gdpar_spatial_dependence_diagnostic(fit_sp, coords = cbind(gx, gy), seed = 1) ``` Moran's I is $$ I \;=\; \frac{n}{S_0}\, \frac{\sum_i \sum_j w_{ij}\,(r_i - \bar r)(r_j - \bar r)} {\sum_i (r_i - \bar r)^2}, \qquad S_0 = \sum_i \sum_j w_{ij}, $$ with $r$ the residuals and $W = (w_{ij})$ a **spatial weight matrix**. Under the null of spatial exchangeability $\mathbb{E}[I] = -1/(n-1)$. **Choosing the weights.** By default gdpar builds a **row-standardized $k$-nearest-neighbour** graph (so $S_0 = n$), with the declared heuristic $k = \max(4, \min(\lfloor \log n \rceil, n-1))$ — robust to irregular spacing and guaranteeing no isolated point. Alternatives: * `weights = "distance"` — a distance band whose threshold is the smallest that isolates no location. * `W = ` — supply your own neighbourhood (adjacency, flow network, administrative contiguity). This is the right choice whenever domain knowledge defines the structure; it is row-standardized internally. **Significance.** The default is a **two-sided permutation test** (`n_perm = 999`): the residuals are relabelled across locations, $I$ is recomputed, and $p = (1 + \#\{|I_{\text{perm}} - \mathbb{E}[I]| \ge |I - \mathbb{E}[I]|\}) / (n_{\text{perm}} + 1)$. It assumes neither normal residuals nor a symmetric $W$, so it is safe with Dunn-Smyth residuals and the asymmetric kNN graph. The analytic Cliff-Ord normal approximation is available via `test = "analytic"` (cheaper, but it warns under an asymmetric $W$). ## 3.2. Robust SE: spatial block bootstrap ```{r spatial-robust} gdpar_spatial_dependence_robust(fit_sp, data = df, coords = cbind(gx, gy), B = 199, seed = 1) ``` The bounding box of `coords` is tiled into a `g × g` grid; non-empty cells are resampled with replacement and concatenated to length `n`. By default the grid **origin is randomized** per replicate (`random_origin = TRUE`, Politis-Romano-Lahiri), which breaks the deterministic cell-boundary artifact. An overlapping `scheme = "moving"` is also available. The output table has the same columns as the temporal one. ## 3.3. The default block size, and why `n^(1/4)` The block side per axis defaults to `g = max(2, round(n^(1/4)))`. This is the $d = 2$ case of the rate that minimises the **mean-squared error of the block-bootstrap variance estimator**. Writing $M$ for the points per block (so the block has linear extent $M^{1/d}$ per axis): * bias from dependence broken at block edges: $O(M^{-1/d})$ (Künsch 1989; Hall, Horowitz & Jing 1995), * estimator variance: $O(M/n)$, so $\mathrm{MSE}(M) \sim M^{-2/d} + M/n$ is minimised at $M \sim n^{\,d/(d+2)}$. At $d = 1$ this gives $M \sim n^{1/3}$ points per block — **exactly** the temporal `block_length = round(n^(1/3))` default — and at $d = 2$ it gives $M \sim n^{1/2}$, i.e. $g^2 = n/M \sim n^{1/2}$ cells, hence $g \sim n^{1/4}$ cells per axis. The exponent is therefore the variance-optimal rate that reduces correctly to the canonical temporal rate. > **Registered dissent (D100).** A decorrelating cross-lineage review argued for > the $n^{1/(d+4)}$ rate ($n^{1/6}$ at $d = 2$). That rate governs a *different* > estimand — the second-order bias / two-sided distribution-function coverage, > which gives $n^{1/5}$ at $d = 1$ and so does **not** reduce to the variance > default's $n^{1/3}$. It is recorded as a dissent, not adopted. ## 3.4. Data-driven block size (`block_size = "auto"`) The default above fixes only the *rate*. Its *constant* can be chosen from the data — but, unlike the temporal case, Politis & White (2004) has **no** established spatial plug-in (its flat-top spectral-density-at-zero estimator does not extend cleanly to a field in the plane). gdpar therefore calibrates the cells-per-axis `g` over a grid of candidates: ```{r spatial-auto} gdpar_spatial_dependence_robust(fit_sp, data = df, coords = cbind(gx, gy), block_size = "auto", B = 199, seed = 1) ``` For each candidate `g`, cheap (no-refit) spatial block resamples give the bootstrap variance $V(g)$ of the **design-weighted residual functionals** $(1/n)\,[1, \tilde{gx}, \tilde{gy}]^\top z$ — these are the influence directions of the coefficient, so their optimal block size matches the coefficient's, which the residual mean alone would not. The block size minimises an empirical mean-squared error, $$ g^\ast \;=\; \arg\min_g\;\Big[\underbrace{(\tilde V(g) - \tilde V(g_{\min}))^2} _{\text{squared bias}} \;+\; \underbrace{c\,V(g)^2 / n_{\text{tiles}}(g)} _{\text{variance}}\Big], $$ with the bias **anchored at the largest blocks** $g_{\min}$ (the least biased, since the dependence-breaking bias of the variance estimator grows like $g/\sqrt n$) and the variance scaling like the inverse number of blocks (Lahiri 2003). Stronger / longer-range spatial dependence is captured by larger blocks (smaller `g`); a short-range or near-independent field by smaller blocks (larger `g`); a degenerate calibration falls back to the $n^{1/4}$ rate. The choice and method are reported in `block_size` and `block_size_method`. > **Provenance and honest scope (D101).** A decorrelating cross-lineage review > supplied the empirical-MSE skeleton; two of its concrete choices — the bias > anchor and the variance term — were **corrected after an audit and empirical > validation**, because the proposed forms would have made the selector > anticonservative (anchoring at the smallest blocks) or non-adaptive (a > Monte-Carlo jackknife variance that vanishes with the resample count). A single > **isotropic** `g` is used; strongly anisotropic residual dependence is a > documented limitation (the minimal fix, two coordinate-wise calibrations, is > deferred). As everywhere in Axis 2, this only sizes the resampling blocks — it > does not model the dependence. # **4. The full-Bayes path** Everything above was shown on the Empirical-Bayes path (`gdpar_eb`). The exact same four functions also accept a **scalar full-Bayes fit** (`gdpar`), so the EB/FB asymmetry is closed: diagnose, then — if flagged — re-estimate, with no change of API. ```{r fb, eval = FALSE, purl = FALSE} # A full-Bayes fit instead of an Empirical-Bayes one: fit_fb <- gdpar(y ~ x, amm = amm_spec(a = ~ x), data = df, chains = 2, iter_warmup = 300, iter_sampling = 300) # Same diagnostic, same robust SE -- only the object class changes. gdpar_dependence_diagnostic(fit_fb, index = df$t) gdpar_dependence_robust(fit_fb, data = df, index = df$t, B = 199, seed = 1) ``` What differs is **internal**, and worth understanding before you read the table: * **Point estimate and model SE.** On the full-Bayes path the per-coefficient point estimate is the **posterior mean** and `model_se` is the **posterior standard deviation** (vs. the Laplace mode / conditional posterior SD on the EB path). `robust_se` is, as always, the block-bootstrap SD of the per-refit point estimate, so `se_ratio = robust_se / model_se` stays a like-for-like SD-vs-SD ratio. The posterior mean / SD are chosen (over median / IQR) to keep that parity and to avoid an undeclared normal-scaling constant. * **Cost.** Each refit re-runs the **full** HMC, so a full-Bayes `gdpar_dependence_robust()` is markedly more expensive than the Empirical-Bayes one. Keep `B` modest, and raise `iter_sampling` rather than `B` if the refit ESS (reported in the result's `refit_diagnostics`) is low — a finite-iteration refit slightly and *conservatively* inflates `robust_se`. * **Reading `se_ratio` under an informative prior.** Unlike the EB path, a full-Bayes `se_ratio < 1` is usually **benign**: an informative prior concentrates the posterior beyond what the data alone support, so the posterior SD is smaller than the bootstrap SD even under correct independent specification (the conjugate-Gaussian algebra gives $\text{se\_ratio}^2 = n\tau/(n\tau+\tau_0) < 1$ with prior precision $\tau_0$). Only `se_ratio` clearly **above** 1 flags dependence / misspecification. * **EB vs FB are different estimands for `theta_ref`.** The EB point estimate is the Laplace *mode*; the full-Bayes one is the posterior *mean*. They coincide asymptotically (Bernstein–von Mises) but may differ in finite samples, so the two paths' tables need not agree to the last digit on the same data. * **Convergence accounting.** The result carries `refit_diagnostics` (aggregate `max_rhat`, `min_ess_bulk`, divergent / high-R-hat refit counts). Under-converged refits are **never excluded or down-weighted** — that screen would be non-random and would bias the SE — but a single note is emitted when a refit's R-hat clearly exceeds 1.05. A *bagged* / widened posterior (BayesBag) would be a different object — a re-architected estimator, not a robust variance for the same one — and is a deliberately deferred lateral; Axis 2 keeps its honest scope, *robust variance, not better estimates*, on both paths. # **5. Reading the result, and the caveats** * **`se_ratio > 1`** ⇒ the model-based uncertainty understated the dependence-robust uncertainty; trust the robust interval. **`se_ratio ≈ 1`** ⇒ little correction needed. * **Coordinates are Euclidean.** Project lon/lat first (e.g. to UTM); raw lon/lat distorts the neighbour graph, severely at high latitudes. Great-circle distance is deliberately not supported, to avoid a heavy **sf** / **geosphere** dependency. * **Moran's I tests residual exchangeability, not its cause.** A significant $I$ may reflect true spatial dependence **or** model misspecification (e.g. an omitted nonlinear effect). Interpret accordingly — a misspecified mean structure is better fixed than bootstrapped around. * **Honest scope, restated.** The bootstrap delivers robust *variance*, not better point estimates, and is valid for weak / short-range dependence relative to the block size; it does not rescue long-memory or strong long-range dependence. # **References** * Cliff, A. D. & Ord, J. K. (1981). *Spatial Processes: Models and Applications*. Pion, London. * Hall, P., Horowitz, J. L. & Jing, B.-Y. (1995). On blocking rules for the bootstrap with dependent data. *Biometrika* 82(3), 561-574. * Künsch, H. R. (1989). The jackknife and the bootstrap for general stationary observations. *Annals of Statistics* 17(3), 1217-1241. * Lahiri, S. N. (2003). *Resampling Methods for Dependent Data*. Springer. * Liang, K.-Y. & Zeger, S. L. (1986). Longitudinal data analysis using generalized linear models. *Biometrika* 73(1), 13-22. * Patton, A., Politis, D. N. & White, H. (2009). Correction to "Automatic block-length selection for the dependent bootstrap". *Econometric Reviews* 28(4), 372-375. * Politis, D. N. & White, H. (2004). Automatic block-length selection for the dependent bootstrap. *Econometric Reviews* 23(1), 53-70. * Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. *Biometrika* 37(1/2), 17-23. * Nordman, D. J. & Lahiri, S. N. (2004). On optimal spatial subsample size for variance estimation. *Annals of Statistics* 32(5), 1981-2027. * Politis, D. N. & Romano, J. P. (1992). A circular block resampling procedure for stationary data. In *Exploring the Limits of Bootstrap*, 263-270. Wiley.