Shared statistical primitives
A shared set of statistical primitives used across the product’s training and recall paths: calibration, metrics,
preprocessing and data splits. Every type is a pure function or an immutable value over primitive arrays of double
and int, so it is thread safe and deterministic.
Every expected number in the independent test suite behind these primitives was produced by a from-scratch implementation written directly from each definition, in a different language and with no dependency on the production code, so a shared bug in both implementations is very unlikely. Synthetic test data is generated by the same linear congruential generator implemented in both, so the two independent implementations see identical rows: a 400-row deliberately miscalibrated set, and a 60,000-row population at a 2 percent base rate.
Calibration
Platt scaling fits a Calibrator (Slope, Intercept, an input mode, and an epsilon) such that
p = sigmoid(Slope * x + Intercept), with x either the raw score or the logit of a score already clamped into
(0, 1).
- Targets are Platt’s smoothed values,
(positives + 1)/(positives + 2)and1/(negatives + 2)with class weight sums, so a duplicated row is identical to a single row of weight 2. - Fit by Newton’s method with a small ridge on the Hessian and a backtracking line search, as in Lin, Lin and Weng (2007). Scores are standardised internally for numerical conditioning and the fitted parameters mapped back.
- Rows with a NaN score are dropped. An infinite score, a label other than 0 or 1, a negative or non-finite weight, or a bounded score outside [0, 1] is rejected outright, never silently coerced.
- A single class, a single class with zero total weight, or constant scores are degenerate and rejected; the smoothed targets mean perfectly separable data still converges.
- A negative fitted slope (scores inversely related to the label) is still a valid, strictly monotone calibrator — a caller that requires the calibrator to preserve a particular ranking direction must check for this explicitly.
Prior shift adds the logit offset log(target odds / training odds) to move a calibrated probability from the
training sample’s class balance to a target deployment base rate; both priors must be strictly between 0 and 1, and
probabilities of exactly 0 or 1 are fixed points.
Metrics
Binary classification metrics take parallel score and 0/1 label arrays, dropping any row with a NaN score; a
predicted positive is score >= threshold. The confusion matrix gives accuracy, precision, recall, specificity, F1,
a general F-beta, Matthews correlation coefficient, Cohen’s kappa and expected cost, with undefined ratios (for
example, no predicted positives at all) defined as 0 rather than left to divide by zero.
ROC AUC is computed from the Mann-Whitney statistic on average ranks, so tied scores are handled exactly, with a companion DeLong standard error computed from the same ranks in O(n log n). A single-class sample makes AUC, Gini and average precision undefined (NaN), and makes the ROC and precision-recall curves and the KS statistic meaningless, so those are rejected outright rather than returning a curve with no content. Average precision is the step-wise sum over distinct thresholds. Log loss and the Brier score both accept per-row weights. Expected calibration error uses equal-width probability bins, weighted by count.
Regression metrics: MAE, RMSE, MAPE and sMAPE (both as fractions, with the usual zero-actual edge cases defined explicitly rather than dividing by zero), MASE (scaled by the in-sample seasonal naive error of the training series), and R-squared (undefined when the actuals are constant).
A cost matrix of false-negative and false-positive costs gives the minimum-risk decision threshold — the Bayes decision point on calibrated probabilities — and rejects a cost structure where being wrong does not cost more than being right.
Preprocessing (fit on the training split, reapplied at recall)
Every preprocessing primitive is an immutable record of its fitted primitive parameters, fitted ignoring any NaN or infinite values in the training data (and failing outright if no finite value remains), and leaves NaN as NaN when transforming, so that missing-value imputation stays an explicit, separate step rather than something a scaler does implicitly.
- Standardisation: z-score using the sample standard deviation (n − 1); a zero-variance column maps to 0 rather than dividing by zero.
- Min-max scaling, optionally clipped to the fitted range; a constant column maps to 0.
- Robust scaling: median and a normal-consistent multiple of the median absolute deviation; a zero MAD maps to 0.
- Winsorising: clamping to a fitted lower and upper quantile, by linear-interpolated quantiles.
- Imputation: mean, median, mode (ties going to the smallest value) or a fixed constant, with an optional missing-value indicator column. A value counts as missing if it is NaN or infinite.
Splits
Every split returns index arrays rather than copying data, and every split that involves randomness is seeded.
- Forward-chaining time split: rows sorted by time, divided into equal blocks, each fold training only on data strictly before its block (minus an optional gap), so training time never exceeds test time for any fold.
- Group-aware k-fold and three-way split: groups are shuffled by the seed, then assigned to whichever fold is furthest below its target size, so no group is ever split across folds and fold sizes stay balanced.
- Stratified k-fold: each class is shuffled and dealt round-robin across folds, so per-fold class counts differ by at most one.
