micro-ml API Documentation

Complete function reference with examples and performance benchmarks

Loading WASM module...

Getting Started

Installation

npm install micro-ml

Basic Usage

import { linearRegression, init } from 'micro-ml';

// Optional: explicitly initialize WASM (auto-initializes on first call)
await init();

// Fit a model
const model = await linearRegression([1, 2, 3, 4, 5], [2, 4, 6, 8, 10]);

console.log(model.slope);     // 2
console.log(model.intercept); // 0
console.log(model.rSquared);  // 1
console.log(model.predict([6, 7, 8])); // [12, 14, 16]

Browser Usage (ES Modules)

<script type="module">
  import * as ml from './node_modules/micro-ml/dist/index.js';

  const model = await ml.linearRegression([1, 2, 3], [2, 4, 6]);
  console.log(model.slope); // 2
</script>

Linear Regression

Fit a line: y = slope * x + intercept

linearRegression(x, y)

async function linearRegression(x: number[], y: number[]): Promise<LinearModel>
ParameterTypeDescription
xnumber[]Independent variable values
ynumber[]Dependent variable values (same length as x)

Returns: LinearModel

PropertyTypeDescription
slopenumberSlope coefficient (m)
interceptnumberY-intercept (b)
rSquarednumberCoefficient of determination (0-1)
nnumberNumber of data points
predict(x)(number[]) => number[]Predict y values for given x
toString()() => stringHuman-readable equation

Example

// Stock price trend
const days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const prices = [100, 102, 105, 103, 108, 110, 112, 115, 118, 120];

const model = await linearRegression(days, prices);

console.log(`Trend: $${model.slope.toFixed(2)}/day`);
console.log(`R² = ${(model.rSquared * 100).toFixed(1)}%`);

// Predict next 5 days
const forecast = model.predict([11, 12, 13, 14, 15]);

linearRegressionSimple(y)

async function linearRegressionSimple(y: number[]): Promise<LinearModel>

Convenience function when x values are just indices (0, 1, 2, ...). Useful for time series.

// Equivalent calls:
const model1 = await linearRegressionSimple([10, 20, 30, 40]);
const model2 = await linearRegression([0, 1, 2, 3], [10, 20, 30, 40]);

Polynomial Regression

Fit a curve: y = c₀ + c₁x + c₂x² + c₃x³ + ...

polynomialRegression(x, y, options?)

async function polynomialRegression(x: number[], y: number[], options?: { degree?: number }): Promise<PolynomialModel>
ParameterTypeDescription
xnumber[]Independent variable values
ynumber[]Dependent variable values
options.degreenumberPolynomial degree (default: 2)

Returns: PolynomialModel

PropertyTypeDescription
degreenumberPolynomial degree
rSquarednumberCoefficient of determination
nnumberNumber of data points
getCoefficients()() => number[]Returns [c₀, c₁, c₂, ...]
predict(x)(number[]) => number[]Predict y values

Example

// Projectile motion (parabola)
const time = [0, 0.5, 1, 1.5, 2, 2.5, 3];
const height = [0, 11.4, 19.6, 24.5, 26.1, 24.5, 19.6];

const model = await polynomialRegression(time, height, { degree: 2 });

console.log('Coefficients:', model.getCoefficients());
// [c₀, c₁, c₂] representing: height = c₀ + c₁*t + c₂*t²

// Find max height
const tMax = 1.5;
console.log('Max height:', model.predict([tMax])[0]);
Note: Higher degrees (>5) may cause numerical instability. Use the minimum degree that fits your data well.

Exponential Regression

Fit growth/decay: y = a × e^(bx)

exponentialRegression(x, y)

async function exponentialRegression(x: number[], y: number[]): Promise<ExponentialModel>
Requirement: All y values must be positive (> 0).

Returns: ExponentialModel

PropertyTypeDescription
anumberInitial value coefficient
bnumberGrowth rate (positive = growth, negative = decay)
rSquarednumberCoefficient of determination
doublingTime()() => numberTime to double (for growth)
predict(x)(number[]) => number[]Predict y values

Example

// Bacterial growth
const hours = [0, 1, 2, 3, 4, 5, 6];
const population = [100, 150, 225, 338, 506, 759, 1139];

const model = await exponentialRegression(hours, population);

console.log(`Initial: ${model.a.toFixed(0)} bacteria`);
console.log(`Growth rate: ${(model.b * 100).toFixed(1)}% per hour`);
console.log(`Doubling time: ${model.doublingTime().toFixed(2)} hours`);

