lowess
High-performance LOWESS (Locally Weighted Scatterplot Smoothing) for Rust — 40-500× faster than Python's statsmodels with robust statistics, confidence intervals, and parallel execution.
Why This Crate?
- ⚡ Blazingly Fast: 40-500× faster than statsmodels, sub-millisecond smoothing for 1000 points
- 🎯 Production-Ready: Comprehensive error handling, numerical stability, extensive testing
- 📊 Feature-Rich: Confidence/prediction intervals, multiple kernels, cross-validation
- 🚀 Scalable: Parallel execution, streaming mode, delta optimization
- 🔬 Scientific: Validated against R and Python implementations
- 🛠️ Flexible:
no_stdsupport, multiple robustness methods
Quick Start
use Lowess;
let x = vec!;
let y = vec!;
// Basic smoothing
let result = new
.fraction
.fit
.unwrap;
println!;
Installation
[]
= "0.3"
# For no_std environments (requires alloc)
= { = "0.3", = false }
Features at a Glance
| Feature | Description | Use Case |
|---|---|---|
| Robust Smoothing | IRLS with Bisquare/Huber/Talwar weights | Outlier-contaminated data |
| Confidence Intervals | Point-wise standard errors & bounds | Uncertainty quantification |
| Cross-Validation | Auto-select optimal fraction | Unknown smoothing parameter |
| Multiple Kernels | Tricube, Epanechnikov, Gaussian, etc. | Different smoothness profiles |
| Parallel Execution | Multi-threaded via Rayon (std feature) | Large datasets (n > 1000) |
| Streaming Mode | Constant memory usage | Very large datasets |
| Delta Optimization | Skip dense regions | 10× speedup on dense data |
Common Use Cases
1. Robust Smoothing (Handle Outliers)
use Lowess;
# let x = vec!;
# let y = vec!;
let result = new
.fraction
.iterations // Robust iterations
.with_robustness_weights // Return outlier weights
.fit?;
// Check which points were downweighted
if let Some = result.robustness_weights
# Ok::
2. Uncertainty Quantification
use Lowess;
# let x = vec!;
# let y = vec!;
let result = new
.fraction
.with_confidence_intervals
.with_prediction_intervals
.fit?;
// Plot confidence bands
for i in 0..x.len
# Ok::
3. Automatic Parameter Selection
use Lowess;
# let x = vec!;
# let y = vec!;
// Let cross-validation find the optimal smoothing fraction
let result = new
.cross_validate
.fit?;
println!;
println!;
# Ok::
4. Large Dataset Optimization
use Lowess;
# let large_x: = .map.collect;
# let large_y: = large_x.iter.map.collect;
// Enable all performance optimizations
let result = new
.fraction
.delta // Skip dense regions
.parallel // Multi-threaded (requires std feature)
.fit?;
# Ok::
5. Production Monitoring
use Lowess;
# let x = vec!;
# let y = vec!;
let result = new
.fraction
.iterations
.with_diagnostics
.fit?;
if let Some = result.diagnostics
# Ok::
6. Convenience Constructors
Pre-configured builders for common scenarios:
use Lowess;
# let x = vec!;
# let y = vec!;
// For noisy data with outliers
let result = robust.fit?;
// For speed on clean data
let result = quick.fit?;
// For comprehensive analysis
let result = detailed.fit?;
# Ok::
Performance Benchmarks
Comparison against Python's statsmodels on typical workloads:
| Dataset Size | statsmodels | Rust (sequential) | Rust (parallel) | Sequential Speedup | Parallel Speedup |
|---|---|---|---|---|---|
| 100 points | 2.71 ms | 0.17 ms | 0.15 ms | 16× | 32× |
| 1,000 points | 36.32 ms | 8.65 ms | 1.47 ms | 4× | 39× |
| 5,000 points | 373.15 ms | 211.87 ms | 6.97 ms | 2× | 63× |
| 10,000 points | 1,245.80 ms | 897.44 ms | 12.68 ms | 1.4× | 110× |
Benchmarks conducted on ntel Core Ultra 7 268V (8 cores @ up to 5.0 GHz) running Arch Linux (6.17.9-arch1-1). See validation/ directory for detailed methodology and reproducible test scripts.
API Overview
Builder Methods
use ;
new
// Core parameters
.fraction // Smoothing span (0, 1], default: 0.67
.iterations // Robustness iterations, default: 3
.delta // Interpolation threshold
// Kernel selection
.weight_function // Default
// Robustness method
.robustness_method // Default
// Intervals & diagnostics
.with_confidence_intervals
.with_prediction_intervals
.with_both_intervals
.with_diagnostics
.with_all_diagnostics
.with_residuals
.with_robustness_weights
// Parameter selection
.cross_validate
.cross_validate_kfold
.cross_validate_loocv
// Convergence
.auto_converge
.max_iterations
// Performance (requires std feature, enabled by default)
.parallel
// Convenience constructors
// Lowess::robust() // Pre-configured for outliers
// Lowess::quick() // Pre-configured for speed
// Lowess::detailed() // Pre-configured for analysis
;
Result Structure
Advanced Features
Streaming Processing
For datasets too large to fit in memory:
use ;
let variant = new
.fraction
.for_mode
.chunk_size
.build?;
match variant
# Ok::
Online/Incremental Updates
Real-time smoothing with sliding window:
use ;
let variant = new
.fraction
.for_mode
.window_size
.build?;
match variant
# Ok::
ndarray Integration
ndarray is always available (no feature flag needed):
use Lowess;
use Array1;
let x: = linspace;
let y: = x.mapv;
let result = new
.fraction
.fit?;
// Convert back to ndarray
let smoothed = from;
# Ok::
Parameter Selection Guide
Fraction (Smoothing Span)
- 0.1-0.3: Local, captures rapid changes (wiggly)
- 0.4-0.6: Balanced, general-purpose
- 0.7-1.0: Global, smooth trends only
- Default: 0.67 (2/3, Cleveland's choice)
- Use CV when uncertain
Robustness Iterations
- 0: Clean data, speed critical
- 1-2: Light contamination
- 3: Default, good balance (recommended)
- 4-5: Heavy outliers
- >5: Diminishing returns
Kernel Function
- Tricube (default): Best all-around, smooth, efficient
- Epanechnikov: Theoretically optimal MSE
- Gaussian: Very smooth, no compact support
- Uniform: Fastest, least smooth (moving average)
Delta Optimization
- None: Small datasets (n < 1000)
- 0.01 × range(x): Good starting point for dense data
- Manual tuning: Adjust based on data density
Error Handling
use ;
match new.fit
Feature Flags
The crate has only two features:
default: Enablesstdfeaturestd: Standard library support (includes Rayon for parallelism)
# Standard configuration (includes parallel execution)
[]
= "0.3"
# No-std configuration (requires alloc, no parallelism)
[]
= { = "0.3", = false }
Note: There are no separate parallel or ndarray feature flags in v0.3. When std is enabled (default), parallel execution via Rayon is automatically available.
Validation
This implementation has been extensively validated against:
- R's stats::lowess: Numerical agreement to machine precision
- Python's statsmodels: Validated on 44 test scenarios
- Cleveland's original paper: Reproduces published examples
See validation/ directory for cross-language comparison scripts.
MSRV (Minimum Supported Rust Version)
Rust 1.86.0 or later (requires Rust Edition 2024).
Contributing
Contributions welcome! See CONTRIBUTING.md for:
- Bug reports and feature requests
- Pull request guidelines
- Development workflow
- Testing requirements
License
MIT License - see LICENSE file.
References
Original papers:
-
Cleveland, W.S. (1979). "Robust Locally Weighted Regression and Smoothing Scatterplots". Journal of the American Statistical Association, 74(368): 829-836. DOI:10.2307/2286407
-
Cleveland, W.S. (1981). "LOWESS: A Program for Smoothing Scatterplots by Robust Locally Weighted Regression". The American Statistician, 35(1): 54.
Related implementations:
Citation
Author
Amir Valizadeh
📧 thisisamirv@gmail.com
🔗 GitHub
Keywords: LOWESS, LOESS, local regression, nonparametric regression, smoothing, robust statistics, time series, bioinformatics, genomics, signal processing