Skip to main content
v2026.11,858 entries · CC-BY 4.0

LOESS Regression: Formula, Worked Example and Span Choice

LOESS (lowess) local regression explained with the formula, a hand-computed fit, span guidance and R, Python and Excel recipes.

Written and maintained by CASRAI Editorial Board

Last updated

LOESS regression (also written LOWESS, and called local regression or locally weighted regression) draws a smooth curve through a scatterplot without assuming a global equation such as a straight line or a parabola. At every point where you want a fitted value, it fits a small straight line or parabola to the nearby observations only, giving closer points more weight, and keeps just the value of that local fit. This guide gives the formula, a fit computed by hand with the arithmetic shown, how to choose the span, how the lowess and loess functions differ, and short R, Python and Excel recipes.

Definition: what is LOESS regression?

The NIST/SEMATECH e-Handbook of Statistical Methods describes LOESS as locally weighted polynomial regression: at each point in the data set, a low-degree polynomial is fitted to a subset of the data, with explanatory variable values near the point of estimation, using weighted least squares. The method was proposed by Cleveland (1979) and developed further by Cleveland and Devlin (1988). The regression function value at a point is the value of the local polynomial evaluated at that point, and the process is repeated for every point in the data set, which is what produces a smooth curve rather than one equation.

LOESS, LOWESS and local regression: are they the same?

They name the same family of methods. The R manual for stats::loess calls lowess the “ancestor” of loess, and the two functions have different defaults, so the same data can give different curves (see the comparison table below). “Local regression” is the general term; the statsmodels lowess function implements the robust locally weighted regression of Cleveland (1979), and R’s loess adds a choice of polynomial degree.

LOESS regression formula

For a target point x0 and observations (xi, yi), i = 1, …, n, a degree-1 (local linear) fit proceeds in four steps.

  1. Choose the neighbourhood. Take the q = ⌊αn⌋ observations nearest to x0, where α is the span (the smoothing parameter, between 0 and 1).
  2. Scale the distances. Let h be the largest distance from x0 within that neighbourhood and set ui = |xi − x0| / h.
  3. Weight with the tricube function. wi = (1 − ui3)3 for ui < 1, and wi = 0 otherwise. NIST and the R manual give the same weight function.
  4. Fit by weighted least squares. Choose b0 and b1 to minimise Σ wi (yi − b0 − b1(xi − x0))2. The fitted value is ŷ(x0) = b0.

Symbols: x0 is the point being estimated; α is the span; q the number of neighbours; h the neighbourhood radius; ui the scaled distance; wi the tricube weight; b0, b1 the local intercept and slope. A degree-2 fit adds a b2(xi − x0)2 term. Per NIST, the degree is almost always 1 or 2 (degree 0 reduces to a weighted moving average, and higher degrees tend to overfit and be numerically unstable). In the R implementation, a span above 1 uses all points with the maximum distance scaled up accordingly.

LOESS regression example: one local fit by hand

Eight observations, with x = 1 to 8: y = 2.1, 3.0, 3.4, 4.9, 5.2, 5.4, 7.6, 7.9. We estimate the curve at x0 = 3 with span α = 0.75 and degree 1.

Neighbourhood. q = ⌊0.75 × 8⌋ = 6. The six nearest points to 3 are x = 3, 2, 4, 1, 5, 6, with distances 0, 1, 1, 2, 2, 3. So h = 3.

x y Distance u = d/h Weight (1 − u³)³
3 3.4 0 0 1.0000
2 3.0 1 1/3 (1 − 1/27)³ = 0.8929
4 4.9 1 1/3 0.8929
1 2.1 2 2/3 (1 − 8/27)³ = 0.3485
5 5.2 2 2/3 0.3485
6 5.4 3 1 0 (on the boundary)

