Get up and running with LOWESS in minutes.
Smooth a noisy sine wave — the kind of signal where LOWESS shines. Each example recovers the underlying trend from 100 points of Gaussian noise.
library(rfastlowess)
# 100-point noisy sine wave
set.seed(42)
x <- seq(0, 2 * pi, length.out = 100)
y <- sin(x) + rnorm(100, sd = 0.3)
model <- Lowess(fraction = 0.3, iterations = 3)
result <- fit(model, x, y)
cat(sprintf("First smoothed value: %.4f (true: %.4f)\n",
result$y[1], sin(x[1])))
#> First smoothed value: 0.4287 (true: 0.0000)library(rfastlowess)
set.seed(42)
x <- seq(0, 2 * pi, length.out = 100)
y <- sin(x) + rnorm(100, sd = 0.3)
model <- Lowess(
fraction = 0.5,
iterations = 3,
outputs = "diagnostics",
intervals = intervals_opts(confidence = 0.90, prediction = 0.99)
)
result <- fit(model, x, y)
cat("Smoothed (first 5):", head(result$y, 5), "\n")
#> Smoothed (first 5): 0.4814511 0.4921418 0.5035375 0.5156728 0.528477
cat("CI lower (first 5):", head(result$confidence_lower, 5), "\n")
#> CI lower (first 5): 0.4195388 0.4274692 0.4360829 0.4454497 0.4555389
cat("CI upper (first 5):", head(result$confidence_upper, 5), "\n")
#> CI upper (first 5): 0.5433635 0.5568145 0.5709921 0.5858959 0.6014151
cat("R2:", result$diagnostics$r_squared, "\n")
#> R2: 0.7984579LOWESS can robustly handle outliers through iterative reweighting:
library(rfastlowess)
x_out <- seq(1, 6, length.out = 6)
y_with_outlier <- c(2.0, 4.0, 6.0, 50.0, 10.0, 12.0)
model <- Lowess(
fraction = 0.7,
iterations = 5,
robustness_method = "bisquare",
outputs = "weights"
)
result <- fit(model, x_out, y_with_outlier)
# Outliers will have low robustness weights
for (i in seq_along(result$robustness_weights)) {
if (result$robustness_weights[i] < 0.5)
cat(sprintf("Point %d is likely an outlier (weight: %.3f)\n",
i, result$robustness_weights[i]))
}
#> Point 4 is likely an outlier (weight: 0.000)For datasets too large to fit in memory, stream them in fixed-size chunks with overlap.
library(rfastlowess)
set.seed(42)
x <- seq(0, 10 * pi, length.out = 5000)
y <- sin(x / pi) * exp(-x / 30) + rnorm(5000, sd = 0.15)
model <- StreamingLowess(
fraction = 0.2,
chunk_size = 1000,
overlap = 100,
merge_strategy = "weighted_average"
)
chunk_size <- 1000
for (start in seq(1, 4001, by = chunk_size)) {
end <- min(start + chunk_size - 1, length(x))
process_chunk(model, x[start:end], y[start:end])
}
result <- finalize(model)
cat(sprintf("Smoothed %d points in streaming mode\n", length(result$y)))
#> Smoothed 100 points in streaming mode| Topic | Link |
|---|---|
| How LOWESS works | Concepts |
| All parameters explained | ?Lowess |
| Batch vs Streaming vs Online | Execution Modes |
| Edge handling | Boundary |
| Outlier handling in depth | Robustness |
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] rfastlowess_5.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