Node.js Examples¶
Complete Node.js examples demonstrating fastloess with native N-API bindings.
Batch Smoothing¶
Process complete datasets with confidence intervals and diagnostics.
const fastloess = require('../../bindings/nodejs');
/**
* fastloess Batch Smoothing - Comprehensive Examples
*
* 17 examples covering the full Loess batch API:
* 1. Basic smoothing
* 2. Robust smoothing with outliers
* 3. Uncertainty quantification (confidence/prediction intervals)
* 4. Cross-validation (K-Fold)
* 5. Complete diagnostic analysis
* 6. Different weight functions (kernels)
* 7. Robustness methods comparison
* 8. Benchmark
* 9. Scaling methods (MAR, MAD, Mean)
* 10. Boundary policies
* 11. Zero-weight fallback strategies
* 12. Polynomial degrees + iterations_used
* 13. Distance metrics
* 14. Surface modes and standard errors
* 15. Additional weight functions
* 16. LOOCV and auto-converge
* 17. Interpolation tuning (surface_mode effects)
*/
function makeLinear(n) {
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) { x[i] = i; y[i] = 2 * i + 1; }
return { x, y };
}
// ── Example 1: Basic Smoothing ──────────────────────────────────────────────
function example_1_basic_smoothing() {
console.log("Example 1: Basic Smoothing");
const x = new Float64Array([1, 2, 3, 4, 5]);
const y = new Float64Array([2.0, 4.1, 5.9, 8.2, 9.8]);
const result = new fastloess.Loess({ fraction: 0.5, iterations: 3 }).fit(x, y);
console.log(` fraction_used=${result.fraction_used}`);
console.log(` Smoothed: [${Array.from(result.y).map(v => v.toFixed(3)).join(', ')}]`);
console.log();
}
// ── Example 2: Robust Smoothing with Outliers ────────────────────────────────
function example_2_robust_with_outliers() {
console.log("Example 2: Robust Smoothing with Outliers");
const x = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8]);
const y = new Float64Array([2.1, 4.0, 5.9, 25.0, 10.1, 12.0, 14.1, 15.9]); // 25.0 is an outlier
const result = new fastloess.Loess({
fraction: 0.5,
iterations: 5,
robustness_method: "bisquare",
return_robustness_weights: true,
return_residuals: true,
}).fit(x, y);
const weights = result.robustness_weights;
if (weights) {
for (let i = 0; i < weights.length; i++) {
if (weights[i] < 0.5) {
console.log(` Outlier at index ${i} (y=${y[i]}): weight=${weights[i].toFixed(3)}`);
}
}
}
console.log(` Smoothed: [${Array.from(result.y).map(v => v.toFixed(2)).join(', ')}]`);
console.log();
}
// ── Example 3: Uncertainty Quantification ───────────────────────────────────
function example_3_uncertainty_quantification() {
console.log("Example 3: Uncertainty Quantification");
const x = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8]);
const y = new Float64Array([2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7]);
const result = new fastloess.Loess({
fraction: 0.5,
iterations: 3,
confidence_intervals: 0.95,
prediction_intervals: 0.95,
}).fit(x, y);
const cLow = result.confidence_lower;
const cHigh = result.confidence_upper;
const pLow = result.prediction_lower;
const pHigh = result.prediction_upper;
console.log(" x\t y_smooth\t conf[low, high]\t pred[low, high]");
for (let i = 0; i < result.y.length; i++) {
console.log(
` ${result.x[i].toFixed(0)}\t ${result.y[i].toFixed(4)}\t` +
` [${cLow[i].toFixed(4)}, ${cHigh[i].toFixed(4)}]\t` +
` [${pLow[i].toFixed(4)}, ${pHigh[i].toFixed(4)}]`
);
}
console.log();
}
// ── Example 4: Cross-Validation ──────────────────────────────────────────────
function example_4_cross_validation() {
console.log("Example 4: Cross-Validation for Parameter Selection");
const n = 20;
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) {
x[i] = i + 1;
y[i] = 2 * x[i] + 1 + Math.sin(x[i] * 0.5);
}
const result = new fastloess.Loess({
cv_fractions: [0.2, 0.3, 0.5, 0.7],
cv_method: "kfold",
cv_k: 5,
iterations: 2,
return_diagnostics: true,
}).fit(x, y);
console.log(` Selected fraction: ${result.fraction_used}`);
const scores = result.cv_scores;
if (scores) {
const fracs = [0.2, 0.3, 0.5, 0.7];
console.log(" CV Scores (RMSE per fraction):");
for (let i = 0; i < fracs.length; i++) {
console.log(` fraction=${fracs[i]}: ${scores[i].toFixed(4)}`);
}
}
console.log();
}
// ── Example 5: Complete Diagnostic Analysis ──────────────────────────────────
function example_5_complete_diagnostics() {
console.log("Example 5: Complete Diagnostic Analysis");
const x = new Float64Array([1, 2, 3, 4, 5, 6, 7, 8]);
const y = new Float64Array([2.1, 3.8, 6.2, 7.9, 10.3, 11.8, 14.1, 15.7]);
const result = new fastloess.Loess({
fraction: 0.5,
iterations: 3,
confidence_intervals: 0.95,
prediction_intervals: 0.95,
return_diagnostics: true,
return_residuals: true,
return_robustness_weights: true,
}).fit(x, y);
const diag = result.diagnostics;
if (diag) {
console.log(" Diagnostics:");
console.log(` RMSE: ${diag.rmse.toFixed(6)}`);
console.log(` MAE: ${diag.mae.toFixed(6)}`);
console.log(` R²: ${diag.r_squared.toFixed(6)}`);
console.log(` Residual SD: ${diag.residual_sd.toFixed(6)}`);
if (diag.aic != null) console.log(` AIC: ${diag.aic.toFixed(2)}`);
if (diag.aicc != null) console.log(` AICc: ${diag.aicc.toFixed(2)}`);
if (diag.effective_df != null) console.log(` Eff. DF: ${diag.effective_df.toFixed(2)}`);
}
console.log(` Smoothed[0]: ${result.y[0].toFixed(5)}`);
if (result.residuals) console.log(` residuals[0]: ${result.residuals[0].toFixed(5)}`);
if (result.robustness_weights) console.log(` robWeight[0]: ${result.robustness_weights[0].toFixed(4)}`);
console.log();
}
// ── Example 6: Different Weight Functions (Kernels) ──────────────────────────
function example_6_different_kernels() {
console.log("Example 6: Different Weight Functions (Kernels)");
const x = new Float64Array([1, 2, 3, 4, 5]);
const y = new Float64Array([2.0, 4.1, 5.9, 8.2, 9.8]);
for (const kernel of ["tricube", "epanechnikov", "gaussian", "biweight"]) {
const result = new fastloess.Loess({ fraction: 0.5, weight_function: kernel }).fit(x, y);
console.log(` ${kernel}: [${Array.from(result.y).map(v => v.toFixed(3)).join(', ')}]`);
}
console.log();
}
// ── Example 7: Robustness Methods Comparison ─────────────────────────────────
function example_7_robustness_methods() {
console.log("Example 7: Robustness Methods Comparison");
const x = new Float64Array([1, 2, 3, 4, 5]);
const y = new Float64Array([2.0, 4.1, 20.0, 8.2, 9.8]); // 20.0 is an outlier
for (const method of ["bisquare", "huber", "talwar"]) {
const result = new fastloess.Loess({
fraction: 0.5,
iterations: 5,
robustness_method: method,
return_robustness_weights: true,
}).fit(x, y);
const wStr = result.robustness_weights
? Array.from(result.robustness_weights).map(v => v.toFixed(3)).join(', ')
: 'N/A';
console.log(` ${method}:`);
console.log(` Smoothed: [${Array.from(result.y).map(v => v.toFixed(2)).join(', ')}]`);
console.log(` Weights: [${wStr}]`);
}
console.log();
}
// ── Example 8: Benchmark ─────────────────────────────────────────────────────
function example_8_benchmark() {
console.log("Example 8: Benchmark");
const n = 1000;
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) {
x[i] = i;
y[i] = Math.sin(i * 0.1) + Math.cos(i * 0.01);
}
const t0 = process.hrtime.bigint();
const result = new fastloess.Loess({ parallel: true }).fit(x, y);
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
console.log(` ${n} points in ${ms.toFixed(2)}ms`);
console.log(` fraction_used=${result.fraction_used}, y[0]=${result.y[0].toFixed(4)}`);
console.log();
}
// ── Example 9: Scaling Methods (MAR, MAD, Mean) ──────────────────────────────
function example_9_scaling_methods() {
console.log("Example 9: Scaling Methods");
const { x, y } = makeLinear(20);
for (const method of ["mar", "mad", "mean"]) {
const result = new fastloess.Loess({ fraction: 0.5, scaling_method: method }).fit(x, y);
console.log(` ${method}: y[0]=${result.y[0].toFixed(3)}`);
}
console.log();
}
// ── Example 10: Boundary Policies ────────────────────────────────────────────
function example_10_boundary_policies() {
console.log("Example 10: Boundary Policies");
const { x, y } = makeLinear(30);
for (const policy of ["extend", "reflect", "zero", "noboundary"]) {
const result = new fastloess.Loess({ fraction: 0.5, boundary_policy: policy }).fit(x, y);
console.log(
` ${policy}: first=${result.y[0].toFixed(2)}, last=${result.y[result.y.length - 1].toFixed(2)}`
);
}
console.log();
}
// ── Example 11: Zero-Weight Fallback Strategies ───────────────────────────────
function example_11_zero_weight_fallback() {
console.log("Example 11: Zero-Weight Fallback Strategies");
const { x, y } = makeLinear(20);
for (const fb of ["use_local_mean", "return_original", "return_none"]) {
const result = new fastloess.Loess({ fraction: 0.5, zero_weight_fallback: fb }).fit(x, y);
console.log(` ${fb}: y[0]=${result.y[0].toFixed(3)}`);
}
console.log();
}
// ── Example 12: Polynomial Degrees + iterations_used ──────────────────────────
function example_12_polynomial_degrees() {
console.log("Example 12: Polynomial Degrees");
const { x, y } = makeLinear(30);
for (const deg of ["constant", "linear", "quadratic", "cubic", "quartic"]) {
const result = new fastloess.Loess({
fraction: 0.5,
iterations: 2,
degree: deg,
}).fit(x, y);
console.log(
` ${deg}: y[0]=${result.y[0].toFixed(3)}, iterations_used=${result.iterations_used}`
);
}
console.log();
}
// ── Example 13: Distance Metrics ─────────────────────────────────────────────
function example_13_distance_metrics() {
console.log("Example 13: Distance Metrics");
const { x, y } = makeLinear(20);
for (const metric of ["euclidean", "normalized", "manhattan", "chebyshev"]) {
const result = new fastloess.Loess({ fraction: 0.5, distance_metric: metric }).fit(x, y);
console.log(` ${metric}: y[0]=${result.y[0].toFixed(3)}`);
}
// Minkowski with custom p via "minkowski:p" format
const rMink = new fastloess.Loess({ fraction: 0.5, distance_metric: "minkowski:3" }).fit(x, y);
console.log(` minkowski(p=3): y[0]=${rMink.y[0].toFixed(3)}`);
console.log();
}
// ── Example 14: Surface Modes and Standard Errors ────────────────────────────
function example_14_surface_modes_and_se() {
console.log("Example 14: Surface Modes and Standard Errors");
const { x, y } = makeLinear(30);
// Direct surface — fits every point exactly; SE fields fully populated
const rDirect = new fastloess.Loess({
fraction: 0.5,
surface_mode: "direct",
return_se: true,
confidence_intervals: 0.95,
prediction_intervals: 0.95,
}).fit(x, y);
console.log(" surface_mode=direct:");
console.log(` confidence_lower non-null: ${rDirect.confidence_lower != null}`);
console.log(` prediction_lower non-null: ${rDirect.prediction_lower != null}`);
if (rDirect.standard_errors) console.log(` standard_errors[0]: ${rDirect.standard_errors[0].toFixed(4)}`);
if (rDirect.enp != null) console.log(` enp: ${rDirect.enp.toFixed(3)}`);
if (rDirect.trace_hat != null) console.log(` trace_hat: ${rDirect.trace_hat.toFixed(3)}`);
if (rDirect.delta1 != null) console.log(` delta1: ${rDirect.delta1.toFixed(3)}`);
if (rDirect.delta2 != null) console.log(` delta2: ${rDirect.delta2.toFixed(3)}`);
if (rDirect.residual_scale != null) console.log(` residual_scale: ${rDirect.residual_scale.toFixed(4)}`);
if (rDirect.leverage) console.log(` leverage[0]: ${rDirect.leverage[0].toFixed(4)}`);
// Interpolation surface — faster, approximate
const rInterp = new fastloess.Loess({
fraction: 0.5,
surface_mode: "interpolation",
return_se: true,
}).fit(x, y);
console.log(" surface_mode=interpolation:");
console.log(` y[0]: ${rInterp.y[0].toFixed(3)}`);
if (rInterp.standard_errors) console.log(` standard_errors[0]: ${rInterp.standard_errors[0].toFixed(4)}`);
console.log();
}
// ── Example 15: Additional Weight Functions (Uniform, Triangle, Cosine) ───────
function example_15_additional_kernels() {
console.log("Example 15: Additional Weight Functions (Uniform, Triangle, Cosine)");
const x = new Float64Array([1, 2, 3, 4, 5]);
const y = new Float64Array([2.0, 4.1, 5.9, 8.2, 9.8]);
for (const kernel of ["uniform", "triangle", "cosine"]) {
const result = new fastloess.Loess({ fraction: 0.5, weight_function: kernel }).fit(x, y);
console.log(` ${kernel}: [${Array.from(result.y).map(v => v.toFixed(3)).join(', ')}]`);
}
console.log();
}
// ── Example 16: LOOCV, K-Fold, and Auto-Converge ─────────────────────────────
function example_16_loocv_and_auto_converge() {
console.log("Example 16: LOOCV, K-Fold, and Auto-Converge");
const n = 20;
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) {
x[i] = i + 1;
y[i] = 2 * x[i] + 1 + Math.sin(x[i] * 0.5);
}
// Leave-one-out cross-validation
const rLoocv = new fastloess.Loess({
cv_fractions: [0.3, 0.5, 0.7],
cv_method: "loocv",
}).fit(x, y);
console.log(` LOOCV selected fraction: ${rLoocv.fraction_used}`);
if (rLoocv.cv_scores) {
console.log(` LOOCV scores: [${Array.from(rLoocv.cv_scores).map(v => v.toFixed(4)).join(', ')}]`);
}
// K-Fold cross-validation
const rKfold = new fastloess.Loess({
cv_fractions: [0.2, 0.4, 0.6],
cv_method: "kfold",
cv_k: 5,
}).fit(x, y);
console.log(` KFold(k=5) selected fraction: ${rKfold.fraction_used}`);
if (rKfold.cv_scores) {
console.log(` KFold scores: [${Array.from(rKfold.cv_scores).map(v => v.toFixed(4)).join(', ')}]`);
}
// Auto-converge: stop robustness iterations when change < tolerance
const rAc = new fastloess.Loess({
fraction: 0.5,
auto_converge: 1e-4,
}).fit(x, y);
console.log(` auto_converge=1e-4: iterations_used=${rAc.iterations_used}`);
console.log();
}
// ── Example 17: Interpolation Tuning (surface_mode effects) ───────────────────
function example_17_interpolation_tuning() {
console.log("Example 17: Interpolation Tuning (surface_mode effects)");
const n = 50;
const { x, y } = makeLinear(n);
// Default (interpolation) — fastest, uses a spatial grid
const rInterp = new fastloess.Loess({
fraction: 0.5,
surface_mode: "interpolation",
}).fit(x, y);
console.log(` interpolation: y[0]=${rInterp.y[0].toFixed(3)}, y[-1]=${rInterp.y[n - 1].toFixed(3)}`);
// Direct — fits every point exactly, more accurate but slower
const rDirect = new fastloess.Loess({
fraction: 0.5,
surface_mode: "direct",
}).fit(x, y);
console.log(` direct: y[0]=${rDirect.y[0].toFixed(3)}, y[-1]=${rDirect.y[n - 1].toFixed(3)}`);
// Fraction sweep with direct surface
for (const frac of [0.2, 0.5, 0.8]) {
const r = new fastloess.Loess({ fraction: frac, surface_mode: "direct" }).fit(x, y);
console.log(` direct fraction=${frac}: y[0]=${r.y[0].toFixed(3)}`);
}
// Interpolation + SE for hat-matrix statistics
const rSe = new fastloess.Loess({
fraction: 0.5,
surface_mode: "interpolation",
return_se: true,
}).fit(x, y);
if (rSe.enp != null) console.log(` interpolation+SE enp: ${rSe.enp.toFixed(3)}`);
console.log();
}
// ── Main ──────────────────────────────────────────────────────────────────────
function main() {
console.log("=".repeat(60));
console.log("fastloess Batch Smoothing - Comprehensive Examples");
console.log("=".repeat(60));
console.log();
example_1_basic_smoothing();
example_2_robust_with_outliers();
example_3_uncertainty_quantification();
example_4_cross_validation();
example_5_complete_diagnostics();
example_6_different_kernels();
example_7_robustness_methods();
example_8_benchmark();
example_9_scaling_methods();
example_10_boundary_policies();
example_11_zero_weight_fallback();
example_12_polynomial_degrees();
example_13_distance_metrics();
example_14_surface_modes_and_se();
example_15_additional_kernels();
example_16_loocv_and_auto_converge();
example_17_interpolation_tuning();
console.log("=== Batch Smoothing Examples Complete ===");
}
main();
Streaming Smoothing¶
Process large datasets in memory-efficient chunks.
const fastloess = require('../../bindings/nodejs');
/**
* fastloess Streaming Smoothing - Comprehensive Examples
*
* 9 examples covering the full StreamingLoess API:
* 1. Basic chunked processing
* 2. Chunk size comparison
* 3. Overlap strategies
* 4. Large dataset processing
* 5. Outlier handling in streaming mode
* 6. File-based streaming simulation
* 7. Benchmark (sequential streaming)
* 8. Merge strategies (average, weighted_average, take_first, take_last)
* 9. Advanced streaming options
*/
function makeLinear(n) {
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) { x[i] = i; y[i] = 2 * i + 1; }
return { x, y };
}
// ── Example 1: Basic Chunked Processing ─────────────────────────────────────
function example_1_basic_chunked_processing() {
console.log("Example 1: Basic Chunked Processing");
const n = 50;
const { x, y } = makeLinear(n);
const chunk_size = 15;
const overlap = 5;
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5, iterations: 2, return_residuals: true },
{ chunk_size, overlap }
);
console.log(` Dataset: ${n} points, chunk=${chunk_size}, overlap=${overlap}`);
let totalProcessed = 0;
let chunkIdx = 0;
for (let start = 0; start < n; start += chunk_size - overlap) {
const end = Math.min(start + chunk_size, n);
const res = streamer.process_chunk(x.subarray(start, end), y.subarray(start, end));
if (res.x.length > 0) {
totalProcessed += res.x.length;
console.log(` Chunk ${chunkIdx}: ${res.x.length} pts (x: ${res.x[0].toFixed(0)}..${res.x[res.x.length - 1].toFixed(0)})`);
}
chunkIdx++;
}
const fin = streamer.finalize();
if (fin.x.length > 0) {
totalProcessed += fin.x.length;
console.log(` Finalize: ${fin.x.length} remaining pts`);
}
console.log(` Total: ${totalProcessed}/${n}`);
console.log();
}
// ── Example 2: Chunk Size Comparison ────────────────────────────────────────
function example_2_chunk_size_comparison() {
console.log("Example 2: Chunk Size Comparison");
const n = 100;
const { x, y } = makeLinear(n);
for (const [chunk_size, overlap, label] of [[20, 5, "Small"], [50, 10, "Medium"], [80, 15, "Large"]]) {
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5, iterations: 1 },
{ chunk_size, overlap }
);
let chunks = 0, total = 0;
for (let start = 0; start < n; start += chunk_size - overlap) {
const end = Math.min(start + chunk_size, n);
const res = streamer.process_chunk(x.subarray(start, end), y.subarray(start, end));
if (res.x.length > 0) { chunks++; total += res.x.length; }
}
const fin = streamer.finalize();
if (fin.x.length > 0) { chunks++; total += fin.x.length; }
console.log(` ${label} (size=${chunk_size}, overlap=${overlap}): chunks=${chunks}, total=${total}`);
}
console.log();
}
// ── Example 3: Overlap Strategies ────────────────────────────────────────────
function example_3_overlap_strategies() {
console.log("Example 3: Overlap Strategies");
const n = 100;
const { x, y } = makeLinear(n);
for (const [overlap, label] of [[0, "No overlap"], [10, "10-pt overlap"], [20, "20-pt overlap"]]) {
const chunk_size = 40;
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5 },
{ chunk_size, overlap }
);
let total = 0;
const step = chunk_size - overlap;
// Feed only full-size chunks; finalize() handles remaining data
for (let start = 0; start + chunk_size <= n; start += step) {
const res = streamer.process_chunk(x.subarray(start, start + chunk_size), y.subarray(start, start + chunk_size));
total += res.x.length;
}
total += streamer.finalize().x.length;
console.log(` ${label} (overlap=${overlap}): total points output=${total}`);
}
console.log();
}
// ── Example 4: Large Dataset Processing ──────────────────────────────────────
function example_4_large_dataset_processing() {
console.log("Example 4: Large Dataset Processing");
const n = 10000;
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) { x[i] = i; y[i] = Math.sin(i * 0.01) + i * 0.001; }
const chunk_size = 500;
const overlap = 50;
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.05, iterations: 2 },
{ chunk_size, overlap }
);
let total = 0;
const step = chunk_size - overlap;
for (let start = 0; start < n; start += step) {
const end = Math.min(start + chunk_size, n);
const res = streamer.process_chunk(x.subarray(start, end), y.subarray(start, end));
total += res.x.length;
if (total > 0 && total % 2000 < step) {
console.log(` Progress: ~${total} points smoothed`);
}
}
total += streamer.finalize().x.length;
console.log(` Total processed: ${total}/${n}`);
console.log(` Memory efficiency: constant (chunk=${chunk_size})`);
console.log();
}
// ── Example 5: Outlier Handling in Streaming Mode ─────────────────────────────
function example_5_outlier_handling() {
console.log("Example 5: Outlier Handling in Streaming Mode");
const n = 100;
const x = new Float64Array(n);
const y = new Float64Array(n);
for (let i = 0; i < n; i++) {
x[i] = i;
y[i] = 2 * i + 1 + Math.sin(i * 0.2) * 2;
if (i === 25 || i === 50 || i === 75) y[i] += 50; // Outliers
}
for (const method of ["bisquare", "huber", "talwar"]) {
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5, iterations: 5, robustness_method: method, return_residuals: true },
{ chunk_size: 30, overlap: 10 }
);
let largeResiduals = 0;
for (let start = 0; start < n; start += 20) {
const end = Math.min(start + 30, n);
const res = streamer.process_chunk(x.subarray(start, end), y.subarray(start, end));
if (res.residuals) {
for (const r of res.residuals) { if (Math.abs(r) > 10) largeResiduals++; }
}
}
const fin = streamer.finalize();
if (fin.residuals) {
for (const r of fin.residuals) { if (Math.abs(r) > 10) largeResiduals++; }
}
console.log(` ${method}: points with |residual|>10: ${largeResiduals}`);
}
console.log();
}
// ── Example 6: File-Based Streaming Simulation ───────────────────────────────
function example_6_file_simulation() {
console.log("Example 6: File-Based Streaming Simulation");
console.log(" Simulating: Read from input.csv -> Smooth -> Write to output.csv");
const totalLines = 200;
const chunk_size = 50;
const overlap = 10;
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5, iterations: 2, return_residuals: true },
{ chunk_size, overlap }
);
let outputLines = 0;
for (let ci = 0; ci < Math.ceil(totalLines / (chunk_size - overlap)); ci++) {
const start = ci * (chunk_size - overlap);
const end = Math.min(start + chunk_size, totalLines);
// Simulate reading a chunk from a file
const xChunk = new Float64Array(end - start);
const yChunk = new Float64Array(end - start);
for (let j = 0; j < end - start; j++) {
xChunk[j] = start + j;
yChunk[j] = 2 * xChunk[j] + 1 + Math.sin(xChunk[j] * 0.1) * 3;
}
console.log(` Reading chunk ${ci} (lines ${start}..${end - 1})`);
const res = streamer.process_chunk(xChunk, yChunk);
if (res.x.length > 0) {
outputLines += res.x.length;
console.log(` -> Writing ${res.x.length} smoothed pts (total: ${outputLines})`);
}
}
const fin = streamer.finalize();
if (fin.x.length > 0) {
outputLines += fin.x.length;
console.log(` Finalizing: Writing ${fin.x.length} remaining pts`);
}
console.log(` Input: ${totalLines}, Output: ${outputLines}`);
console.log();
}
// ── Example 7: Benchmark (Sequential Streaming) ───────────────────────────────
function example_7_benchmark() {
console.log("Example 7: Benchmark (Sequential Streaming)");
const n = 1000;
const chunk_size = 100;
const overlap = 10;
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5, iterations: 3 },
{ chunk_size, overlap }
);
const t0 = process.hrtime.bigint();
let total = 0;
const step = chunk_size - overlap;
for (let start = 0; start < n; start += step) {
const end = Math.min(start + chunk_size, n);
const xc = new Float64Array(end - start);
const yc = new Float64Array(end - start);
for (let j = 0; j < end - start; j++) {
xc[j] = start + j;
yc[j] = Math.sin(xc[j] * 0.1) + Math.cos(xc[j] * 0.01);
}
total += streamer.process_chunk(xc, yc).x.length;
}
total += streamer.finalize().x.length;
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
console.log(` ${total} points in ${ms.toFixed(2)}ms`);
console.log(` chunk=${chunk_size}, overlap=${overlap}`);
console.log();
}
// ── Example 8: Merge Strategies ──────────────────────────────────────────────
function example_8_merge_strategies() {
console.log("Example 8: Merge Strategies");
const n = 50;
const { x, y } = makeLinear(n);
for (const strategy of ["average", "weighted_average", "take_first", "take_last"]) {
const streamer = new fastloess.StreamingLoess(
{ fraction: 0.5, iterations: 2 },
{ chunk_size: 20, overlap: 5, merge_strategy: strategy }
);
let total = 0;
for (let start = 0; start < n; start += 15) {
const end = Math.min(start + 20, n);
total += streamer.process_chunk(x.subarray(start, end), y.subarray(start, end)).x.length;
}
total += streamer.finalize().x.length;
console.log(` ${strategy}: total=${total}`);
}
console.log();
}
// ── Example 9: Advanced Streaming Options ─────────────────────────────────────
function example_9_advanced_options() {
console.log("Example 9: Advanced Streaming Options");
const n = 50;
const { x, y } = makeLinear(n);
const streamer = new fastloess.StreamingLoess(
{
fraction: 0.5,
iterations: 2,
degree: "quadratic",
scaling_method: "mar",
boundary_policy: "reflect",
zero_weight_fallback: "return_original",
distance_metric: "manhattan",
surface_mode: "direct",
return_se: true,
return_diagnostics: true,
return_robustness_weights: true,
auto_converge: 1e-3,
},
{ chunk_size: 20, overlap: 5 }
);
let total = 0;
for (let start = 0; start < n; start += 15) {
const end = Math.min(start + 20, n);
total += streamer.process_chunk(x.subarray(start, end), y.subarray(start, end)).x.length;
}
const fin = streamer.finalize();
total += fin.x.length;
console.log(` total points: ${total}`);
if (fin.standard_errors && fin.standard_errors.length > 0) {
console.log(` standard_errors[0]: ${fin.standard_errors[0].toFixed(4)}`);
}
if (fin.diagnostics) {
console.log(` diagnostics.rmse: ${fin.diagnostics.rmse.toFixed(3)}`);
console.log(` diagnostics.r_squared: ${fin.diagnostics.r_squared.toFixed(3)}`);
if (fin.diagnostics.aic != null) console.log(` diagnostics.aic: ${fin.diagnostics.aic.toFixed(3)}`);
}
if (fin.robustness_weights && fin.robustness_weights.length > 0) {
console.log(` robustness_weights[0]: ${fin.robustness_weights[0].toFixed(4)}`);
}
console.log();
}
// ── Main ──────────────────────────────────────────────────────────────────────
function main() {
console.log("=".repeat(60));
console.log("fastloess Streaming Smoothing - Comprehensive Examples");
console.log("=".repeat(60));
console.log();
example_1_basic_chunked_processing();
example_2_chunk_size_comparison();
example_3_overlap_strategies();
example_4_large_dataset_processing();
example_5_outlier_handling();
example_6_file_simulation();
example_7_benchmark();
example_8_merge_strategies();
example_9_advanced_options();
console.log("=== Streaming Smoothing Examples Complete ===");
}
main();
Download streaming_smoothing.js
Online Smoothing¶
Real-time smoothing with sliding window for streaming data.
const fastloess = require('../../bindings/nodejs');
/**
* fastloess Online Smoothing - Comprehensive Examples
*
* 9 examples covering the full OnlineLoess API:
* 1. Basic incremental processing
* 2. Real-time sensor data simulation
* 3. Outlier handling in online mode
* 4. Window size comparison
* 5. Memory-bounded processing (embedded systems)
* 6. Sliding window behavior
* 7. Benchmark (sequential online)
* 8. Update modes (Full vs Incremental) and min_points
* 9. Advanced online options
*/
// ── Example 1: Basic Incremental Processing ──────────────────────────────────
function example_1_basic_streaming() {
console.log("Example 1: Basic Incremental Processing");
const data = [
[1, 3.1], [2, 5.0], [3, 7.2], [4, 8.9], [5, 11.1],
[6, 13.0], [7, 15.2], [8, 16.8], [9, 19.1], [10, 21.0],
];
const model = new fastloess.OnlineLoess(
{ fraction: 0.5, iterations: 2, return_residuals: true },
{ window_capacity: 5 }
);
console.log(` ${"X".padStart(8)} ${"Y_obs".padStart(12)} ${"Y_smooth".padStart(12)}`);
for (const [x, y] of data) {
const res = model.add_point(x, y);
const smoothed = res !== null ? res.smoothed.toFixed(2) : "(buffering)";
console.log(` ${x.toFixed(2).padStart(8)} ${y.toFixed(2).padStart(12)} ${smoothed.padStart(12)}`);
}
console.log();
}
// ── Example 2: Real-Time Sensor Data Simulation ───────────────────────────────
function example_2_sensor_data_simulation() {
console.log("Example 2: Real-Time Sensor Data Simulation");
console.log(" Simulating temperature sensor readings with noise...");
const n = 24; // 24 hours
const model = new fastloess.OnlineLoess(
{ fraction: 0.4, iterations: 3, robustness_method: "bisquare", return_residuals: true },
{ window_capacity: 12 }
);
console.log(` ${"Hour".padStart(6)} ${"Raw".padStart(12)} ${"Smoothed".padStart(12)}`);
for (let hour = 0; hour < n; hour++) {
const baseTemp = 20.0;
const cycle = 5.0 * Math.sin(hour * Math.PI / 12.0);
const noise = ((hour * 7) % 11) * 0.3 - 1.5;
const temp = baseTemp + cycle + noise;
const res = model.add_point(hour, temp);
if (res !== null) {
console.log(
` ${hour.toString().padStart(6)} ${temp.toFixed(2).padStart(12)}°C ${res.smoothed.toFixed(2).padStart(12)}°C`
);
} else {
console.log(` ${hour.toString().padStart(6)} ${temp.toFixed(2).padStart(12)}°C ${"(warming up)".padStart(13)}`);
}
}
console.log();
}
// ── Example 3: Outlier Handling in Online Mode ────────────────────────────────
function example_3_outlier_handling() {
console.log("Example 3: Outlier Handling in Online Mode");
const data = [
[1, 2.0], [2, 4.1], [3, 5.9],
[4, 25.0], // Outlier!
[5, 10.1], [6, 12.0], [7, 14.1],
[8, 50.0], // Outlier!
[9, 18.0], [10, 20.1],
];
for (const method of ["bisquare", "talwar"]) {
const model = new fastloess.OnlineLoess(
{ fraction: 0.5, iterations: 5, robustness_method: method, return_residuals: true },
{ window_capacity: 6 }
);
const smoothed = [];
for (const [x, y] of data) {
const res = model.add_point(x, y);
if (res !== null) smoothed.push(res.smoothed.toFixed(1));
}
console.log(` ${method}: [${smoothed.join(', ')}]`);
}
console.log();
}
// ── Example 4: Window Size Comparison ────────────────────────────────────────
function example_4_window_size_comparison() {
console.log("Example 4: Window Size Comparison");
const data = Array.from({ length: 20 }, (_, i) => {
const x = i + 1;
return [x, 2 * x + Math.sin(x * 0.5) * 3];
});
for (const windowSize of [5, 10, 15]) {
const model = new fastloess.OnlineLoess(
{ fraction: 0.5, iterations: 2 },
{ window_capacity: windowSize }
);
const smoothed = [];
for (const [x, y] of data) {
const res = model.add_point(x, y);
if (res !== null) smoothed.push(res.smoothed);
}
const last5 = smoothed.slice(-5).map(v => v.toFixed(2));
console.log(` window_capacity=${windowSize}: last 5 = [${last5.join(', ')}]`);
}
console.log();
}
// ── Example 5: Memory-Bounded Processing ──────────────────────────────────────
function example_5_memory_bounded_processing() {
console.log("Example 5: Memory-Bounded Processing (Embedded Systems)");
const total = 1000;
const model = new fastloess.OnlineLoess(
{ fraction: 0.3, iterations: 1 },
{ window_capacity: 20 }
);
let count = 0;
let lastSmoothed = 0;
for (let i = 0; i < total; i++) {
const x = i;
const y = 2 * x + Math.sin(x * 0.1) * 5 + ((i % 7) - 3) * 0.5;
const res = model.add_point(x, y);
if (res !== null) {
count++;
lastSmoothed = res.smoothed;
if (count % 200 === 0) {
console.log(` Processed: ${count.toString().padStart(4)} pts | smoothed=${lastSmoothed.toFixed(2)}`);
}
}
}
console.log(` Total processed: ${count}, final smoothed: ${lastSmoothed.toFixed(2)}`);
console.log(` Memory: constant (window=20)`);
console.log();
}
// ── Example 6: Sliding Window Behavior ───────────────────────────────────────
function example_6_sliding_window_behavior() {
console.log("Example 6: Sliding Window Behavior");
const data = [[1, 2], [2, 4], [3, 6], [4, 8], [5, 10], [6, 12], [7, 14], [8, 16]];
const model = new fastloess.OnlineLoess(
{ fraction: 0.6, iterations: 0, return_residuals: true },
{ window_capacity: 4 }
);
console.log(` ${"Pt".padStart(4)} ${"X".padStart(6)} ${"Y".padStart(8)} ${"Smoothed".padStart(10)} ${"Status".padStart(22)}`);
data.forEach(([x, y], i) => {
const res = model.add_point(x, y);
if (res !== null) {
console.log(` ${(i + 1).toString().padStart(4)} ${x.toFixed(0).padStart(6)} ${y.toFixed(0).padStart(8)} ${res.smoothed.toFixed(2).padStart(10)} ${"Window full (sliding)".padStart(22)}`);
} else {
console.log(` ${(i + 1).toString().padStart(4)} ${x.toFixed(0).padStart(6)} ${y.toFixed(0).padStart(8)} ${"-".padStart(10)} ${`Filling (${i + 1}/4)`.padStart(22)}`);
}
});
console.log(" Output starts after window fills (4 pts), then slides.");
console.log();
}
// ── Example 7: Benchmark (Sequential Online) ──────────────────────────────────
function example_7_benchmark() {
console.log("Example 7: Benchmark (Sequential Online)");
const n = 1000;
const model = new fastloess.OnlineLoess(
{ fraction: 0.5, iterations: 3 },
{ window_capacity: 10 }
);
const t0 = process.hrtime.bigint();
let count = 0;
for (let i = 0; i < n; i++) {
const x = i;
const y = Math.sin(x * 0.1) + Math.cos(x * 0.01);
const res = model.add_point(x, y);
if (res !== null) count++;
}
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
console.log(` ${count} pts processed in ${ms.toFixed(2)}ms`);
console.log(` window_capacity=10`);
console.log();
}
// ── Example 8: Update Modes (Full vs Incremental) and min_points ───────────────
function example_8_update_modes() {
console.log("Example 8: Update Modes (Full vs Incremental) and min_points");
const data = Array.from({ length: 30 }, (_, i) => [i, 2 * i + 1]);
for (const mode of ["full", "incremental"]) {
const model = new fastloess.OnlineLoess(
{ fraction: 0.5, iterations: 2 },
{ window_capacity: 15, min_points: 5, update_mode: mode }
);
let emitted = 0;
for (const [x, y] of data) {
const res = model.add_point(x, y);
if (res !== null) emitted++;
}
console.log(` ${mode}: ${emitted} points emitted (out of ${data.length})`);
}
// Show iterations_used from the returned OnlineOutput
const model = new fastloess.OnlineLoess(
{ fraction: 0.5, iterations: 2, return_residuals: true, return_robustness_weights: true },
{ window_capacity: 10, min_points: 3 }
);
let lastSmoothed = null;
let lastIterations = null;
for (const [x, y] of data) {
const res = model.add_point(x, y);
if (res !== null) { lastSmoothed = res.smoothed; lastIterations = res.iterations_used; }
}
if (lastSmoothed !== null) {
console.log(` last smoothed: ${lastSmoothed.toFixed(3)}`);
if (lastIterations !== null) console.log(` iterations_used: ${lastIterations}`);
}
console.log();
}
// ── Example 9: Advanced Online Options ────────────────────────────────────────
function example_9_advanced_online_options() {
console.log("Example 9: Advanced Online Options");
const data = Array.from({ length: 30 }, (_, i) => [i, 2 * i + 1]);
const model = new fastloess.OnlineLoess(
{
fraction: 0.5,
iterations: 2,
degree: "quadratic",
scaling_method: "mar",
boundary_policy: "reflect",
zero_weight_fallback: "return_original",
distance_metric: "chebyshev",
auto_converge: 1e-3,
return_residuals: true,
return_robustness_weights: true,
},
{ window_capacity: 15, min_points: 5 }
);
let emitted = 0;
let lastSmoothed = null;
for (const [x, y] of data) {
const res = model.add_point(x, y);
if (res !== null) { emitted++; lastSmoothed = res.smoothed; }
}
console.log(` emitted: ${emitted}`);
if (lastSmoothed !== null) {
console.log(` last smoothed: ${lastSmoothed.toFixed(3)}`);
}
console.log();
}
// ── Main ──────────────────────────────────────────────────────────────────────
function main() {
console.log("=".repeat(60));
console.log("fastloess Online Smoothing - Comprehensive Examples");
console.log("=".repeat(60));
console.log();
example_1_basic_streaming();
example_2_sensor_data_simulation();
example_3_outlier_handling();
example_4_window_size_comparison();
example_5_memory_bounded_processing();
example_6_sliding_window_behavior();
example_7_benchmark();
example_8_update_modes();
example_9_advanced_online_options();
console.log("=== Online Smoothing Examples Complete ===");
}
main();
Running the Examples¶
# Install the package
cd bindings/nodejs
npm install
npm run build
# Run examples
node examples/nodejs/batch_smoothing.js
node examples/nodejs/streaming_smoothing.js
node examples/nodejs/online_smoothing.js
Quick Start¶
const { Loess } = require('fastloess');
// Generate sample data
const x = Array.from({ length: 100 }, (_, i) => i * 0.1);
const y = x.map(xi => Math.sin(xi) + Math.random() * 0.2);
// Basic smoothing
const model = new Loess({ fraction: 0.3 });
const result = model.fit(x, y);
console.log('Smoothed values:', result.y);
// With options
const resultWithOptions = new Loess({
fraction: 0.3,
iterations: 3,
confidence_intervals: 0.95,
return_diagnostics: true
}).fit(x, y);
console.log('R²:', resultWithOptions.diagnostics.r_squared);
TypeScript Support¶
The package includes TypeScript definitions: