Core machine learning types: the seedable Random generator, Matrix2D linear algebra and activations, matrix reference holders, the NeuralNetwork and CSV-backed MatrixReader. Compile with -lib ml.
CrossValidation
Cross-validation utilities for model evaluation
Operations
Evaluate # function
Runs stratified k-fold cross-validation and reports per-fold scores. The model is refitted on each fold's training split, so it is left holding the last fold's fit. Standardization, when asked for, fits the scaler on the TRAINING split only and reapplies it to the test split -- scaling test data by its own statistics leaks the test distribution and flatters any model measured at a fixed false-alarm rate.
function : Evaluate(model:ScoreModel, X:Float[,], y:Bool[], k:Int, seed:Int, max_fpr:Float, standardize:Bool) ~ CrossValResultParameters
| Name | Type | Description |
|---|---|---|
| model | ScoreModel | anything that fits on Bool labels and scores rows |
| X | Float | rows x features |
| y | Bool | one label per row |
| k | Int | folds |
| seed | Int | seeds the fold assignment, so a run can be repeated |
| max_fpr | Float | the false-alarm budget recall is measured at |
| standardize | Bool | fit a FeatureScaler on each training split |
Return
| Type | Description |
|---|---|
| CrossValResult | per-fold and averaged scores, or Nil on bad input |
Evaluate # function
Cross-validation whose folds are stratified by a key of your choosing. The overload above stratifies by the binary label, which keeps the positive rate steady across folds but says nothing about what the positives are made of. When the positive class is a union of rare sub-populations -- attack families, fault types, device models -- a fold can be balanced on the label and still hold none of a sub-population that only has a few dozen members. Pass those category codes as strata and each fold keeps their proportions too. strata is a fold-assignment key only. The model still fits and scores against y, so the metrics are unchanged.
function : Evaluate(model:ScoreModel, X:Float[,], y:Bool[], k:Int, seed:Int, max_fpr:Float, standardize:Bool, strata:Float[]) ~ CrossValResultParameters
| Name | Type | Description |
|---|---|---|
| model | ScoreModel | anything that fits on Bool labels and scores rows |
| X | Float | rows x features |
| y | Bool | one label per row |
| k | Int | folds |
| seed | Int | seeds the fold assignment, so a run can be repeated |
| max_fpr | Float | the false-alarm budget recall is measured at |
| standardize | Bool | fit a FeatureScaler on each training split |
| strata | Float | one code per row; folds preserve its distribution |
Return
| Type | Description |
|---|---|
| CrossValResult | per-fold scores, averages and pooled out-of-fold scores, or Nil on bad input |
Evaluate # function
Cross-validation with standardization on, which is the usual case.
function : Evaluate(model:ScoreModel, X:Float[,], y:Bool[], k:Int, seed:Int, max_fpr:Float) ~ CrossValResultParameters
| Name | Type | Description |
|---|---|---|
| model | ScoreModel | anything that fits on Bool labels and scores rows |
| X | Float | rows x features |
| y | Bool | one label per row |
| k | Int | folds |
| seed | Int | seeds the fold assignment |
| max_fpr | Float | the false-alarm budget recall is measured at |
Return
| Type | Description |
|---|---|
| CrossValResult | per-fold and averaged scores, or Nil on bad input |
KFold # native
Splits data into K folds for cross-validation
function : native : KFold(data:Float[,], k:Int) ~ Vector[]<IntRef>Parameters
| Name | Type | Description |
|---|---|---|
| data | Float | input matrix |
| k | Int | number of folds |
Return
| Type | Description |
|---|---|
| Vector | array of K fold indices |
Split # function
Builds the train/test matrices for one fold. StratifiedKFold returns row indexes; turning those into matrices is about twenty lines of copying that every experiment otherwise rewrites, and getting it subtly wrong shifts labels against features without any error. Takes ONE fold's row indexes rather than the whole array plus an index: a `Vector[]
function : Split(X:Float[,], y:Bool[], test_rows:Vector<IntRef>) ~ FoldSplitParameters
| Name | Type | Description |
|---|---|---|
| X | Float | rows x features |
| y | Bool | one label per row |
| test_rows | Vector<IntRef> | row indexes for the test split, i.e. folds[i] |
Return
| Type | Description |
|---|---|
| FoldSplit | the split, or Nil on bad input |
StratifiedKFold # function
Splits row indices into K folds that each keep the class ratio of the whole, shuffled from a caller-supplied seed so the same seed gives the same folds. KFold above shuffles with the global generator and ignores labels. Both hurt on imbalanced data: an unseeded split cannot be reproduced, and an unstratified split lets the rare class land unevenly, so a fold may hold too few positives to measure anything at a low false-positive rate. Intrusion-detection sets are exactly that shape. Classes are taken from the label values as they first appear. Each class is shuffled independently and dealt round-robin across the folds, continuing from where the previous class stopped, so a remainder cannot pile into fold 0.
function : StratifiedKFold(labels:Float[], k:Int, seed:Int) ~ Vector[]<IntRef>Parameters
| Name | Type | Description |
|---|---|---|
| labels | Float | one label per row; only the labels are needed to stratify |
| k | Int | number of folds, at least 2 |
| seed | Int | shuffle seed; the same seed reproduces the same folds |
Return
| Type | Description |
|---|---|
| Vector | k vectors of row indices, or Nil on bad input |
Example
folds := CrossValidation->StratifiedKFold(y, 5, 42);
each(f : folds) {
test_rows := folds[f];
};ToBool # function
Converts scored labels to the Bool[] the classifiers and Metrics take. TableEncoder hands back Float[] and StratifiedKFold wants that form, but every classifier Fit and every Metrics function takes Bool[]. Without this, each caller keeps both representations alive and writes the same conversion loop.
function : ToBool(labels:Float[]) ~ Bool[]Parameters
| Name | Type | Description |
|---|---|---|
| labels | Float | one value per row; anything above 0.5 is the positive class |
Return
| Type | Description |
|---|---|
| Bool | one Bool per row, or Nil for Nil input |
ToFloat # function
Converts Bool labels to the Float[] StratifiedKFold takes.
function : ToFloat(labels:Bool[]) ~ Float[]Parameters
| Name | Type | Description |
|---|---|---|
| labels | Bool | one label per row |
Return
| Type | Description |
|---|---|
| Float | 1.0 for true and 0.0 for false, or Nil for Nil input |
TrainTestSplit # native
Splits data into training and test sets
function : native : TrainTestSplit(data:Float[,], test_ratio:Float) ~ FloatMatrixRef[]Parameters
| Name | Type | Description |
|---|---|---|
| data | Float | input matrix |
| test_ratio | Float | percentage of data for testing (0.0 to 1.0) |
Return
| Type | Description |
|---|---|
| FloatMatrixRef | array with [training_data, test_data] |