Weighted sums. Σw = 1 + 2(0.8929) + 2(0.3485) = 3.4828. Because the weights are symmetric about x = 3, the weighted mean of x is x̄w = 3. The weighted mean of y is ȳw = (3.4 × 1 + 0.8929 × (3.0 + 4.9) + 0.3485 × (2.1 + 5.2)) / 3.4828 = 12.998 / 3.4828 = 3.7321.

Slope. Sxx = Σw(x − 3)² = 0.8929 × 2 × 1 + 0.3485 × 2 × 4 = 4.5736. Sxy = Σw(x − 3)y = 0.8929 × (4.9 − 3.0) + 0.3485 × 2 × (5.2 − 2.1) = 0.8929 × 1.9 + 0.3485 × 6.2 = 1.6966 + 2.1605 = 3.8571. Slope b1 = 3.8571 / 4.5736 = 0.8433.

Fitted value. Because x0 equals the weighted mean of x, b0 = ȳw = 3.73. The LOESS estimate at x = 3 is 3.73, against an observed 3.4. Repeating the procedure at x = 1, 2, …, 8 (or on a finer grid) traces out the curve. The result was cross-checked against Python’s statsmodels lowess(y, x, frac=0.75, it=0), which returns 3.732 at x = 3.

Choosing the span (smoothing parameter)

NIST states that the smoothing parameter q lies between (d + 1)/n and 1, where d is the degree, that larger values give smoother functions, and that useful values typically fall between 0.25 and 0.5 for most applications. The R default is span = 0.75 and degree = 2.

Span What happens
Small (toward the lower bound) Each fit uses few points; the curve follows local wiggles and noise.
Larger Each fit uses more points; the curve is smoother and may flatten real features.
Span of 1 or more (R) All points enter every fit, with weights falling off toward the far points.

How to interpret a LOESS curve

A LOESS curve is a descriptive summary of how the average response changes with x. It is not a model with coefficients, so interpretation means reading the shape of the curve, and reading it together with the span you chose and the density of the data.

What you see How to read it
Curve rises or falls steadily The average response changes in one direction across that range of x. The local slope is the steepness of the curve at that point and can differ along x.
Curve is roughly flat No clear change in the average response over that range at this span. A flat curve at a large span can hide a short-lived feature.
Small wiggles May be noise followed by a small span. Refit with a larger span; a wiggle that persists across several spans is more credible than one that appears at only one.
Wide gaps between observations Each local fit leans on whatever distant points exist, so the curve there is less certain. Treat the curve across a gap as interpolation, not evidence.
Behaviour at the ends of the x range Only one side of the data is available, so the fit is less constrained and the curve is usually less reliable. Avoid reading strong conclusions into the extreme ends.
Points far from the curve Large residuals show scatter around the local average. Plot residuals against x; a visible pattern suggests the span is too large.

Because the result is a smooth curve rather than a test, report the span and degree used, and avoid describing the curve as proof of a particular functional form.

LOWESS vs LOESS: defaults compared

R loess() Python statsmodels lowess()
Fraction of data per local fit span = 0.75 frac = 2/3
Local polynomial degree = 2 (normally 1 or 2) Local linear fit (Cleveland 1979)
Robustness family = "gaussian" (least squares); "symmetric" uses a re-descending M-estimator with Tukey’s biweight it = 3 residual-based reweightings
Speed shortcut Not applicable delta = 0.0 (set above 0 to interpolate between nearby fits)

Assumptions and common mistakes

  • It is descriptive, not a model with coefficients. There is no single equation to report; the output is a set of fitted values along the x range.
  • Choosing the span to get the picture you expect. State the span and degree you used and why; a different span can tell a different story.
  • Ignoring outliers. R’s default family = "gaussian" is ordinary least squares, so extreme points can pull the curve; use the robust option (family = "symmetric" in R, it > 0 in statsmodels) when outliers are plausible.
  • Treating the smooth as a test. A smoothed curve shows shape; it does not by itself test a hypothesis. See non-linear relationships for how curvature is assessed.
  • Mixing up defaults. Moving between lowess and loess (or between software) without matching span, degree and robustness gives different curves.

