--- title: "Introduction to spconform: Spatial and Spatio-Temporal Conformal Prediction" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Introduction to spconform: Spatial and Spatio-Temporal Conformal Prediction} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 6.5, fig.height = 5, fig.align = "center", eval = requireNamespace("sp", quietly = TRUE) ) ``` ```{r setup} library(spconform) ``` ## Overview `spconform` provides distribution-free, finite-sample prediction intervals for spatial and spatio-temporally dependent data by relaxing the standard exchangeability assumption. It provides two foundational procedures: - `scp_geostatistical()` for point-referenced (geostatistical) data, implementing locally weighted split conformal prediction with spatial (and spatio-temporal) distance kernels. - `scp_areal()` for areal (lattice) data, implementing neighbourhood-weighted leave-one-out conformal prediction based on graph adjacency structures. - `diagnose()` for comprehensive multi-panel diagnostics: assessing marginal validity, Winkler Interval Score (WIS) sharpness, conditional coverage across spatial strata, boundary effects, and Moran's $I$ spatial residual autocorrelation. Both procedures are **model-agnostic**: you can supply any point predictor (e.g., Random Forest, Kriging, GAM, Splines, or Neural Networks), and `spconform` constructs finite-sample valid prediction intervals regardless of model misspecification. --- ## 1. Geostatistical (Point-Referenced) Prediction We illustrate the workflow on the `meuse` river dataset (Pebesma and Bivand 2005), a classic environmental spatial benchmark. ```{r} library(sp) data(meuse) coords <- as.matrix(meuse[, c("x", "y")]) coords_scaled <- scale(coords) y <- log(meuse$zinc) ``` ### Visualizing the Spatial Layout ```{r fig-layout} plot(meuse$x, meuse$y, col = rgb(0.2, 0.4, 0.8, 0.6), pch = 19, xlab = "Easting (m)", ylab = "Northing (m)", main = "Meuse River Topsoil Sampling Locations (n = 155)") ``` ### Defining a Model-Agnostic Predictor `scp_geostatistical()` accepts any prediction function with signature `function(s_train, y_train, s_new)`: ```{r} pred_fun <- function(s_train, y_train, s_new) { df_tr <- data.frame(y = y_train, x1 = s_train[, 1], x2 = s_train[, 2]) df_new <- data.frame(x1 = s_new[, 1], x2 = s_new[, 2]) fit <- lm(y ~ x1 + x2 + I(x1^2) + I(x2^2) + I(x1 * x2), data = df_tr) as.numeric(predict(fit, newdata = df_new)) } ``` ### Fitting Locally Weighted Conformal Prediction Intervals We split the observations into 70% training and 30% independent testing, generating 90% prediction intervals ($\alpha = 0.10$): ```{r} set.seed(42) n <- nrow(coords_scaled) train_idx <- sample(n, floor(0.70 * n)) test_idx <- setdiff(seq_len(n), train_idx) s_train <- coords_scaled[train_idx, ]; y_train <- y[train_idx] s_test <- coords_scaled[test_idx, ]; y_test <- y[test_idx] out <- scp_geostatistical( s_train = s_train, y_train = y_train, s0 = s_test, pred_fun = pred_fun, alpha = 0.10, split = 0.50, seed = 123 ) print(out) summary(out) # Standard S3 methods for seamless integration with R workflows: head(predict(out, interval = "prediction")) head(residuals(out, y_true = y_test, type = "abs")) head(as.data.frame(out)) ``` ```{r fig-intervals} plot(out, y_true = y_test) ``` --- ## 2. Comprehensive Diagnostic Suite (`diagnose()`) `spconform` includes an advanced spatial diagnostic tool that evaluates: 1. **Marginal Coverage** and the strictly proper **Winkler Interval Score (WIS)**. 2. **Spatial Residual Autocorrelation (Moran's $I$)** to verify absence of unmodeled spatial error clustering. 3. **Conditional Coverage across Spatial Strata Quadrants**. 4. **Boundary Proximity Effects** via 2D convex hull geometric analysis. ```{r fig-diagnostics, fig.width = 7.5, fig.height = 6} # Generate structured diagnostic object diag_res <- diagnose(out, y_true = y_test, s_test = s_test, plot = FALSE) # S3 print method displays text summary including Moran's I print(diag_res) # S3 plot method produces multi-panel spatial diagnostic layout plot(diag_res) ``` --- ## 3. Areal (Lattice) Conformal Prediction `scp_areal()` constructs distribution-free prediction intervals for areal units (polygons, counties, grid cells) linked by graph adjacency matrices: ```{r} # Aggregate Meuse observations onto a 6x6 spatial grid xbreaks <- seq(min(meuse$x), max(meuse$x), length.out = 7) ybreaks <- seq(min(meuse$y), max(meuse$y), length.out = 7) meuse$cell_x <- cut(meuse$x, xbreaks, include.lowest = TRUE, labels = FALSE) meuse$cell_y <- cut(meuse$y, ybreaks, include.lowest = TRUE, labels = FALSE) meuse$cell_id <- (meuse$cell_y - 1) * 6 + meuse$cell_x agg <- aggregate(log(zinc) ~ cell_id, data = meuse, FUN = mean) names(agg) <- c("cell_id", "y") cell_coords <- unique(meuse[, c("cell_id", "cell_x", "cell_y")]) agg <- merge(agg, cell_coords, by = "cell_id") agg <- agg[order(agg$cell_id), ] # Construct Rook/Queen graph adjacency matrix n_cells <- nrow(agg) adj <- matrix(0, n_cells, n_cells) for (i in 1:n_cells) { for (j in 1:n_cells) { if (i != j) { dx <- abs(agg$cell_x[i] - agg$cell_x[j]) dy <- abs(agg$cell_y[i] - agg$cell_y[j]) if (dx <= 1 && dy <= 1) adj[i, j] <- 1 } } } # Run 80% Areal Conformal Prediction out_areal <- scp_areal(y = agg$y, adjacency = adj, alpha = 0.20, decay = 1.0) print(out_areal) coverage_report(out_areal, agg$y) ``` ```{r fig-areal-intervals} plot(out_areal, y_true = agg$y) ``` --- ## 4. Software Architecture & Portability `spconform` is implemented in 100% pure Base R (importing only standard `stats`, `graphics`, and `grDevices`), ensuring: - **Zero Heavy Dependencies**: Installs instantly without compilers or external C++ libraries. - **Universal Portability**: 13/13 Green status across all Linux, macOS (Apple Silicon & Intel), and Windows platforms. - **Strict Reproducibility**: Autonomous execution scripts that replicate all findings in sub-second speeds. --- ## References - Mao, H., Martin, R., and Reich, B. J. (2024). Valid Model-Free Spatial Prediction. *Journal of the American Statistical Association*, 119(546), 904–914. \doi{10.1080/01621459.2022.2147531} - Pebesma, E. J., and Bivand, R. S. (2005). Classes and Methods for Spatial Data in R. *R News*, 5(2), 9–13. - Winkler, R. L. (1972). A Decision-Theoretic Approach to Interval Estimation. *Journal of the American Statistical Association*, 67(337), 187–191. - Vovk, V., Gammerman, A., and Shafer, G. (2005). *Algorithmic Learning in a Random World*. Springer.