// Predict after 10 hours
const future = model.predict([10]);
console.log(`After 10 hours: ${future[0].toFixed(0)} bacteria`);

Logarithmic Regression

Fit logarithmic curve: y = a + b × ln(x)

logarithmicRegression(x, y)

async function logarithmicRegression(x: number[], y: number[]): Promise<LogarithmicModel>
Requirement: All x values must be positive (> 0).

Returns: LogarithmicModel

PropertyTypeDescription
anumberIntercept
bnumberLogarithmic coefficient
rSquarednumberCoefficient of determination
predict(x)(number[]) => number[]Predict y values

Example

// Learning curve (diminishing returns)
const practice = [1, 2, 5, 10, 20, 50, 100];
const skill = [10, 25, 45, 60, 75, 90, 100];

const model = await logarithmicRegression(practice, skill);

console.log(`Skill = ${model.a.toFixed(2)} + ${model.b.toFixed(2)} × ln(practice)`);
console.log(`R² = ${(model.rSquared * 100).toFixed(1)}%`);

// How much practice for 95% skill?
// Solve: 95 = a + b * ln(x)
const target = Math.exp((95 - model.a) / model.b);
console.log(`Need ${target.toFixed(0)} hours for 95% skill`);

Power Regression

Fit power law: y = a × x^b

powerRegression(x, y)

async function powerRegression(x: number[], y: number[]): Promise<PowerModel>
Requirement: All x and y values must be positive (> 0).

Example

// Kepler's third law: T² ∝ r³
const orbitalRadius = [0.39, 0.72, 1.0, 1.52, 5.2, 9.54];  // AU
const orbitalPeriod = [0.24, 0.62, 1.0, 1.88, 11.86, 29.46]; // years

const model = await powerRegression(orbitalRadius, orbitalPeriod);

console.log(`Period = ${model.a.toFixed(4)} × radius^${model.b.toFixed(4)}`);
// b should be close to 1.5 (Kepler's law: T = r^1.5)

Moving Averages

Smooth noisy time series data.

Available Functions

async function sma(data: number[], window: number): Promise<number[]> async function ema(data: number[], window: number): Promise<number[]> async function wma(data: number[], window: number): Promise<number[]> async function movingAverage(data: number[], options: MovingAverageOptions): Promise<number[]>
FunctionDescriptionUse Case
smaSimple Moving Average - equal weight to all periodsGeneral smoothing
emaExponential MA - more weight to recent valuesTrend following, quick response
wmaWeighted MA - linearly decreasing weightsBalance between SMA and EMA
Note: Returns NaN for positions before the window is full. For a window of 5, the first 4 values will be NaN.

Example

// Stock price smoothing
const prices = [100, 102, 98, 105, 110, 108, 115, 112, 120, 118, 125];

const simple = await sma(prices, 3);
const exponential = await ema(prices, 3);
const weighted = await wma(prices, 3);

console.log('SMA:', simple);    // [NaN, NaN, 100, 101.67, 104.33, ...]
console.log('EMA:', exponential); // [NaN, NaN, 100, 102.5, 106.25, ...]
console.log('WMA:', weighted);   // [NaN, NaN, 99.33, 103.17, 106.17, ...]

// Using generic function
const result = await movingAverage(prices, { window: 5, type: 'ema' });

Trend Analysis & Forecasting

trendForecast(data, periods)

async function trendForecast(data: number[], periods: number): Promise<TrendAnalysis>

Returns: TrendAnalysis

PropertyTypeDescription
direction'up' | 'down' | 'flat'Trend direction
slopenumberRate of change per period
strengthnumberR² value (0-1), how well trend fits
getForecast()() => number[]Predicted future values

Other Trend Functions

async function rateOfChange(data: number[], periods: number): Promise<number[]> async function momentum(data: number[], periods: number): Promise<number[]> async function exponentialSmoothing(data: number[], options?: { alpha?: number }): Promise<number[]>

Example

// Sales trend analysis
const monthlySales = [42, 45, 48, 52, 55, 58, 62, 68, 72, 75, 80, 85];

const trend = await trendForecast(monthlySales, 6);

console.log(`Direction: ${trend.direction}`);     // 'up'
console.log(`Growth: $${trend.slope.toFixed(2)}/month`);
console.log(`Confidence: ${(trend.strength * 100).toFixed(1)}%`);
console.log(`Next 6 months:`, trend.getForecast());