How to report LOESS regression (APA style)

Report the method, software, span, degree, weight function and robustness setting, and show the smooth with the raw data. Example: “The relationship between dose and response was explored with a locally weighted regression (LOESS; Cleveland, 1979), using a span of 0.75, local linear fits and tricube weights, computed with the loess function in R.” Cite the original source in the reference list: Cleveland, W. S. (1979). Robust locally weighted regression and smoothing scatterplots. Journal of the American Statistical Association, 74(368), 829-836.

How to run LOESS in R, Python or Excel

R

fit <- loess(y ~ x, span = 0.75, degree = 1, family = "gaussian")
predict(fit, newdata = data.frame(x = 3))

In ggplot2, geom_smooth(method = "loess") draws the same kind of smooth; see scatterplots in R.

Python

import numpy as np
from statsmodels.nonparametric.smoothers_lowess import lowess
x = np.arange(1, 9.0)
y = np.array([2.1, 3.0, 3.4, 4.9, 5.2, 5.4, 7.6, 7.9])
smooth = lowess(y, x, frac=0.75, it=0)   # it=0: no robustness iterations
print(smooth[2])                          # [3.0, 3.732...]

Excel

This reproduces the single local fit above with worksheet formulas, with x in A2:A9, y in B2:B9 and the target x0 in F1.

C2:  =ABS(A2-$F$1)                                  (distance)
H1:  =SMALL($C$2:$C$9,6)                            (h for 6 neighbours)
D2:  =IF(C2<=$H$1,(1-(C2/$H$1)^3)^3,0)               (tricube weight)
F2:  =SUMPRODUCT(D2:D9,A2:A9)/SUM(D2:D9)            (weighted mean of x)
F3:  =SUMPRODUCT(D2:D9,B2:B9)/SUM(D2:D9)            (weighted mean of y)
F4:  =SUMPRODUCT(D2:D9,(A2:A9-F2),(B2:B9-F3))/SUMPRODUCT(D2:D9,(A2:A9-F2)^2)   (slope)
F5:  =F3+F4*($F$1-F2)                               (fitted value)

Fill C2 and D2 down to row 9. With x0 = 3 this gives 3.73. Related smoothing ideas appear in moving averages, which LOESS generalises with weights and local slopes, and in linear regression on a scatter plot, which LOESS replaces with a local fit.

FAQ

What is the difference between LOESS and linear regression?

Linear regression estimates one global line (or polynomial) for all the data. LOESS estimates a separate weighted fit at each point from nearby observations only, so the curve can bend where the data bend.

What is the difference between lowess and loess?

Lowess is the older function and the “ancestor” of loess in R; they use different defaults (see the comparison table above), so results differ unless span, degree and robustness are matched.

What is a good span for LOESS?

NIST gives 0.25 to 0.5 as typical for most applications, with larger values smoother; R defaults to 0.75. Choose by inspecting the curve against the data, and report the value you used.

Is there a LOESS regression calculator?

A hand fit at one point needs only the weights and a weighted least-squares line, as shown above; for a full curve use loess in R or lowess in statsmodels.

Sources

  • NIST/SEMATECH e-Handbook of Statistical Methods, section 4.1.4.4, LOESS (local regression): itl.nist.gov/div898/handbook/pmd/section1/pmd144.htm, read 2026-11-08.
  • R Documentation, stats::loess, Local Polynomial Regression Fitting: stat.ethz.ch/R-manual/R-devel/library/stats/html/loess.html, read 2026-11-08. It cites Cleveland, Grosse and Shyu (1992), Local regression models, in Chambers and Hastie (eds.), Statistical Models in S, chapter 8.
  • statsmodels documentation, lowess: statsmodels.org, read 2026-11-08.
  • Cleveland, W. S. (1979). Robust locally weighted regression and smoothing scatterplots. Journal of the American Statistical Association, 74(368), 829-836.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about LOESS Regression: Formula, Worked Example and Span Choice

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →