Skip to main content

LOESS Project

loess-rs fastLoess PyPI R-universe npm Julia WASM C++
fastloess (Python) libfastloess (C++) rfastloess (R)
CI

One LOESS to Rule Them All
One LOESS to Rule Them All

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

[!IMPORTANT]

The loess-project contains a complete ecosystem for LOESS smoothing:


Installation

[!NOTE]

Currently available for R, Python, Rust, Julia, Node.js, WebAssembly, and C++. See the Installation Guide for detailed installation instructions.

Documentation

[!NOTE]

📚 View the full documentation


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)

[!TIP] Note: For a LOWESS implementation, use lowess-project.


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 typically 5–20x faster than R's loess in serial mode, and up to 200x faster on large datasets with parallel execution.

For more details on the performance comparison, 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 = median(|r_i - median(r)|)

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

s = 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)
Polynomial Degree 5 (0–4) 2 (1 or 2)
Kernel 7 options only Tricube
Robustness Weighting 3 options only Bisquare
Scale Estimation 3 options only MAR
Distance Metric 6 options normalized only
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
Diagnostics (RMSE, R², AIC) yes no
Cross-Validation 2 options no
Parallel Execution yes no
no-std Support yes no

Validation

All implementations are numerical twins of R's loess:

Aspect Status Details
Accuracy ✅ EXACT MATCH Max diff < 1e-12 across all scenarios
Consistency ✅ PERFECT Multiple scenarios pass with strict tolerance
Robustness ✅ VERIFIED Robust smoothing matches R exactly

API Reference

R:

library(rfastloess)

model <- Loess(
    fraction = 0.67,
    iterations = 3L,
    weight_function = "tricube",
    robustness_method = "bisquare",
    zero_weight_fallback = "use_local_mean",
    boundary_policy = "extend",
    scaling_method = "mad",
    confidence_intervals = NULL,
    prediction_intervals = NULL,
    return_diagnostics = FALSE,
    return_residuals = FALSE,
    return_robustness_weights = FALSE,
    cv_fractions = NULL,
    cv_method = "kfold",
    cv_k = 5L,
    auto_converge = NULL,
    parallel = TRUE
)
custom_weights <- rep(1, length(x))
result <- fit(model, x, y, custom_weights = custom_weights)

# Result structure:
result$x,
result$y,
result$standard_errors,
result$confidence_lower,
result$confidence_upper,
result$prediction_lower,
result$prediction_upper,
result$residuals,
result$robustness_weights,
result$diagnostics,
result$iterations_used,
result$fraction_used,
result$cv_scores

Python:

from fastloess import Loess

model = Loess(
    fraction=0.67,
    iterations=3,
    weight_function="tricube",
    robustness_method="bisquare",
    zero_weight_fallback="use_local_mean",
    boundary_policy="extend",
    scaling_method="mad",
    confidence_intervals=None,
    prediction_intervals=None,
    return_diagnostics=False,
    return_residuals=False,
    return_robustness_weights=False,
    cv_fractions=None,
    cv_method="kfold",
    cv_k=5,
    auto_converge=None,
    parallel=True
)
custom_weights = [1.0] * len(x)
result = model.fit(x, y, custom_weights=custom_weights)

# Result structure:
result.x,
result.y,
result.standard_errors,
result.confidence_lower,
result.confidence_upper,
result.prediction_lower,
result.prediction_upper,
result.residuals,
result.robustness_weights,
result.diagnostics,
result.iterations_used,
result.fraction_used,
result.cv_scores

Rust:

use loess_rs::prelude::*;

let model = Loess::new()
    .fraction(0.67)
    .iterations(3)
    .weight_function("tricube")
    .robustness_method("bisquare")
    .zero_weight_fallback("use_local_mean")
    .boundary_policy("extend")
    .scaling_method("mad")
    .confidence_intervals(0.95)
    .prediction_intervals(0.95)
    .return_diagnostics()
    .return_residuals()
    .return_robustness_weights()
    .cv_fractions(vec![0.3, 0.5, 0.7])
    .cv_method("kfold")
    .cv_k(5)
    .cv_seed(123)
    .auto_converge(1e-4)
    .custom_weights(vec![1.0; x.len()])
    .parallel(true)             // fastLoess only
    .build()?;

let result = model.fit(&x, &y)?;