// Rate of change (% change from n periods ago)
const roc = await rateOfChange(monthlySales, 3);
console.log('3-month ROC:', roc);

// Momentum (absolute change from n periods ago)
const mom = await momentum(monthlySales, 3);
console.log('3-month momentum:', mom);

Utility Functions

findPeaks(data) / findTroughs(data)

async function findPeaks(data: number[]): Promise<number[]> async function findTroughs(data: number[]): Promise<number[]>

Returns indices of local maxima (peaks) or minima (troughs).

predict(xTrain, yTrain, xPredict)

async function predict(xTrain: number[], yTrain: number[], xPredict: number[]): Promise<number[]>

One-liner: fit linear model and predict in single call.

trendLine(data, futurePoints)

async function trendLine(data: number[], futurePoints: number): Promise<{ model: LinearModel, trend: number[] }>

Quick trend line with future predictions.

Example

// Find peaks and troughs in stock data
const prices = [100, 105, 102, 110, 108, 115, 112, 120, 118];

const peaks = await findPeaks(prices);   // indices of local highs
const troughs = await findTroughs(prices); // indices of local lows

console.log('Peak indices:', peaks);     // [1, 3, 5, 7]
console.log('Peak values:', peaks.map(i => prices[i]));

// Quick prediction
const predicted = await predict(
  [1, 2, 3, 4, 5],  // x training
  [10, 20, 30, 40, 50],  // y training
  [6, 7, 8]  // x to predict
);
console.log('Predicted:', predicted); // [60, 70, 80]

Performance Benchmarks

Test micro-ml with large datasets to see WASM performance.

-
1,000 points
-
10,000 points
-
100,000 points
-
1,000,000 points

Expected Performance

Benchmarked on real hardware (median of 5 runs)

Data SizeLinear RegressionPolynomial (deg 3)Moving Average
1,000< 1ms< 1ms< 1ms
10,000< 1ms< 1ms< 1ms
100,0001ms5ms3-4ms
1,000,0006-12ms53ms30-35ms
10,000,00050-100ms~530ms~280ms
100,000,000~500ms-1s-~2.9s

Bottlenecks & Best Practices

1. WASM Initialization

First call overhead: The first function call loads the WASM module (~40KB). Subsequent calls are instant.
// Pre-load WASM during app startup
import { init } from 'micro-ml';

// Call early in your app lifecycle
await init();  // ~10-50ms first time

// Now all calls are fast
const model = await linearRegression(x, y);  // < 1ms

2. Array Conversion Overhead

Tip: Each call converts JavaScript arrays to Float64Array for WASM. For repeated operations on the same data, this is unavoidable but minimal.
// Each call has ~0.1ms overhead for array conversion
// For 100,000 points: ~1ms conversion + ~10ms computation

// If doing multiple operations, they share the same conversion cost
const linear = await linearRegression(x, y);    // includes conversion
const poly = await polynomialRegression(x, y);  // includes conversion again

3. Polynomial Degree Limits

Caution: High polynomial degrees cause numerical instability and slow performance.
// Good: degree 2-4
const quadratic = await polynomialRegression(x, y, { degree: 2 }); // Fast, stable

// Risky: degree 5-7
const quintic = await polynomialRegression(x, y, { degree: 5 }); // May have precision issues

// Avoid: degree > 7
const high = await polynomialRegression(x, y, { degree: 10 }); // Likely unstable

4. Memory Considerations

// Each number = 8 bytes (Float64)
// 1M points = ~8MB per array
// Linear regression with 1M points = ~16MB (x + y arrays)

// For very large datasets, consider:
// 1. Sampling: Use every nth point
// 2. Chunking: Process in batches
// 3. Web Workers: Keep UI responsive

5. Web Worker Usage

// For large datasets, use Web Workers to avoid blocking UI
import { createWorker } from 'micro-ml/worker';

const worker = await createWorker();

// Non-blocking regression on huge dataset
const model = await worker.linearRegression(hugeX, hugeY);

// Clean up when done
worker.terminate();

6. Common Pitfalls

IssueCauseSolution
Error: "All y values must be positive" exponentialRegression with y ≤ 0 Filter/transform data or use different model
Error: "Arrays must have same length" Mismatched x and y arrays Verify array lengths match
R² is negative Wrong model type for data Try different regression type
NaN in results Division by zero or log of negative Check input data for zeros/negatives
Slow performance Many small calls instead of batching Batch predictions in single predict() call