loess-rs
A high-performance implementation of LOESS (Locally Estimated Scatterplot Smoothing) in Rust. This crate provides a robust, production-ready implementation with support for confidence intervals, multiple kernel functions, and optimized execution modes.
How LOESS works
LOESS creates smooth curves through scattered data using local weighted neighborhoods:
LOESS vs. LOWESS
| Feature | LOESS (This Crate) | LOWESS |
|---|---|---|
| Polynomial Degree | Linear, Quadratic, Cubic, Quartic | Linear (Degree 1) |
| Dimensions | Multivariate (n-D support) | Univariate (1-D only) |
| Flexibility | High (Distance metrics) | Standard |
| Complexity | Higher (Matrix inversion) | Lower (Weighted average/slope) |
LOESS can fit higher-degree polynomials for more complex data:
LOESS can also handle multivariate data (n-D), while LOWESS is limited to univariate data (1-D):
[!TIP] Note: For a simple, lightweight, and fast LOWESS implementation, use
lowesscrate.
Features
- Robust Statistics: IRLS with Bisquare, Huber, or Talwar weighting for outlier handling.
- Multidimensional Smoothing: Support for n-D data with customizable distance metrics (Euclidean, Manhattan, etc.).
- Flexible Fitting: Linear, Quadratic, Cubic, and Quartic local polynomials.
- Uncertainty Quantification: Point-wise standard errors, confidence intervals, and prediction intervals.
- Optimized Performance: Interpolation surface with Tensor Product Hermite interpolation and streaming/online modes for large or real-time datasets.
- Parameter Selection: Built-in cross-validation for automatic smoothing fraction selection.
- Flexibility: Multiple weight kernels (Tricube, Epanechnikov, etc.) and
no_stdsupport (requiresalloc). - Validated: Numerical twin of R's
stats::loesswith exact match (< 1e-12 diff).
Performance
Benchmarked against R's loess. Achieves 4.4×–53× faster performance across all tested scenarios. No regressions observed.
Summary
| Category | Matched | Median Speedup | Mean Speedup |
|---|---|---|---|
| Polynomial Degrees | 2 | 21.67× | 21.67× |
| Fraction | 6 | 13.36× | 19.70× |
| Iterations | 6 | 16.35× | 15.90× |
| Pathological | 4 | 16.14× | 16.27× |
| Dimensions | 3 | 7.98× | 8.01× |
| Scalability | 2 | 5.86× | 5.86× |
| Genomic | 2 | 5.27× | 5.27× |
| Financial | 3 | 4.88× | 5.97× |
| Scientific | 3 | 4.46× | 5.28× |
Top 10 Performance Wins
| Benchmark | Rust | R | Speedup |
|---|---|---|---|
| fraction_0.67 | 0.83ms | 44.80ms | 53.71× |
| fraction_0.5 | 1.22ms | 32.25ms | 26.50× |
| degree_quadratic | 0.75ms | 19.21ms | 25.52× |
| high_noise | 1.60ms | 34.68ms | 21.68× |
| iterations_1 | 0.80ms | 15.88ms | 19.94× |
| iterations_0 | 0.75ms | 13.68ms | 18.25× |
| degree_linear | 0.78ms | 13.92ms | 17.81× |
| clustered | 1.15ms | 19.74ms | 17.17× |
| iterations_2 | 0.97ms | 16.63ms | 17.13× |
| iterations_3 | 1.13ms | 17.56ms | 15.57× |
Check Benchmarks for detailed results and reproducible benchmarking code.
Robustness Advantages
This implementation includes several robustness features beyond R's loess:
MAD-Based Scale Estimation
Uses MAD-based scale estimation for robustness weight calculations:
s = median(|r_i - median(r)|)
MAD is a breakdown-point-optimal estimator—it remains valid even when up to 50% of data are outliers, compared to the median of absolute residuals used by some other implementations.
Median Absolute Residual (MAR), which is the default Cleveland's choice, is also available through the scaling_method parameter.
Configurable Boundary Policies
R's loess uses asymmetric windows at data boundaries, which can introduce edge bias. This implementation offers configurable boundary policies to mitigate this:
- Extend (default): Pad with constant values for symmetric windows
- Reflect: Mirror data at boundaries (best for periodic data)
- Zero: Pad with zeros (signal processing applications)
- NoBoundary: Original R behavior (no padding)
Boundary Degree Fallback
When using Interpolation mode with higher polynomial degrees (Quadratic, Cubic), vertices outside the tight data bounds can produce unstable extrapolation. This implementation offers a configurable boundary degree fallback:
true(default): Reduce to Linear fits at boundary vertices (more stable)false: Use full requested degree everywhere (matches R exactly)
Validation
The Rust loess-rs crate is a numerical twin of R's loess implementation:
| Aspect | Status | Details |
|---|---|---|
| Accuracy | ✅ EXACT MATCH | Max diff < 1e-12 across all scenarios |
| Consistency | ✅ PERFECT | 20/20 scenarios pass with strict tolerance |
| Robustness | ✅ VERIFIED | Robust smoothing matches R exactly |
Check Validation for detailed scenario results.
Installation
Add this to your Cargo.toml:
[]
= "0.2"
For no_std environments:
[]
= { = "0.2", = false }
Quick Start
use *;
Summary:
Data points: 5
Fraction: 0.5
Smoothed Data:
X Y_smooth
--------------------
1.00 2.00000
2.00 4.10000
3.00 5.90000
4.00 8.20000
5.00 9.80000
Builder Methods
All builder parameters have sensible defaults. You only need to specify what you want to change.
use *;
new
// Smoothing span (0, 1] - default: 0.67
.fraction
// Polynomial degree - default: Linear
.degree
// Number of dimensions - default: 1
.dimensions
// Distance metric - default: Euclidean
.distance_metric
// Robustness iterations - default: 3
.iterations
// Kernel selection - default: Tricube
.weight_function
// Robustness method - default: Bisquare
.robustness_method
// Boundary handling - default: Extend
.boundary_policy
// Boundary degree fallback - default: true
.boundary_degree_fallback
// Confidence intervals (Batch only)
.confidence_intervals
// Prediction intervals (Batch only)
.prediction_intervals
// Include diagnostics
.return_diagnostics
.return_residuals
.return_robustness_weights
// Cross-validation (Batch only)
.cross_validate
// Auto-convergence
.auto_converge
// Interpolation settings
.surface_mode
// Interpolation cell size - default: 0.2
.cell
// Execution mode
.adapter
// Build the model
.build?;
Result Structure
[!TIP] Using with ndarray: While the result struct uses
Vec<T>for maximum compatibility, you can effortlessly convert any field to anArray1usingArray1::from_vec(result.y).
Streaming Processing
For datasets that don't fit in memory:
let mut processor = new
.fraction
.iterations
.adapter
.chunk_size
.overlap
.build?;
// Process data in chunks
let result1 = processor.process_chunk?;
let result2 = processor.process_chunk?;
// Finalize to get remaining buffered data
let final_result = processor.finalize?;
Online Processing
For real-time data streams:
let mut processor = new
.fraction
.iterations
.adapter
.window_capacity
.build?;
// Process points as they arrive
for i in 1..=10
Parameter Selection Guide
Fraction (Smoothing Span)
- 0.1-0.3: Fine detail, may be noisy
- 0.3-0.5: Moderate smoothing (good for most cases)
- 0.5-0.7: Heavy smoothing, emphasizes trends
- 0.7-1.0: Very smooth, may over-smooth
- Default: 0.67 (Cleveland's choice)
Robustness Iterations
- 0: No robustness (fastest, sensitive to outliers)
- 1-3: Light to moderate robustness (recommended)
- 4-6: Strong robustness (for contaminated data)
- 7+: Diminishing returns
Polynomial Degree
- Constant: Local weighted mean (smoothing only)
- Linear (default): Standard LOESS, good bias-variance balance
- Quadratic: Better for peaks/valleys, higher variance
- Cubic/Quartic: Specialized high-order fitting
Kernel Function
- Tricube (default): Best all-around, Cleveland's original choice
- Epanechnikov: Theoretically optimal MSE
- Gaussian: Maximum smoothness, no compact support
- Uniform: Fastest, least smooth (moving average)
Boundary Policy
- Extend (default): Pad with constant values
- Reflect: Mirror data at boundaries (for periodic/symmetric data)
- Zero: Pad with zeros (signal processing)
- NoBoundary: Original Cleveland behavior
Note: For nD data,
Extenddefaults toNoBoundaryto preserve regression accuracy.
Examples
MSRV
Rust 1.85.0 or later (2024 Edition).
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
References
- Cleveland, W.S. (1979). "Robust Locally Weighted Regression and Smoothing Scatterplots". Journal of the American Statistical Association.
- Cleveland, W.S. & Devlin, S.J. (1988). "Locally Weighted Regression: An Approach to Regression Analysis by Local Fitting". Journal of the American Statistical Association.