stats
stableA comprehensive statistics library providing descriptive statistics, distributions, regression, resampling, and time-series analysis functions.
use plugin stats::{mean, median, mode, …} Functions (37)
- mean Arithmetic mean of a dataset
- median Middle value of a sorted dataset
- mode Most frequently occurring value
- variance Sample variance (Bessel-corrected)
- std_dev Sample standard deviation
- population_variance Population variance (divide by N)
- population_std_dev Population standard deviation
- min Minimum value in dataset
- max Maximum value in dataset
- sum Sum of all values
- range Difference between max and min
- percentile Value at a given percentile
- iqr Interquartile range (Q3 - Q1)
- outliers Values outside IQR fence
- normalize Scale dataset to [0, 1] range
- z_score Standard score for a value
- skewness Adjusted Fisher-Pearson skewness
- kurtosis Excess kurtosis
- correlation Pearson correlation coefficient
- covariance Sample covariance of two datasets
- spearman_correlation Rank-based correlation
- linear_regression Slope, intercept, and R-squared
- histogram Frequency distribution into bins
- moving_average Simple moving average
- exponential_moving_average EMA with smoothing factor alpha
- t_test Welch's t-test for two samples
- chi_squared_test Chi-squared goodness of fit
- sample_with_replacement Draw n samples with replacement
- bootstrap_mean Bootstrap mean with 95% CI
- cumulative_sum Running total of values
- rank Ordinal ranks with tie averaging
- weighted_mean Mean weighted by a second dataset
- geometric_mean Nth root of product of all values
- harmonic_mean Reciprocal mean
- describe Summary statistics in one call
- standard_error Standard error of the mean
- mean_absolute_deviation Average absolute deviation from mean
Overview
stats is a batteries-included statistics toolkit exposed as a single static
class. Every function is called as stats.fn(...) and operates on plain Zolo
arrays of numbers — there is no handle to construct or state to carry between
calls, so a dataset is just an array you pass in and a result (a number or a
table) you get back. The library spans the full descriptive-statistics surface
(mean, median, variance, percentiles, skewness, kurtosis), relationship measures
(Pearson and Spearman correlation, covariance, linear regression), hypothesis
tests (Welch's t-test, chi-squared), resampling (bootstrap, sampling with
replacement), and time-series helpers (moving averages, cumulative sums).
The mental model is simple: hand any function an array of numbers, and it
either reduces it to a single value, or returns a new array/table derived from
it. Functions that need a second series (correlation, t_test,
weighted_mean, ...) take a second array of matching length. Reach for it
whenever you need to summarize a dataset, quantify dispersion, compare two
groups, or smooth a series — all without pulling in an external dependency.
Common patterns
Summarize a dataset in one call, then drill into a specific quartile:
use plugin stats::{stats}
let data = [4.0, 7.0, 13.0, 16.0, 21.0, 24.0, 100.0]
let s = stats.describe(data)
print("mean={s["mean"]}, median={s["median"]}, std_dev={s["std_dev"]}")
print("spread: q1={s["q1"]}, q3={s["q3"]}, iqr={stats.iqr(data)}")
Flag anomalies with Tukey fences, then re-summarize the clean data:
use plugin stats::{stats}
let readings = [10.0, 11.0, 9.0, 12.0, 10.5, 250.0]
let bad = stats.outliers(readings, 1.5)
print("outliers found: {bad}")
print("median is robust to them: {stats.median(readings)}")
Fit a trend line and judge its quality with R-squared:
use plugin stats::{stats}
let x = [1.0, 2.0, 3.0, 4.0, 5.0]
let y = [2.1, 3.9, 6.2, 7.8, 10.1]
let model = stats.linear_regression(x, y)
print("y = {model["slope"]} * x + {model["intercept"]}")
print("fit quality (r2): {model["r_squared"]}")
Arithmetic mean of a dataset
Returns the arithmetic mean of the numeric dataset. Errors on empty input.
use plugin stats::{stats}
let scores = [85.0, 90.0, 78.0, 92.0, 88.0]
print(stats.mean(scores))
Pair it with std_dev to report a center-and-spread summary:
use plugin stats::{stats}
let latencies = [120.0, 135.0, 128.0, 142.0, 119.0]
print("avg {stats.mean(latencies)}ms ± {stats.std_dev(latencies)}ms")
Middle value of a sorted dataset
Returns the median value. For even-length datasets, returns the average of the two middle values.
use plugin stats::{stats}
let values = [3.0, 1.0, 4.0, 1.0, 5.0, 9.0]
print(stats.median(values))
Most frequently occurring value
Returns the most frequently occurring value. Uses rounded integer keys at 6 decimal places for comparison.
use plugin stats::{stats}
let votes = [1.0, 2.0, 2.0, 3.0, 2.0, 1.0]
print(stats.mode(votes))
Sample variance (Bessel-corrected)
Returns the sample variance using Bessel's correction (divides by N-1). Requires at least 2 data points.
use plugin stats::{stats}
let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]
print(stats.variance(data))
Sample standard deviation
Returns the sample standard deviation (square root of sample variance). Requires at least 2 data points.
use plugin stats::{stats}
let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]
print(stats.std_dev(data))
Population variance (divide by N)
Returns the population variance (divides by N instead of N-1). Use when the dataset represents the entire population.
use plugin stats::{stats}
print(stats.population_variance([2.0, 4.0, 6.0]))
Population standard deviation
Returns the population standard deviation.
use plugin stats::{stats}
print(stats.population_std_dev([2.0, 4.0, 6.0]))
Minimum value in dataset
Returns the minimum value in the dataset.
use plugin stats::{stats}
print(stats.min([3.0, 1.0, 4.0, 1.0, 5.0]))
Maximum value in dataset
Returns the maximum value in the dataset.
use plugin stats::{stats}
print(stats.max([3.0, 1.0, 4.0, 1.0, 5.0]))
Sum of all values
Returns the total sum of all values.
use plugin stats::{stats}
print(stats.sum([1.0, 2.0, 3.0, 4.0, 5.0]))
Difference between max and min
Returns the difference between the maximum and minimum values.
use plugin stats::{stats}
print(stats.range([10.0, 20.0, 5.0, 30.0]))
Value at a given percentile
Returns the value at the p-th percentile (0–100) using linear interpolation.
use plugin stats::{stats}
let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
print(stats.percentile(data, 75.0))
Compute a tail latency budget (the median and the p95):
use plugin stats::{stats}
let times = [12.0, 15.0, 11.0, 22.0, 18.0, 90.0, 14.0, 16.0]
print("p50: {stats.percentile(times, 50.0)}")
print("p95: {stats.percentile(times, 95.0)}")
Interquartile range (Q3 - Q1)
Returns the interquartile range (Q3 - Q1), useful for measuring statistical dispersion.
use plugin stats::{stats}
let data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
print(stats.iqr(data))
Values outside IQR fence
Returns values that fall outside Q1 - thresholdIQR or Q3 + thresholdIQR. Default threshold is 1.5 (standard Tukey fences).
use plugin stats::{stats}
let data = [1.0, 2.0, 3.0, 4.0, 5.0, 100.0]
let found = stats.outliers(data, 1.5)
Scale dataset to [0, 1] range
Scales all values to the [0, 1] range using min-max normalization. Returns a new table of the same length.
use plugin stats::{stats}
let raw = [10.0, 20.0, 30.0, 40.0, 50.0]
let scaled = stats.normalize(raw)
Standard score for a value
Returns how many standard deviations value is from mean. Errors if std_dev is zero.
use plugin stats::{stats}
let score = stats.z_score(85.0, 70.0, 10.0)
print("z-score: {score}")
Adjusted Fisher-Pearson skewness
Returns the adjusted Fisher-Pearson skewness coefficient. Requires at least 3 data points. Positive means right-skewed, negative means left-skewed.
use plugin stats::{stats}
let data = [1.0, 2.0, 3.0, 4.0, 10.0]
print(stats.skewness(data))
Excess kurtosis
Returns the excess kurtosis (normal distribution = 0). Requires at least 4 data points. Positive values indicate heavier tails than normal.
use plugin stats::{stats}
let data = [1.0, 2.0, 3.0, 2.0, 1.0, 3.0, 2.0, 2.0]
print(stats.kurtosis(data))
Pearson correlation coefficient
Returns the Pearson correlation coefficient between two equal-length datasets. Returns a value in [-1, 1].
use plugin stats::{stats}
let x = [1.0, 2.0, 3.0, 4.0, 5.0]
let y = [2.0, 4.0, 5.0, 4.0, 5.0]
print(stats.correlation(x, y))
A perfectly inverse relationship returns -1.0:
use plugin stats::{stats}
let up = [1.0, 2.0, 3.0, 4.0]
let down = [8.0, 6.0, 4.0, 2.0]
print(stats.correlation(up, down))
Sample covariance of two datasets
Returns the sample covariance between two equal-length datasets.
use plugin stats::{stats}
let x = [1.0, 2.0, 3.0]
let y = [4.0, 5.0, 6.0]
print(stats.covariance(x, y))
Rank-based correlation
Returns the Spearman rank correlation, which is robust to outliers and non-linear relationships.
use plugin stats::{stats}
let x = [1.0, 2.0, 3.0, 4.0, 5.0]
let y = [5.0, 6.0, 7.0, 8.0, 7.0]
print(stats.spearman_correlation(x, y))
Slope, intercept, and R-squared
Fits a line y = slope*x + intercept to the data. Returns a table with slope, intercept, and r_squared.
use plugin stats::{stats}
let x = [1.0, 2.0, 3.0, 4.0, 5.0]
let y = [2.1, 3.9, 6.2, 7.8, 10.1]
let model = stats.linear_regression(x, y)
print("slope={model["slope"]}, r2={model["r_squared"]}")
Frequency distribution into bins
Divides data into bins equal-width buckets. Returns a table of {min, max, count} entries.
use plugin stats::{stats}
let data = [1.0, 2.0, 2.5, 3.0, 4.0, 4.5, 5.0]
let hist = stats.histogram(data, 5)
for _, bin in hist {
print("{bin["min"]}-{bin["max"]}: {bin["count"]}")
}
Simple moving average
Returns the simple moving average with the given window size. Output length is len(data) - window + 1.
use plugin stats::{stats}
let prices = [10.0, 12.0, 11.0, 13.0, 14.0, 15.0]
let ma = stats.moving_average(prices, 3)
Iterate the smoothed series to print each windowed average:
use plugin stats::{stats}
let prices = [10.0, 12.0, 11.0, 13.0, 14.0, 15.0]
for _, avg in stats.moving_average(prices, 2) {
print("window avg: {avg}")
}
EMA with smoothing factor alpha
Returns the EMA where alpha (0–1) controls smoothing. Higher alpha gives more weight to recent values.
use plugin stats::{stats}
let prices = [10.0, 12.0, 11.0, 13.0, 14.0, 15.0]
let ema = stats.exponential_moving_average(prices, 0.3)
Welch's t-test for two samples
Performs Welch's t-test for two independent samples. Returns {t_statistic, degrees_of_freedom}.
use plugin stats::{stats}
let a = [2.0, 3.0, 4.0, 5.0, 6.0]
let b = [3.0, 5.0, 6.0, 7.0, 8.0]
let result = stats.t_test(a, b)
print("t={result["t_statistic"]}, df={result["degrees_of_freedom"]}")
Chi-squared goodness of fit
Computes the chi-squared goodness-of-fit statistic. Returns {statistic, degrees_of_freedom}.
use plugin stats::{stats}
let observed = [18.0, 22.0, 20.0, 15.0, 25.0]
let expected = [20.0, 20.0, 20.0, 20.0, 20.0]
let result = stats.chi_squared_test(observed, expected)
Draw n samples with replacement
Draws n random samples from data with replacement using a deterministic LCG. Useful for bootstrap procedures.
use plugin stats::{stats}
let data = [1.0, 2.0, 3.0, 4.0, 5.0]
let sample = stats.sample_with_replacement(data, 10)
Bootstrap mean with 95% CI
Estimates the mean and 95% confidence interval via bootstrap resampling. Returns {mean, ci_low, ci_high}.
use plugin stats::{stats}
let data = [12.0, 14.0, 11.0, 15.0, 13.0, 16.0]
let result = stats.bootstrap_mean(data, 1000)
print("mean={result["mean"]}, 95% CI [{result["ci_low"]}, {result["ci_high"]}]")
Running total of values
Returns the running total of the dataset. Each value equals the sum of all preceding values including itself.
use plugin stats::{stats}
let daily = [10.0, 5.0, 8.0, 12.0, 3.0]
let running = stats.cumulative_sum(daily)
Ordinal ranks with tie averaging
Assigns ranks to each value, with ties receiving the average rank. Order follows the original dataset position.
use plugin stats::{stats}
let data = [30.0, 10.0, 20.0, 10.0]
let ranks = stats.rank(data)
Mean weighted by a second dataset
Computes the weighted average. Both tables must be the same length and weights must sum to a non-zero value.
use plugin stats::{stats}
let grades = [90.0, 85.0, 78.0]
let weights = [0.5, 0.3, 0.2]
print(stats.weighted_mean(grades, weights))
Nth root of product of all values
Returns the nth root of the product of all values. All values must be positive. Useful for growth rates and ratios.
use plugin stats::{stats}
let growth = [1.1, 1.05, 1.08, 1.12]
print(stats.geometric_mean(growth))
Reciprocal mean
Returns the reciprocal of the mean of reciprocals. All values must be positive. Useful for rates and speeds.
use plugin stats::{stats}
let speeds = [60.0, 80.0, 120.0]
print(stats.harmonic_mean(speeds))
Summary statistics in one call
Returns a comprehensive summary including count, mean, min, max, median, q1, q3, sum, variance, and std_dev in a single call.
use plugin stats::{stats}
let data = [4.0, 7.0, 13.0, 16.0, 21.0, 24.0, 100.0]
let summary = stats.describe(data)
print("mean={summary["mean"]}, median={summary["median"]}, stddev={summary["std_dev"]}")
Standard error of the mean
Returns the standard error of the mean (std_dev / sqrt(n)). Measures how much the sample mean varies from the true mean.
use plugin stats::{stats}
let samples = [5.0, 6.0, 7.0, 8.0, 9.0]
print(stats.standard_error(samples))
Average absolute deviation from mean
Returns the average absolute deviation from the mean. Less sensitive to outliers than standard deviation.
use plugin stats::{stats}
let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]
print(stats.mean_absolute_deviation(data))