Skip to content

LOESS Project

The fastest, most robust, and most feature-complete language-agnostic LOESS (Locally Weighted Scatterplot Smoothing) implementation for Rust, Python, R, Julia, JavaScript, C++, and WebAssembly.

What is LOESS?

LOESS is a nonparametric regression method that fits smooth curves through scatter plots. At each point, it fits a weighted polynomial using nearby data, with weights decreasing smoothly with distance. This creates flexible, data-adaptive curves without assuming a global functional form.

LOESS Smoothing Concept

Key advantages:

  • No parametric assumptions — Adapts to local data structure
  • Robust to outliers — With robustness iterations enabled
  • Uncertainty quantification — Confidence and prediction intervals
  • Handles irregular sampling — Works with missing regions gracefully

Why this package?

Speed

The loess project beats the competition in terms of speed, whether in single-threaded or multi-threaded parallel execution. It is on average 2-3x faster than R's loess.

For detailed benchmark comparisons, see the Benchmarks page.

Robustness

This implementation is more robust than R's loess due to two key design choices:

MAD-Based Scale Estimation:

For robustness weight calculations, this crate uses Median Absolute Deviation (MAD) for scale estimation:

\[s = \text{median}(|r_i - \text{median}(r)|)\]

In contrast, R's loess uses the median of absolute residuals (MAR):

\[s = \text{median}(|r_i|)\]
  • MAD is a breakdown-point-optimal estimator—it remains valid even when up to 50% of data are outliers.
  • The median-centering step removes asymmetric bias from residual distributions.
  • MAD provides consistent outlier detection regardless of whether residuals are centered around zero.

Boundary Padding:

This crate applies a range of different boundary policies at dataset edges:

  • Extend: Repeats edge values to maintain local neighborhood size.
  • Reflect: Mirrors data symmetrically around boundaries.
  • Zero: Pads with zeros (useful for signal processing).
  • NoBoundary: Original Cleveland behavior

R's loess does not apply boundary padding, which can lead to:

  • Biased estimates near boundaries due to asymmetric local neighborhoods.
  • Increased variance at the edges of the smoothed curve.

Features

A variety of features, supporting a range of use cases:

Feature This package R (stats)
Kernel 7 options only Tricube
Robustness Weighting 3 options only Huber
Scale Estimation 3 options only MAR
Boundary Padding 4 options no padding
Zero Weight Fallback 3 options no
Auto Convergence yes no
Online Mode yes no
Streaming Mode yes no
Confidence Intervals yes no
Prediction Intervals yes no
Cross-Validation 2 options no
Parallel Execution yes no
no-std Support yes no

Installation

Currently available for R, Python, Rust, Julia, Node.js, and WebAssembly.

From R-universe (recommended, no Rust toolchain required):

install.packages("rfastloess", repos = "https://thisisamirv.r-universe.dev")

Or from conda-forge:

conda install -c conda-forge r-rfastloess

Install from PyPI:

pip install fastloess

Or from conda-forge:

conda install -c conda-forge fastloess

Add the crate to your Cargo.toml:

[dependencies]
loess-rs = "*"
[dependencies]
fastLoess = "*"

Install from the Julia General Registry:

using Pkg
Pkg.add("FastLOESS")

Install from npm:

npm install fastloess

Install from npm:

npm install fastloess-wasm

Or via CDN:

<script type="module">
  import { Loess } from "https://cdn.jsdelivr.net/npm/fastloess-wasm@<version>/index.js";
</script>

Install from source:

git clone https://github.com/thisisamirv/loess-project.git
cd loess-project
make cpp

Or from conda-forge:

conda install -c conda-forge libfastloess

See the Installation Guide for more options and details.

Quick Example

library(rfastloess)

x <- c(1, 2, 3, 4, 5)
y <- c(2.0, 4.1, 5.9, 8.2, 9.8)

model <- Loess(fraction = 0.5, iterations = 3)
result <- model$fit(x, y)
print(result$y)
import fastloess as fl
import numpy as np

x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([2.0, 4.1, 5.9, 8.2, 9.8])

model = fl.Loess(fraction=0.5, iterations=3)
result = model.fit(x, y)
print(result.y)
use fastLoess::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];

let model = Loess::new()
    .fraction(0.5)
    .iterations(3)
    .build()?;

let result = model.fit(&x, &y)?;
println!("{}", result);
using FastLOESS

x = [1.0, 2.0, 3.0, 4.0, 5.0]
y = [2.0, 4.1, 5.9, 8.2, 9.8]

model = Loess(; fraction=0.5, iterations=3)
result = fit(model, x, y)
println(result.y)
const fl = require("fastloess");

const x = new Float64Array([1, 2, 3, 4, 5]);
const y = new Float64Array([2.0, 4.1, 5.9, 8.2, 9.8]);

const model = new fl.Loess({ fraction: 0.5, iterations: 3 });
const result = model.fit(x, y);
console.log(result.y);
import { Loess } from "fastloess-wasm";

const x = new Float64Array([1, 2, 3, 4, 5]);
const y = new Float64Array([2.0, 4.1, 5.9, 8.2, 9.8]);

const model = new Loess({ fraction: 0.5, iterations: 3 });
const result = model.fit(x, y);
console.log(result.y);
#include <fastloess.hpp>
#include <iostream>
#include <vector>

int main() {
    std::vector<double> x = {1.0, 2.0, 3.0, 4.0, 5.0};
    std::vector<double> y = {2.0, 4.1, 5.9, 8.2, 9.8};

    fastloess::LoessOptions options;
    options.fraction = 0.5;
    options.iterations = 3;

    fastloess::Loess model(options);
    auto result = model.fit(x, y).value();

    for (const auto& val : result.y_vector()) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    return 0;
}

Getting Started

  1. Installation — Set up the library for your language
  2. Quick Start — Basic usage examples
  3. Concepts — Understand how LOESS works
  • Rust


    Pure Rust crates with zero-copy ndarray support, parallel execution.

    Rust API

  • Python


    Native Python bindings via PyO3 with NumPy integration and pip installation.

    Python API

  • R


    R package with Bioconductor-style documentation and seamless integration.

    R API

  • Julia


    Native Julia package with C FFI, supporting parallel execution and JLL dependencies.

    Julia API

  • Node.js


    Native Node.js bindings with high-performance C++ core and support for asynchronous streaming.

    Node.js API

  • WebAssembly


    Optimized WebAssembly build for browsers and Node.js with zero-overhead data transfer.

    WebAssembly API

  • C++


    Native C++ bindings with RAII memory management and STL container support.

    C++ API

License

Dual-licensed under MIT or Apache-2.0.