--- title: "Use Case: Real-Time Processing" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Use Case: Real-Time Processing} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` ## Overview When data arrives continuously — from sensors, logs, or streaming pipelines — you need incremental smoothing that doesn't require reprocessing the entire dataset. --- ## Online Mode: Point-by-Point For true real-time applications where each point must be processed immediately. `window_capacity = 25` limits the internal buffer to the 25 most recent observations; each `add_point` call costs O(window) rather than growing with total history. `min_points = 5` suppresses output until the window holds enough points for a stable fit — calls made before that threshold return `NULL`. `update_mode = "incremental"` re-fits only the most recent point rather than the full window, halving typical latency at a modest accuracy cost. ### Sensor Data Example ```{r use_case_real_time_1} library(rfastloess) set.seed(42) times <- 1:100 temperatures <- 20 + 5 * sin(times / 10) + rnorm(100) model <- OnlineLoess( fraction = 0.3, window_capacity = 25, min_points = 5, update_mode = "incremental" ) for (i in seq_along(times)) { result <- add_point(model, times[i], temperatures[i]) if (!is.null(result)) cat(sprintf("Time %d: %.2f\n", times[i], result$y)) if (i >= 10) break # print only the first few outputs } ``` ### Accumulating Results ```{r use_case_real_time_2} library(rfastloess) set.seed(42) n <- 200 times <- seq_len(n) signal <- 10 + 2 * sin(times / 20) + rnorm(n, sd = 1) model <- OnlineLoess( fraction = 0.3, window_capacity = 30, min_points = 5 ) smoothed_x <- numeric(n) smoothed_y <- numeric(n) n_out <- 0L for (i in seq_len(n)) { result <- add_point(model, times[i], signal[i]) if (!is.null(result)) { n_out <- n_out + 1L smoothed_x[n_out] <- times[i] smoothed_y[n_out] <- result$y } } smoothed_x <- smoothed_x[seq_len(n_out)] smoothed_y <- smoothed_y[seq_len(n_out)] plot(times, signal, pch = 16, cex = 0.4, col = "gray", xlab = "Time", ylab = "Value", main = "Online LOESS — Accumulated Output") lines(smoothed_x, smoothed_y, col = "blue", lwd = 2) ``` --- ## Streaming Mode: Chunk Processing For large datasets that arrive in batches or files. `chunk_size` controls how many data points are processed in one pass; matching it to your file-read buffer or message-batch size avoids unnecessary copying. `overlap` retains that many points from the previous chunk as context so the neighbourhood at chunk boundaries is not artificially truncated. `merge_strategy = "weighted_average"` blends the overlapping region smoothly; use `"take_last"` if chunk boundaries are guaranteed to be well separated and no blending is needed. > **Always call finalize():** The streaming adapter buffers overlap data. > Call `finalize(model)` after the last chunk to retrieve the buffered tail. ### Log File Processing ```{r use_case_real_time_3} library(rfastloess) set.seed(42) total_points <- 100000 x <- 0:(total_points - 1) y <- sin(x / 1000) + rnorm(total_points, sd = 0.1) model <- StreamingLoess( fraction = 0.05, chunk_size = 10000, overlap = 1000, merge_strategy = "weighted_average" ) process_chunk(model, x, y) result <- finalize(model) cat("Processed", length(result$y), "points\n") ``` --- ## Real-Time Dashboard Example The dashboard pattern uses a plain LOESS fit on a manually managed sliding window rather than `OnlineLoess`. This is the simplest approach when your UI framework already owns the data buffer and you only need the most recent smoothed value per frame. The trade-off is a full O(window^2) refit on every tick; for high-frequency streams prefer `OnlineLoess` with `update_mode = "incremental"` to bound per-frame cost. ```{r use_case_real_time_4} library(rfastloess) set.seed(42) window_capacity <- 50 data_x <- numeric(0) data_y <- numeric(0) for (i in 0:199) { xi <- i yi <- 25.0 + 10 * sin(i / 20) + rnorm(1, sd = 2) data_x <- c(data_x, xi) data_y <- c(data_y, yi) if (length(data_x) > window_capacity) { data_x <- tail(data_x, window_capacity) data_y <- tail(data_y, window_capacity) } if (length(data_x) >= 5) { model <- Loess(fraction = 0.4) result <- fit(model, data_x, data_y) current_smoothed <- tail(result$y, 1) } } ``` --- ## Choosing Parameters ### Online Mode | Parameter | Guidance | | --- | --- | | `window_capacity` | Enough history for `fraction` to work | | `min_points` | 2–5 typically; higher for stability | | `update_mode` | `"incremental"` for speed, `"full"` for accuracy | ### Streaming Mode | Parameter | Guidance | | --- | --- | | `chunk_size` | Balance memory vs. processing overhead | | `overlap` | 10–20% of chunk_size for smooth transitions | | `merge_strategy` | `"weighted_average"` (quality) vs `"average"` (simple) | --- ## Performance Considerations | Mode | Memory | Latency | Use Case | | --- | --- | --- | --- | | **Online** | Fixed (window) | ~1ms/point | Sensors, dashboards | | **Streaming** | ~chunk_size | ~100ms/chunk | Large files, ETL | | **Batch** | Full dataset | N/A | Analysis, reports | --- ## See Also - `vignette("adapter-choice", package = "rfastloess")` — Detailed mode comparison - `vignette("merge", package = "rfastloess")` — Chunk reconciliation in depth - `vignette("scaling", package = "rfastloess")` — Robustness scale estimation - `vignette("use-case-time-series", package = "rfastloess")` — General time series analysis ```{r session-info} sessionInfo() ```