--- title: "Multivariate LOESS" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Multivariate LOESS} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ## Overview Standard LOESS operates on a single predictor `x`. Setting `dimensions > 1` extends the neighbourhood search and local polynomial fit into an **n-dimensional predictor space**, enabling surface smoothing over spatial grids, time–altitude combinations, and similar multi-predictor datasets. ![Multivariate LOESS](../man/figures/multivariate_loess.svg) | Dimensions | Use Case | `x` Input Shape | | --- | --- | --- | | `1` | Time series, 1D signal (default) | Numeric vector | | `2` | Spatial surface, 2-predictor model | `n × 2` matrix | | `3+` | High-dimensional regression | `n × d` matrix | > **Note:** Neighbourhood search scales with the number of dimensions. For `d ≥ > 3` keep `fraction` small and consider the `"interpolation"` surface mode (the > default) to reduce computation. --- ## 1D — Standard (Default) Single predictor. No configuration required. ```{r dimensions_1} library(rfastloess) set.seed(42) x <- seq(0, 10, length.out = 200) y <- sin(x) + rnorm(200, sd = 0.2) model <- Loess(fraction = 0.3) result <- fit(model, x, y) cat("First 6 smoothed values (1D LOESS):\n") print(head(result$y)) ``` --- ## 2D — Spatial Surface Two predictors (e.g., latitude/longitude, time/altitude). Pass an `n × 2` matrix as `x`. ```{r dimensions_2} set.seed(42) n <- 100 lat <- runif(n, -pi, pi) lon <- runif(n, -pi, pi) z <- sin(lat) + cos(lon) + rnorm(n, sd = 0.1) x2d <- cbind(lat, lon) # n × 2 matrix model <- Loess(fraction = 0.3, dimensions = 2L) result <- fit(model, x2d, z) cat("First 6 smoothed values (2D LOESS, lat/lon):\n") print(head(result$y)) ``` --- ## 3D and Higher Pass an `n × d` matrix as `x`. Higher dimensions require a larger `fraction` to keep the local neighbourhood populated. ```{r dimensions_3} set.seed(42) n <- 200 x1 <- runif(n) x2 <- runif(n) x3 <- runif(n) y <- x1 + sin(2 * pi * x2) + x3^2 + rnorm(n, sd = 0.1) x3d <- cbind(x1, x2, x3) # n × 3 matrix model <- Loess(fraction = 0.5, dimensions = 3L) result <- fit(model, x3d, y) cat("First 6 smoothed values (3D LOESS):\n") print(head(result$y)) ``` --- ## Distance Metrics for Multivariate Data When `dimensions > 1` you can also control how inter-point distances are computed. | Metric | Description | When to Use | | --- | --- | --- | | `"normalized"` | Scaled by dimension range (default) | Mixed-scale | | `"euclidean"` | Raw Euclidean distance | Same-scale predictors | | `"minkowski:p"` | Minkowski ($L_p$) norm | Custom geometry | | `"weighted"` | Per-dimension via `weighted_metric_weights` | Anisotropic | ```{r dimensions_4} # Reuse the 2D spatial data from above; upweight the lat dimension model <- Loess( fraction = 0.3, dimensions = 2L, distance_metric = "weighted", weighted_metric_weights = c(2.0, 1.0) # lat counts twice ) result <- fit(model, x2d, z) cat("First 6 smoothed values (2D LOESS, weighted distance):\n") print(head(result$y)) ``` --- ## Surface Mode for Multivariate Data | Mode | Behaviour | Speed | | --- | --- | --- | | `"interpolation"` | Grid-fit, interpolate elsewhere (default) | Fast | | `"direct"` | Fit directly at every query point | Exact, slower | ```{r dimensions_5} # Exact fit at every point — slower but no interpolation artefacts model <- Loess(fraction = 0.3, dimensions = 2L, surface_mode = "direct") result <- fit(model, x2d, z) cat("First 6 smoothed values (2D LOESS, direct surface):\n") print(head(result$y)) ``` For large 2D or 3D datasets use `"interpolation"` (default) and tune `cell` and `interpolation_vertices` to control grid resolution. ```{r dimensions_6} model <- Loess( fraction = 0.3, dimensions = 2L, surface_mode = "interpolation", cell = 0.2 ) result <- fit(model, x2d, z) cat("First 6 smoothed values (2D LOESS, interpolation surface):\n") print(head(result$y)) ``` ```{r session-info} sessionInfo() ```