Expand description
§LOESS — Locally Estimated Scatterplot Smoothing for Rust
The fastest, most robust, and most feature-complete language-agnostic LOESS (Locally Estimated Scatterplot Smoothing) implementation for Rust.
§What is LOESS?
LOESS (Locally Estimated Scatterplot Smoothing) is a nonparametric regression method that fits smooth curves through scatter plots. At each point, it fits a weighted polynomial (typically linear or quadratic) using nearby data points, with weights decreasing smoothly with distance. This creates flexible, data-adaptive curves without assuming a global functional form.
§Documentation
📚 Full Documentation: loess.readthedocs.io
Comprehensive guides, API references, and tutorials.
§Quick Start
§Typical Use
use loess_rs::prelude::*;
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let y = vec![2.0, 4.1, 5.9, 8.2, 9.8];
// Build the model
let model = Loess::new()
.fraction(0.5) // Use 50% of data for each local fit
.iterations(3) // 3 robustness iterations
.build()?;
// Fit the model to the data
let result = model.fit(&x, &y)?;
println!("{}", result);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§Full Features
use loess_rs::prelude::*;
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let y = vec![2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7];
// Build model with all features enabled
let model = Loess::new()
.fraction(0.5) // Use 50% of data for each local fit
.iterations(3) // 3 robustness iterations
.degree("linear") // Polynomial degree (case-insensitive)
.dimensions(1) // Number of dimensions
.distance_metric("euclidean") // Distance metric
.weight_function("tricube") // Kernel function
.robustness_method("bisquare") // Outlier handling
.surface_mode("interpolation") // Surface evaluation mode
.boundary_policy("extend") // Boundary handling
.boundary_degree_fallback(true) // Boundary degree fallback
.scaling_method("mad") // Scaling method
.cell(0.2) // Interpolation cell size
.interpolation_vertices(1000) // Maximum vertices for interpolation
.zero_weight_fallback("use_local_mean") // Fallback policy
.auto_converge(1e-6) // Auto-convergence threshold
.confidence_intervals(0.95) // 95% confidence intervals
.prediction_intervals(0.95) // 95% prediction intervals
.return_diagnostics() // Fit quality metrics
.return_residuals() // Include residuals
.return_robustness_weights() // Include robustness weights
.return_se() // Enable standard error computation
.cv_method("kfold") // Case-insensitive: "kfold" or "loocv"
.cv_k(5) // Number of folds for k-fold CV
.cv_fractions(vec![0.3, 0.7]) // Candidate fractions to evaluate
.cv_seed(123) // Reproducible fold split
.build()?;
let result = model.fit(&x, &y)?;
println!("{}", result);Summary:
Data points: 8
Fraction: 0.5
Robustness: Applied
LOESS Diagnostics:
RMSE: 0.191925
MAE: 0.181676
R^2: 0.998205
Residual SD: 0.297750
Effective DF: 8.00
AIC: -10.41
AICc: inf
Smoothed Data:
X Y_smooth Std_Err Conf_Lower Conf_Upper Pred_Lower Pred_Upper Residual Rob_Weight
----------------------------------------------------------------------------------------------------------------
1.00 2.01963 0.389365 1.256476 2.782788 1.058911 2.980353 0.080368 1.0000
2.00 4.00251 0.345447 3.325438 4.679589 3.108641 4.896386 -0.202513 1.0000
3.00 5.99959 0.423339 5.169846 6.829335 4.985168 7.014013 0.200410 1.0000
4.00 8.09859 0.489473 7.139224 9.057960 6.975666 9.221518 -0.198592 1.0000
5.00 10.03881 0.551687 8.957506 11.120118 8.810073 11.267551 0.261188 1.0000
6.00 12.02872 0.539259 10.971775 13.085672 10.821364 13.236083 -0.228723 1.0000
7.00 13.89828 0.371149 13.170829 14.625733 12.965670 14.830892 0.201719 1.0000
8.00 15.77990 0.408300 14.979631 16.580167 14.789441 16.770356 -0.079899 1.0000§Result and Error Handling
The fit method returns a Result<LoessResult<T>, LoessError>.
Ok(LoessResult<T>): Contains the smoothed data and diagnostics.Err(LoessError): Indicates a failure (e.g., mismatched input lengths, insufficient data).
The ? operator is idiomatic:
use loess_rs::prelude::*;
let model = Loess::new().build()?;
let result = model.fit(&x, &y)?;
// or to be more explicit:
// let result: LoessResult<f64> = model.fit(&x, &y)?;But you can also handle results explicitly:
use loess_rs::prelude::*;
let model = Loess::new().build()?;
match model.fit(&x, &y) {
Ok(result) => {
// result is LoessResult<f64>
println!("Smoothed: {:?}", result.y);
}
Err(e) => {
// e is LoessError
eprintln!("Fitting failed: {}", e);
}
}§Builder Arguments
All builder methods return Self and can be chained. Finalize the builder with
build().
§Core Smoothing
-
fraction(f: T)— Smoothing bandwidth: fraction of the data used for each local fit (range(0, 1]). Smaller → more local and jagged; larger → smoother. Default:0.67. -
iterations(n: usize)— Number of robustness (IRLS) iterations for outlier resistance.0disables robustness weighting. Default:3. -
degree(d: PolynomialDegree)— Degree of the local polynomial fitted at each point.Constant/"constant"(0): weighted mean — fastest, least flexibleLinear/"linear"(1, default): standard LOESS — good balance of speed and accuracyQuadratic/"quadratic"(2): better for curved regionsCubic/"cubic"(3) /Quartic/"quartic"(4): higher flexibility, more expensive
-
weight_function(wf: WeightFunction)— Kernel function for distance-based local weighting. Options:Tricube/"tricube"(default),Epanechnikov/"epanechnikov",Biweight/"biweight",Gaussian/"gaussian",Triangle/"triangle",Cosine/"cosine",Uniform/"uniform". -
robustness_method(rm: RobustnessMethod)— Downweighting method applied to outliers during robustness iterations. Options:Bisquare/"bisquare"(default),Huber/"huber",Talwar/"talwar". -
scaling_method(sm: ScalingMethod)— Residual scale estimator used in robustness weighting. Options:MAD/"mad"(default),MAR/"mar",Mean/"mean". -
custom_weights(w: Vec<T>)— Per-observation case weights applied asw_ij = custom_weights[j] × K(d_ij / h). Higher values increase the influence of an observation on nearby local fits (analogous toweightsin R’sstats::loess). Must have the same length asy. Only applied in Batch mode.
§Surface Evaluation
-
surface_mode(m: SurfaceMode)— How the fitted surface is evaluated.Interpolation/"interpolation"(default): fits at a sparse grid of vertices then interpolates — fast for large datasets.Direct/"direct": fits exactly at every data point — exact but O(n²).
-
cell(c: T)— Cell size for the interpolation vertex grid (default:0.2). Smaller → more vertices, higher accuracy, slower. -
interpolation_vertices(n: usize)— Hard cap on the number of interpolation vertices regardless ofcell. -
boundary_degree_fallback(enabled: bool)— Whentrue(default), vertices outside the tight data range use aLinearfit to avoid unstable extrapolation. Set tofalseto match R’sstats::loessbehavior exactly.
§Neighborhood & Distance
-
dimensions(n: usize)— Number of predictor dimensions (default:1). -
distance_metric(m: DistanceMetric<T>)— Distance metric for neighbor selection.Normalized/"normalized"(default): each dimension scaled to[0, 1]Euclidean/"euclidean": standard L² distanceManhattan/"manhattan": L¹ distanceChebyshev/"chebyshev": L∞ (max) distanceMinkowski(p)/"minkowski:p": Lᵖ distance for arbitrarypWeighted(w): dimension-weighted Euclidean (no string form — requires a weights vector)
§Boundary Handling
-
boundary_policy(p: BoundaryPolicy)— How query points outside the observed data range are handled. Options:Extend/"extend"(default),Reflect/"reflect",Zero/"zero",NoBoundary/"noboundary". -
zero_weight_fallback(p: ZeroWeightFallback)— Fallback when all neighbors of a point have zero weight (degenerate neighborhood).UseLocalMean/"use_local_mean"(default): return the weighted mean of nearby valuesReturnOriginal/"return_original": return the rawyvalueReturnNone/"return_none": returnNaN
§Convergence
auto_converge(tol: T)— Stop robustness iterations early when the relative change in fitted values falls belowtol. Disabled by default.
§Output Options
-
return_diagnostics()— Include fit-quality diagnostics in the result (RMSE, MAE, R², AIC, effective degrees of freedom, residual SD, etc.). -
return_residuals()— Include raw residualsr_i = y_i − ŷ_iin the result. -
return_robustness_weights()— Include the final robustness weightsw_i. -
return_se()— Compute standard errors, hat-matrix trace, and effective number of parameters. Required for confidence/prediction intervals. -
confidence_intervals(level: T)— Enable confidence intervals at the given coverage level (e.g.,0.95). Requiresreturn_se()to also be set. -
prediction_intervals(level: T)— Enable prediction intervals at the given coverage level. Requiresreturn_se()to also be set.
§Cross-Validation
-
cv_method(m: &str)— Cross-validation method, string-based and case-insensitive:"kfold""loocv"
-
cv_k(k: usize)— Number of folds for"kfold"mode (default:5). -
cv_fractions(f: Vec<T>)— Candidate fractions to evaluate during CV. -
cv_seed(s: u64)— Optional seed for reproducible fold splitting.
§Adapter-Specific Options
StreamingLoess (StreamingLoess::new()):
chunk_size(n: usize)— Number of points processed per streaming chunk.overlap(n: usize)— Point overlap between consecutive chunks for smooth boundaries.merge_strategy(s: MergeStrategy)— How overlapping region fits are combined. Options:Average/"average",WeightedAverage/"weighted_average",TakeFirst/"take_first",TakeLast/"take_last".
OnlineLoess (OnlineLoess::new()):
window_capacity(n: usize)— Maximum points kept in the sliding window.min_points(n: usize)— Minimum points required before returning a fit.update_mode(m: UpdateMode)— Window update strategy.Full/"full"(default): full refit on every updateIncremental/"incremental": lightweight incremental update
The crate supports no_std environments for embedded devices and resource-constrained systems.
Disable default features to remove the standard library dependency:
[dependencies]
loess_rs = { version = "0.1", default-features = false }Minimal example for embedded systems:
use loess_rs::prelude::*;
// In an embedded context (e.g., sensor data processing)
fn smooth_sensor_data() -> Result<(), LoessError> {
// Small dataset from sensor readings
let x = vec![1.0_f32, 2.0, 3.0, 4.0, 5.0];
let y = vec![2.1, 3.9, 6.2, 7.8, 10.1];
// Build minimal model (no intervals, no diagnostics)
let model = Loess::new()
.fraction(0.5)
.iterations(2) // Fewer iterations for speed
.build()?;
// Fit the model
let result = model.fit(&x, &y)?;
// Use smoothed values (result.y)
// ...
Ok(())
}Tips for embedded/no_std usage:
- Use
f32instead off64to reduce memory footprint - Keep datasets small (< 1000 points)
- Disable optional features (intervals, diagnostics) to reduce code size
- Use fewer iterations (1-2) to reduce computation time
- Allocate buffers statically when possible to avoid heap fragmentation
§References
- Cleveland, W. S. (1979). “Robust Locally Weighted Regression and Smoothing Scatterplots”
- Cleveland, W. S. & Devlin, S. J. (1988). “Locally Weighted Regression: An Approach to Regression Analysis by Local Fitting”
§srrstats Compliance for rOpenSci Statistical Software Review
@srrstats {G1.0} Statistical literature references documented above (Cleveland 1979, 1988). @srrstats {G1.1} This package provides LOESS smoothing, a nonparametric regression method for fitting smooth curves to scatterplot data using locally weighted polynomial regression. @srrstats {G1.4} All exported functions and types are documented with rustdoc comments. @srrstats {G1.6} Performance characteristics documented: SIMD-optimized solvers, O(n*k) complexity where k is the window size, supports streaming and online modes.
§License
See the repository for license information and contribution guidelines.