Skip to content

Quick Start

Get up and running with LOWESS in minutes.

Basic Smoothing

library(rfastlowess)

# Sample data
x <- c(1, 2, 3, 4, 5, 6, 7, 8)
y <- c(2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7)

# Smooth the data
model <- Lowess(fraction = 0.5, iterations = 3)
result <- model$fit(x, y)

print(result$y)
import fastlowess as fl
import numpy as np

# Sample data
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0])
y = np.array([2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7])

# Smooth the data
result = fl.smooth(x, y, fraction=0.5, iterations=3)

print("Smoothed values:", result["y"])
use lowess::prelude::*;

fn main() -> Result<(), LowessError> {
    // Sample data
    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 and fit the model
    let model = Lowess::new()
        .fraction(0.5)      // Use 50% of data for each fit
        .iterations(3)      // 3 robustness iterations
        .adapter(Batch)
        .build()?;

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

    println!("{}", result);
    Ok(())
}
using FastLOWESS

# Sample data
x = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
y = [2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7]

# Smooth the data
result = smooth(x, y, fraction=0.5, iterations=3)

println("Smoothed values: ", result.y)
const fastlowess = require('fastlowess');

// Sample data
const x = new Float64Array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
const y = new Float64Array([2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7]);

// Smooth the data
const result = fastlowess.smooth(x, y, { fraction: 0.5, iterations: 3 });

console.log("Smoothed values:", result.y);
import * as fastlowess from 'fastlowess-wasm';

// Sample data
const x = new Float64Array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
const y = new Float64Array([2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7]);

// Smooth the data
const result = fastlowess.smooth(x, y, { fraction: 0.5, iterations: 3 });

console.log("Smoothed values:", result.y);
#include <fastlowess.hpp>
#include <iostream>
#include <vector>

int main() {
    // Sample data
    std::vector<double> x = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
    std::vector<double> y = {2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7};

    // Smooth the data
    fastlowess::LowessOptions options;
    options.fraction = 0.5;
    options.iterations = 3;

    fastlowess::Lowess model(options);
    auto result = model.fit(x, y);

    // Print smoothed values
    const auto& y_smooth = result.yVector();
    std::cout << "Smoothed values: [";
    for (double val : y_smooth) std::cout << val << ", ";
    std::cout << "]" << std::endl;

    return 0;
}

With Confidence Intervals

model <- Lowess(
    fraction = 0.5,
    iterations = 3,
    confidence_intervals = 0.95,
    prediction_intervals = 0.95,
    return_diagnostics = TRUE
)
result <- model$fit(x, y)

print(result$confidence_lower)
print(result$confidence_upper)
print(result$diagnostics$r_squared)
result = fl.smooth(
    x, y,
    fraction=0.5,
    iterations=3,
    confidence_intervals=0.95,
    prediction_intervals=0.95,
    return_diagnostics=True
)

print("Smoothed:", result["y"])
print("CI Lower:", result["confidence_lower"])
print("CI Upper:", result["confidence_upper"])
print("R²:", result["diagnostics"]["r_squared"])
use lowess::prelude::*;

let model = Lowess::new()
    .fraction(0.5)
    .iterations(3)
    .confidence_intervals(0.95)  // 95% CI
    .prediction_intervals(0.95)  // 95% PI
    .return_diagnostics()
    .adapter(Batch)
    .build()?;

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

// Access intervals
if let Some(ci_lower) = &result.confidence_lower {
    println!("CI Lower: {:?}", ci_lower);
}
result = smooth(
    x, y,
    fraction=0.5,
    iterations=3,
    confidence_intervals=0.95,
    prediction_intervals=0.95,
    return_diagnostics=true
)

println("Smoothed: ", result.y)
println("CI Lower: ", result.confidence_lower)
println("CI Upper: ", result.confidence_upper)
println("R²: ", result.diagnostics.r_squared)
const result = fastlowess.smooth(x, y, {
    fraction: 0.5,
    iterations: 3,
    confidenceIntervals: 0.95,
    predictionIntervals: 0.95,
    returnDiagnostics: true
});

console.log("Smoothed:", result.y);
console.log("CI Lower:", result.confidenceLower);
console.log("CI Upper:", result.confidenceUpper);
console.log("R²:", result.diagnostics.rSquared);
import * as fastlowess from 'fastlowess-wasm';

// Sample data
const x = new Float64Array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
const y = new Float64Array([2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7]);

// Smooth the data
const result = fastlowess.smooth(x, y, { fraction: 0.5, iterations: 3 });

console.log("Smoothed values:", result.y);
fastlowess::LowessOptions options;
options.fraction = 0.5;
options.iterations = 3;
options.confidence_intervals = 0.95;
options.prediction_intervals = 0.95;
options.return_diagnostics = true;

fastlowess::Lowess model(options);
auto result = model.fit(x, y);

// Access standard C++ vectors
auto lower = result.confidenceLower();
auto upper = result.confidenceUpper();
double r2 = result.diagnostics().rSquared();

Handling Outliers

LOWESS can robustly handle outliers through iterative reweighting:

y_with_outlier <- c(2, 4, 6, 50, 10, 12)

model <- Lowess(
    fraction = 0.5,
    iterations = 5,
    robustness_method = "bisquare",
    return_robustness_weights = TRUE
)
result <- model$fit(x, y_with_outlier)

# Check downweighted points
weights <- result$robustness_weights
for (i in seq_along(weights)) {
    if (weights[i] < 0.5) {
        cat(sprintf("Point %d is likely an outlier (weight: %.3f)\n", i, weights[i]))
    }
}
y_with_outlier = np.array([2.0, 4.0, 6.0, 50.0, 10.0, 12.0])

result = fl.smooth(
    x, y_with_outlier,
    fraction=0.5,
    iterations=5,
    robustness_method="bisquare",
    return_robustness_weights=True
)

# Check which points were downweighted
for i, w in enumerate(result["robustness_weights"]):
    if w < 0.5:
        print(f"Point {i} is likely an outlier (weight: {w:.3f})")
// Data with an outlier at position 3
let y_with_outlier = vec![2.0, 4.0, 6.0, 50.0, 10.0, 12.0];  // 50.0 is outlier

let model = Lowess::new()
    .fraction(0.5)
    .iterations(5)                    // More iterations for outliers
    .robustness_method(Bisquare)      // Default, smooth downweighting
    .return_robustness_weights()      // See which points were downweighted
    .adapter(Batch)
    .build()?;

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

// Outliers will have low robustness weights
if let Some(weights) = &result.robustness_weights {
    for (i, w) in weights.iter().enumerate() {
        if *w < 0.5 {
            println!("Point {} is likely an outlier (weight: {:.3})", i, w);
        }
    }
}
y_with_outlier = [2.0, 4.0, 6.0, 50.0, 10.0, 12.0]

result = smooth(
    x, y_with_outlier,
    fraction=0.5,
    iterations=5,
    robustness_method="bisquare",
    return_robustness_weights=true
)

# Check which points were downweighted
for (i, w) in enumerate(result.robustness_weights)
    if w < 0.5
        println("Point $i is likely an outlier (weight: $(round(w, digits=3)))")
    end
end
const fl = require('fastlowess');

const yWithOutlier = new Float64Array([2.0, 4.0, 6.0, 50.0, 10.0, 12.0]);

const result = fl.smooth(x, yWithOutlier, {
    fraction: 0.5,
    iterations: 5,
    robustnessMethod: "bisquare",
    returnRobustnessWeights: true
});

// Outliers will have low robustness weights
result.robustnessWeights.forEach((w, i) => {
    if (w < 0.5) {
        console.log(`Point ${i} is likely an outlier (weight: ${w.toFixed(3)})`);
    }
});
import { smooth } from 'fastlowess-wasm';

// Data with an outlier at position 3
const yWithOutlier = new Float64Array([2.0, 4.0, 6.0, 50.0, 10.0, 12.0]);

const result = smooth(x, yWithOutlier, {
    fraction: 0.5,
    iterations: 5,
    robustnessMethod: "bisquare",
    returnRobustnessWeights: true
});

// Outliers will have low robustness weights
result.robustnessWeights.forEach((w, i) => {
    if (w < 0.5) {
        console.log(`Point ${i} is likely an outlier (weight: ${w.toFixed(3)})`);
    }
});
// Data with an outlier
std::vector<double> y_outlier = {2.0, 4.0, 6.0, 50.0, 10.0, 12.0};

fastlowess::LowessOptions options;
options.fraction = 0.5;
options.iterations = 5;
options.robustness_method = "bisquare";
options.return_robustness_weights = true;

fastlowess::Lowess model(options);
auto result = model.fit(x, y_outlier);

// Check weights
auto weights = result.robustnessWeights();
for (size_t i = 0; i < weights.size(); ++i) {
    if (weights[i] < 0.5) {
        std::cout << "Point " << i << " is outlier (weight: " << weights[i] << ")\n";
    }
}

Next Steps