// Result structure:
pub struct LoessResult<T> {
    pub x: Vec<T>,                           // Sorted x values
    pub y: Vec<T>,                           // Smoothed y values
    pub standard_errors: Option<Vec<T>>,
    pub confidence_lower: Option<Vec<T>>,
    pub confidence_upper: Option<Vec<T>>,
    pub prediction_lower: Option<Vec<T>>,
    pub prediction_upper: Option<Vec<T>>,
    pub residuals: Option<Vec<T>>,
    pub robustness_weights: Option<Vec<T>>,
    pub diagnostics: Option<Diagnostics<T>>,
    pub iterations_used: Option<usize>,
    pub fraction_used: T,
    pub cv_scores: Option<Vec<T>>,
}

Julia:

using FastLOESS

model = Loess(;
    fraction=0.67,
    iterations=3,
    weight_function="tricube",
    robustness_method="bisquare",
    zero_weight_fallback="use_local_mean",
    boundary_policy="extend",
    scaling_method="mad",
    confidence_intervals=NaN,
    prediction_intervals=NaN,
    return_diagnostics=false,
    return_residuals=false,
    return_robustness_weights=false,
    cv_fractions=Float64[], # e.g. [0.3, 0.5]
    cv_method="kfold",
    cv_k=5,
    auto_converge=NaN,
    parallel=true
)
custom_weights = ones(length(x))
result = fit(model, x, y; custom_weights=custom_weights)

# Result structure:
result.x,
result.y,
result.standard_errors,
result.confidence_lower,
result.confidence_upper,
result.prediction_lower,
result.prediction_upper,
result.residuals,
result.robustness_weights,
result.diagnostics,
result.iterations_used,
result.fraction_used,
result.cv_scores

Node.js:

import { Loess } from "fastloess"

const model = new Loess({
    fraction: 0.67,
    iterations: 3,
    weight_function: "tricube",
    robustness_method: "bisquare",
    zero_weight_fallback: "use_local_mean",
    boundary_policy: "extend",
    scaling_method: "mad",
    confidence_intervals: 0.95,
    prediction_intervals: 0.95,
    return_diagnostics: true,
    return_residuals: true,
    return_robustness_weights: true,
    cv_fractions: [0.3, 0.5, 0.7],
    cv_method: "kfold",
    cv_k: 5,
    auto_converge: 1e-4,
    parallel: true
})
const custom_weights = Array(x.length).fill(1.0)
const result = model.fit(x, y, custom_weights)

// Result structure:
result.x,
result.y,
result.standard_errors,
result.confidence_lower,
result.confidence_upper,
result.prediction_lower,
result.prediction_upper,
result.residuals,
result.robustness_weights,
result.diagnostics,
result.iterations_used,
result.fraction_used,
result.cv_scores

WebAssembly:

import { Loess } from "fastloess-wasm"

const model = new Loess({
    fraction: 0.67,
    iterations: 3,
    weight_function: "tricube",
    robustness_method: "bisquare",
    zero_weight_fallback: "use_local_mean",
    boundary_policy: "extend",
    scaling_method: "mad",
    confidence_intervals: 0.95,
    prediction_intervals: 0.95,
    return_diagnostics: true,
    return_residuals: true,
    return_robustness_weights: true,
    cv_fractions: [0.3, 0.5, 0.7],
    cv_method: "kfold",
    cv_k: 5,
    auto_converge: 1e-4,
    parallel: true
})
const custom_weights = new Float64Array(x.length).fill(1)
const result = model.fit(x, y, custom_weights)

// Result structure:
result.x,
result.y,
result.standard_errors,
result.confidence_lower,
result.confidence_upper,
result.prediction_lower,
result.prediction_upper,
result.residuals,
result.robustness_weights,
result.diagnostics,
result.iterations_used,
result.fraction_used,
result.cv_scores

C++:

fastloess::LoessOptions options;
options.fraction = 0.67;
options.iterations = 3;
options.weight_function = "tricube";
options.robustness_method = "bisquare";
options.zero_weight_fallback = "use_local_mean";
options.boundary_policy = "extend";
options.scaling_method = "mad";
options.confidence_intervals = 0.95;
options.prediction_intervals = 0.95;
options.return_diagnostics = true;
options.return_residuals = true;
options.return_robustness_weights = true;
options.cv_fractions = {0.3, 0.5, 0.7};
options.cv_method = "kfold";
options.cv_k = 5;
options.auto_converge = 1e-4;
options.parallel = true;

fastloess::Loess model(options);
std::vector<double> custom_weights(x.size(), 1.0);
const auto result = model.fit(x, y, custom_weights).value();

