At each target point, LOESS fits a polynomial to the neighbouring
data using weighted least squares. The degree parameter
controls the order of that polynomial.
| Degree | Local Fit | Captures | Risk |
|---|---|---|---|
0 / "constant" |
Weighted mean | Level only | Over-smooth; edge bias |
1 / "linear" |
Weighted line | Trend (default) | Rarely overfits |
2 / "quadratic" |
Parabola | Curvature | Overfits with small fraction |
3 / "cubic" |
Cubic curve | Inflections | Requires larger fraction |
4 / "quartic" |
Quartic curve | Fine structure | High variance, rare |
Degree can be specified as an integer
(0L–4L) or as a string
("constant", "linear",
"quadratic", "cubic",
"quartic").
The fit at each point is a weighted mean. Produces very smooth results but ignores local slope, introducing bias wherever the true function changes.
Use when: Maximum smoothness matters more than accuracy; computationally cheapest.
library(rfastloess)
set.seed(42)
x <- seq(0, 2 * pi, length.out = 100)
y <- sin(x) + rnorm(100, sd = 0.3)
model <- Loess(fraction = 0.5, degree = "constant")
result <- fit(model, x, y)
cat("First 6 smoothed values (constant/Nadaraya-Watson):\n")
#> First 6 smoothed values (constant/Nadaraya-Watson):
print(head(result$y))
#> [1] 0.4694689 0.4748509 0.4785029 0.4798484 0.4836073 0.4936813Fits a weighted line through the neighbourhood. Removes first-order bias and handles boundary regions correctly. The right choice for the vast majority of applications.
Use when: Default; monotone or gently curved data; boundary accuracy matters.
model <- Loess(fraction = 0.5, degree = "linear")
result <- fit(model, x, y)
cat("First 6 smoothed values (linear local regression):\n")
#> First 6 smoothed values (linear local regression):
print(head(result$y))
#> [1] 0.4758389 0.4846388 0.4944609 0.5054102 0.5169758 0.5286606Fits a weighted parabola. Captures curvature in the data and reduces bias in regions with strong local curvature, at the cost of higher variance.
Use when: Data has visible curvature or local
extrema; use a larger fraction to stabilise the fit.
model <- Loess(fraction = 0.5, degree = "quadratic")
result <- fit(model, x, y)
cat("First 6 smoothed values (quadratic local regression):\n")
#> First 6 smoothed values (quadratic local regression):
print(head(result$y))
#> [1] 0.4043043 0.4131994 0.4244604 0.4384709 0.4565813 0.4791656Fits a weighted cubic polynomial. Captures inflections and fine structure but requires a sufficiently large neighbourhood to remain stable.
Use when: Data has clear S-shaped curves or multiple
inflection points; use fraction >= 0.5.
model <- Loess(fraction = 0.6, degree = "cubic")
result <- fit(model, x, y)
cat("First 6 smoothed values (cubic local regression):\n")
#> First 6 smoothed values (cubic local regression):
print(head(result$y))
#> [1] 0.4183075 0.4299695 0.4442197 0.4608883 0.4798054 0.5008015Fits a weighted quartic polynomial. Rarely needed in practice; only useful for capturing highly oscillatory local structure. Very prone to overfitting.
Use when: Fine oscillatory structure is physically meaningful and the dataset is large; always cross-validate.
model <- Loess(fraction = 0.7, degree = "quartic")
result <- fit(model, x, y)
cat("First 6 smoothed values (quartic local regression):\n")
#> First 6 smoothed values (quartic local regression):
print(head(result$y))
#> [1] 0.3964750 0.4064069 0.4182002 0.4319700 0.4478315 0.4658997At the dataset boundary, the neighbourhood is one-sided and may not
contain enough points to support the requested degree. Setting
boundary_degree_fallback = TRUE automatically reduces the
degree at boundaries to avoid instability.
model <- Loess(degree = 2L, boundary_degree_fallback = TRUE)
result <- fit(model, x, y)
cat("First 6 smoothed values (quadratic, boundary fallback):\n")
#> First 6 smoothed values (quadratic, boundary fallback):
print(head(result$y))
#> [1] 0.4577829 0.4682789 0.4793020 0.4908341 0.5028573 0.5153538| Situation | Recommended Degree |
|---|---|
| Monotone trend, general purpose | 1 (default) |
| Maximum smoothness, speed | 0 |
| Clear peaks / valleys / inflections | 2 (with fraction >= 0.4) |
| S-shaped curves, multiple inflections | 3 (with fraction >= 0.5) |
| Fine oscillatory structure (rare) | 4 (fraction >= 0.6, CV) |
| Boundary accuracy is critical | 1 or 2 (not 0) |
| Very small dataset (n < 50) | 1 |
Rule of thumb: Start with
degree = 1(default). Move todegree = 2only if you see systematic bias in regions of high curvature, and increasefractionat the same time.
The surface_mode parameter controls whether LOESS
evaluates the local polynomial at every query point or at a sparser grid
of vertices with Hermite cubic interpolation in between.
| Mode | Behaviour | Speed | Accuracy |
|---|---|---|---|
"interpolation" (default) |
Anchor + Hermite blend | Faster | Approx |
"direct" |
Evaluate at every query point | Exact | Full precision |
See vignette("dimensions", package = "rfastloess") for
runnable surface_mode examples.
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] rfastloess_3.0.0 rmarkdown_2.32
#>
#> loaded via a namespace (and not attached):
#> [1] digest_0.6.39 R6_2.6.1 fastmap_1.2.0 xfun_0.61
#> [5] maketools_1.3.2 cachem_1.1.0 knitr_1.52 htmltools_0.5.9
#> [9] buildtools_1.0.0 lifecycle_1.0.5 cli_3.6.6 sass_0.4.10
#> [13] jquerylib_0.1.4 compiler_4.6.1 sys_3.4.3 tools_4.6.1
#> [17] evaluate_1.0.5 bslib_0.12.0 yaml_2.3.12 otel_0.2.0
#> [21] jsonlite_2.0.0 rlang_1.3.0