Skip to content
Ivan Svetunkov edited this page Jan 31, 2026 · 1 revision

lowess - Locally Weighted Scatterplot Smoothing

LOWESS (Locally Weighted Scatterplot Smoothing) is a nonparametric regression method for smoothing scatterplots. The smooth package provides a Python implementation that exactly matches R's stats::lowess function.

Overview

The Python implementation in smooth:

  • Is written in C++ based on R's original C code
  • Produces results identical to R's stats::lowess
  • Runs significantly faster than other Python implementations
  • Uses Cleveland's (1979) algorithm with tricube weighting and iterative robustification

Usage

Python

from smooth import lowess
import numpy as np

# Generate noisy data
x = np.linspace(0, 2*np.pi, 50)
y = np.sin(x) + np.random.randn(50) * 0.3

# Apply LOWESS smoothing
result = lowess(x, y)

# Access smoothed values
x_smooth = result['x']  # Sorted x values
y_smooth = result['y']  # Smoothed y values

R

# R's built-in lowess
result <- lowess(x, y)
result$x  # Sorted x values
result$y  # Smoothed y values

Parameters

Parameter Type (R) Type (Python) Default Description
x numeric vector array-like - X values. Can be 2D array with x in first column
y numeric vector array-like NULL/None Y values. Optional if x is 2D array
f numeric float 2/3 Smoother span (fraction of points). Larger = smoother
iter integer int 3 Number of robustifying iterations
delta numeric float 0.01 * range(x) Distance threshold for interpolation

Output

Returns a dictionary (Python) or list (R) with two components:

Component Type Description
x array/vector Sorted x values
y array/vector Smoothed y values corresponding to sorted x

Examples

Adjusting Smoothness

from smooth import lowess
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x) + np.random.randn(100) * 0.5

# More smoothing (larger span)
result_smooth = lowess(x, y, f=0.8)

# Less smoothing (smaller span)
result_rough = lowess(x, y, f=0.2)

Handling Outliers

LOWESS is robust to outliers due to its iterative reweighting scheme:

# Add outliers to data
y_outliers = y.copy()
y_outliers[25] = 10  # Outlier
y_outliers[50] = -5  # Outlier

# Default iterations (robust)
result = lowess(x, y_outliers, iter=3)

# More iterations for heavily contaminated data
result_robust = lowess(x, y_outliers, iter=5)

# No robustification (faster but sensitive to outliers)
result_fast = lowess(x, y_outliers, iter=0)

Using 2D Input

Like R, you can pass x and y as a single 2D array:

# Combine x and y into 2D array
xy = np.column_stack([x, y])

# Call with single argument
result = lowess(xy)

Algorithm

LOWESS uses Cleveland's (1979) algorithm:

  1. Local Fitting: At each point, fit a weighted linear regression using nearby points. Weights decrease with distance using a tricube function:
w(u) = (1 - |u|^3)^3 \quad for |u| < 1
  1. Robustness Iterations: Recompute weights based on residuals to downweight outliers. Repeat iter times.

  2. Interpolation: For efficiency, only compute fits at a subset of points (controlled by delta) and interpolate between them.

Use in smooth Package

LOWESS is used internally by other smooth functions:

  • msdecompose: Uses LOWESS for trend extraction when smoother="lowess" (default)
  • ADAM/ES: Uses LOWESS for initial state estimation when smoother="lowess" (default). Calls msdecompose for that.

References

  • Cleveland, W.S. (1979). Robust Locally Weighted Regression and Smoothing Scatterplots. Journal of the American Statistical Association, 74(368), 829-836. DOI: 10.1080/01621459.1979.10481038

See Also

  • msdecompose - Multiple seasonal decomposition using LOWESS
  • ADAM - Uses LOWESS for initialization
  • Model-Estimation - Smoother options for model estimation

Clone this wiki locally