// Result structure:
result.x_vector(),
result.y_vector(),
result.standard_errors(),
result.confidence_lower(),
result.confidence_upper(),
result.prediction_lower(),
result.prediction_upper(),
result.residuals(),
result.robustness_weights(),
result.diagnostics(),
result.iterations_used(),
result.fraction_used(),
result.cv_scores()

Contributing

Contributions are welcome! Please see the Contributing Guide for more information.

Changelog

See the Changelog for a history of changes.

License

Licensed under MIT or Apache-2.0.

Citation

If you use this software in your research, please cite it using the CITATION.cff file or the BibTeX entry below:

@software{loess_project,
  author = {Valizadeh, Amir},
  title = {LOESS Project: High-Performance Locally Estimated Scatterplot Smoothing},
  year = {2026},
  url = {https://github.com/thisisamirv/loess-project},
  license = {MIT OR Apache-2.0}
}

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastloess-1.0.0.tar.gz (178.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

fastloess-1.0.0-cp38-abi3-win_amd64.whl (520.5 kB view details)

Uploaded CPython 3.8+Windows x86-64

fastloess-1.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (638.1 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

fastloess-1.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (604.9 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

fastloess-1.0.0-cp38-abi3-macosx_11_0_arm64.whl (573.0 kB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

fastloess-1.0.0-cp38-abi3-macosx_10_12_x86_64.whl (596.9 kB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file fastloess-1.0.0.tar.gz.

File metadata

  • Download URL: fastloess-1.0.0.tar.gz
  • Upload date:
  • Size: 178.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fastloess-1.0.0.tar.gz
Algorithm Hash digest
SHA256 51e9c8f0324151ee0d761c070423b77e6f7b21b0b6f8c9b791d11d5ad338900c
MD5 9ca316588e67677b1b33ed776eac3207
BLAKE2b-256 c98140537e4d7977c7263145149ce1faef3fac6fe66bf60b37bfffe6c97ce2c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastloess-1.0.0.tar.gz:

Publisher: release-pypi.yml on thisisamirv/loess-project

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastloess-1.0.0-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: fastloess-1.0.0-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 520.5 kB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fastloess-1.0.0-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 1f9c1e1fd59a6fb3eb31f1d6bce5274184697dc0d4fe4142ee8f8b4bbc644572
MD5 81388762822722ae4a7f964650b19116
BLAKE2b-256 25d7a70ad8d38c1b872300b7b6def3bb2953d404b85852d178d9c489033ce6a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastloess-1.0.0-cp38-abi3-win_amd64.whl:

Publisher: release-pypi.yml on thisisamirv/loess-project

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastloess-1.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fastloess-1.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0a830dfb4c46de2a5cd0f56d191d44f63d46aaddcc2dce5c0d0f63ede162378a
MD5 4afe29cc64e2fe54da6c553713b0f55b
BLAKE2b-256 1d86bed4be38a786d151397de23a4bc9f95a6d499e1e5168d95a792d1cc5fb38

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastloess-1.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release-pypi.yml on thisisamirv/loess-project

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastloess-1.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fastloess-1.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 802cb02bbea80b6da51d52a572e55eefbb7364bd1f11834593600157c9777bf4
MD5 0bc04a28011081ba4274abba73b7eef2
BLAKE2b-256 b87ff38e4b36fd7b10351ec8444109e15340e457d3e7ea2d695b47aa985d3324

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastloess-1.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release-pypi.yml on thisisamirv/loess-project

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastloess-1.0.0-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for fastloess-1.0.0-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4e3922e1bd70dc87406e30fea0b09d2ef666e7d45ca1fa891451c7140ced0122
MD5 b5e54e294f155744356deb1c11c36341
BLAKE2b-256 59a4dcef2ec63e7bda803402e226de889e7363e1a01c3156009b9c996448600f

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastloess-1.0.0-cp38-abi3-macosx_11_0_arm64.whl:

Publisher: release-pypi.yml on thisisamirv/loess-project

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastloess-1.0.0-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for fastloess-1.0.0-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 185914c98f172383c6899b7a37ab5aa9bbb723a8536517b51c2357a2928650da
MD5 704c3e14ab04acad8b21bfcc66598b2e
BLAKE2b-256 8486d4b6296a46060059bc7a642933855abed40814e164da7f9aa3d404641ed9

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastloess-1.0.0-cp38-abi3-macosx_10_12_x86_64.whl:

Publisher: release-pypi.yml on thisisamirv/loess-project

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

2.0.0

7 files

1.1.0

6 files

This release

1.0.0 This release

6 files

0.9.0

6 files

0.1.0

36 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page