Skip to content

deepbox/preprocess

Splitting & Cross-Validation

Train-test splitting and cross-validation splitters, including grouped, stratified, repeated and time-series strategies.

  • Model validation

Overview

  • trainTestSplit(X, y, options) returns [XTrain, XTest, yTrain, yTest]. testSize defaults to 0.25 and shuffle to true. Without randomState the split changes on every call. stratify keeps class proportions and needs at least 2 samples per class.
  • Splitters (KFold, StratifiedKFold, GroupKFold, TimeSeriesSplit and others) have split(X, y?, groups?), which returns an array of { trainIndex, testIndex } rather than a generator, and getNSplits(). KFold defaults to nSplits: 5 and no shuffling.
  • To cross-validate an estimator, use crossValScore, crossValidate or GridSearchCV from deepbox/ml. They take a fold count, not a splitter object.
  • Rows are taken along the first axis, so X may have more than two dimensions.

Types

1

SplitResult

type

A single train/test split expressed as sample index arrays.

  • readonly trainIndex: number[]
  • readonly testIndex: number[]

Classes

15

GroupKFold

Group K-Fold cross-validator.

Guarantees that no group appears in both the train and the test set of a split. Without shuffling, groups are assigned largest first to the fold that currently holds the fewest samples (the same greedy rule as scikit-learn), so fold sizes stay as balanced as the group sizes allow. With shuffle, the groups are permuted and cut into nSplits chunks of nearly equal group count. Train and test indices are returned in ascending order.

Example
import { GroupKFold } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const gkf = new GroupKFold({ nSplits: 2 });const X = tensor([[1], [2], [3], [4]]);const splits = gkf.split(X, undefined, tensor([0, 0, 1, 1]));
Members (3)
  • constructor(options?: { nSplits?: number; shuffle?: boolean; randomState?: number; })
  • split(X: Tensor, _y: Tensor | undefined, groups: Tensor | readonly Label[]): SplitResult[]

    Generate train/test indices for every fold.

  • getNSplits(): number

    Number of folds.

GroupShuffleSplit

Shuffle-Group(s)-Out cross-validation iterator.

Provides randomized train/test indices to split data by groups. Ensures that the same group is not in both test and train sets. testSize and trainSize count groups, not samples: fractions are taken of the number of distinct groups, integers are absolute group counts. With neither given, 20% of the groups form the test set. Train and test indices are returned in ascending order. Iteration i shuffles with a seed derived from randomState and i (a hash, so that neighbouring seeds do not share iterations).

Example
import { GroupShuffleSplit } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const gss = new GroupShuffleSplit({ nSplits: 5, testSize: 0.2, randomState: 42 });const X = tensor([[1], [2], [3], [4], [5], [6]]);const splits = gss.split(X, undefined, [0, 0, 1, 1, 2, 2]);
Members (3)
  • constructor(options?: { nSplits?: number; testSize?: number; trainSize?: number; randomState?: number; })
  • split(X: Tensor, _y?: Tensor, groups?: Tensor | readonly Label[]): SplitResult[]

    Generate train/test split indices based on groups.

  • getNSplits(): number

    Number of re-shuffling iterations.

KFold

K-Folds cross-validator.

Splits the samples into nSplits consecutive folds (the first n % nSplits folds hold one extra sample). Each fold is used once as the test set while the remaining folds form the train set. Train and test indices are always returned in ascending order, also when shuffle is enabled.

Example
import { KFold } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const kf = new KFold({ nSplits: 2 });const splits = kf.split(tensor([[1], [2], [3], [4]]));// splits[0]: train=[2,3], test=[0,1]
Members (3)
  • constructor(options?: { nSplits?: number; shuffle?: boolean; randomState?: number; })
  • split(X: Tensor): SplitResult[]

    Generate train/test indices for every fold.

  • getNSplits(): number

    Number of folds.

LeaveOneGroupOut

Leave-One-Group-Out cross-validator.

Each distinct group is used once as the test set, in ascending order of the group labels, and the other groups form the train set. At least two groups are required. Train and test indices are returned in ascending order.

Example
import { LeaveOneGroupOut } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const X = tensor([[1], [2], [3], [4]]);const splits = new LeaveOneGroupOut().split(X, undefined, tensor([0, 0, 1, 2]));// 3 splits: test=[0,1], test=[2], test=[3]
Members (2)
  • split(X: Tensor, _y: Tensor | undefined, groups: Tensor | readonly Label[]): SplitResult[]

    Generate one split per group.

  • getNSplits(groups: Tensor | readonly Label[]): number

    Number of splits, which equals the number of distinct groups.

LeaveOneOut

Leave-One-Out cross-validator.

Each sample is used once as a test set of size one. This materialises n * (n - 1) train indices, so very large n is rejected with a MemoryError.

Example
import { LeaveOneOut } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const splits = new LeaveOneOut().split(tensor([[1], [2], [3]]));// 3 splits, each with one test index
Members (2)
  • split(X: Tensor): SplitResult[]

    Generate one split per sample.

  • getNSplits(X: Tensor): number

    Number of splits, which equals the number of samples.

LeavePGroupsOut

Leave-P-Groups-Out cross-validator.

Every combination of nGroups distinct groups is used once as the test set, in lexicographic order of the ascending group labels. The number of splits is C(g, nGroups) for g distinct groups, so the splits are only materialised when they number at most 100,000 and their indices fit a memory budget. Train and test indices are returned in ascending order.

Example
import { LeavePGroupsOut } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const X = tensor([[1], [2], [3], [4], [5]]);const splits = new LeavePGroupsOut(2).split(X, undefined, tensor([0, 0, 1, 1, 2]));// C(3, 2) = 3 splits
Members (3)
  • constructor(nGroups: number)
  • split(X: Tensor, _y: Tensor | undefined, groups: Tensor | readonly Label[]): SplitResult[]

    Generate train/test indices for every combination of nGroups test groups.

  • getNSplits(groups: Tensor | readonly Label[]): number

    Number of splits, C(g, nGroups) for g distinct groups.

LeavePOut

Leave-P-Out cross-validator.

Every combination of p samples is used once as the test set. The number of splits is C(n, p), so the splits are only materialised when they number at most 100,000 and their indices fit a memory budget.

Example
import { LeavePOut } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const lpo = new LeavePOut(2);const splits = lpo.split(tensor([[1], [2], [3], [4]])); // C(4, 2) = 6 splits
Members (3)
  • constructor(p: number)
  • split(X: Tensor): SplitResult[]

    Generate train/test indices for every combination of p test samples, in lexicographic order of the test indices.

  • getNSplits(X: Tensor): number

    Number of splits, C(n, p).

PredefinedSplit

Predefined split cross-validator.

testFold[i] names the fold in which sample i is a test sample. Samples with testFold[i] === -1 are never part of a test set (they are always in the train set). One split is produced for each distinct fold value other than -1, in ascending order.

Example
import { PredefinedSplit } from 'deepbox/preprocess'; const ps = new PredefinedSplit([0, 0, 1, 1, -1]);const splits = ps.split();// Split 0: test=[0,1], train=[2,3,4]// Split 1: test=[2,3], train=[0,1,4]
Members (3)
  • constructor(testFold: Tensor | readonly number[])
  • split(X?: Tensor): SplitResult[]

    Generate one split per distinct fold value other than -1.

  • getNSplits(): number

    Number of splits, the number of distinct fold values other than -1.

RepeatedKFold

Repeated K-Fold cross-validator.

Repeats K-Fold nRepeats times with different shuffling in each repetition. With a randomState, repetition r shuffles with a seed derived from randomState and r (a hash, so that neighbouring seeds do not share repetitions).

Example
import { RepeatedKFold } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const rkf = new RepeatedKFold({ nSplits: 5, nRepeats: 3 });const X = tensor([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]);const splits = rkf.split(X); // 15 splits (5 folds × 3 repeats)
Members (3)
  • constructor(options?: { nSplits?: number; nRepeats?: number; randomState?: number; })
  • split(X: Tensor): SplitResult[]

    Generate nSplits * nRepeats splits, repetition by repetition.

  • getNSplits(): number

    Total number of splits, nSplits * nRepeats.

RepeatedStratifiedKFold

Repeated Stratified K-Fold cross-validator.

Repeats Stratified K-Fold nRepeats times with different shuffling. With a randomState, repetition r shuffles with a seed derived from randomState and r (a hash, so that neighbouring seeds do not share repetitions).

Example
import { RepeatedStratifiedKFold } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const rskf = new RepeatedStratifiedKFold({ nSplits: 2, nRepeats: 3, randomState: 0 });const splits = rskf.split(tensor([[1], [2], [3], [4]]), tensor([0, 0, 1, 1]));
Members (3)
  • constructor(options?: { nSplits?: number; nRepeats?: number; randomState?: number; })
  • split(X: Tensor, y: Tensor): SplitResult[]

    Generate nSplits * nRepeats stratified splits, repetition by repetition.

  • getNSplits(): number

    Total number of splits, nSplits * nRepeats.

ShuffleSplit

Random permutation cross-validator.

Yields indices to split data into train and test sets using random permutations. Unlike KFold, ShuffleSplit allows controlling the train/test size independently and produces overlapping test sets across iterations. With neither trainSize nor testSize given, the test set gets 10% of the samples (scikit-learn's default for this splitter). Iteration i shuffles with a seed derived from randomState and i (a hash, so that neighbouring seeds do not share iterations).

Example
import { ShuffleSplit } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const ss = new ShuffleSplit({ nSplits: 5, testSize: 0.2, randomState: 42 });const X = tensor([[1,2],[3,4],[5,6],[7,8],[9,10]]);const splits = ss.split(X);
Members (3)
  • constructor(options?: { nSplits?: number; testSize?: number; trainSize?: number; randomState?: number; })
  • split(X: Tensor): SplitResult[]

    Generate nSplits random train/test splits.

  • getNSplits(): number

    Number of re-shuffling iterations.

StratifiedGroupKFold

Stratified Group K-Fold cross-validator.

Keeps every group in a single fold (like GroupKFold) while trying to keep the class distribution of each fold close to the overall one (like StratifiedKFold). Without shuffling it follows scikit-learn's greedy algorithm: groups are visited from the most to the least unevenly distributed over classes and each goes to the fold whose class proportions end up most even, ties going to the fold with fewer samples. The result is deterministic and matches scikit-learn. With shuffle, the groups are visited in a random order before that sort, so equally uneven groups are placed in a seeded random order (scikit-learn's shuffled folds depend on NumPy's generator and are not reproduced). Train and test indices are returned in ascending order.

Example
import { StratifiedGroupKFold } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const X = tensor([[1], [2], [3], [4], [5], [6]]);const y = tensor([0, 0, 1, 1, 0, 1]);const groups = tensor([0, 0, 1, 1, 2, 3]);const splits = new StratifiedGroupKFold({ nSplits: 2 }).split(X, y, groups);
Members (3)
  • constructor(options?: { nSplits?: number; shuffle?: boolean; randomState?: number; })
  • split(X: Tensor, y: Tensor, groups: Tensor | readonly Label[]): SplitResult[]

    Generate train/test indices for every fold.

  • getNSplits(): number

    Number of folds.

StratifiedKFold

Stratified K-Folds cross-validator.

Every fold keeps (as closely as possible) the class proportions of the full data set, and fold sizes differ by at most one sample. Without shuffling the assignment is identical to scikit-learn's StratifiedKFold. Each class must have at least nSplits samples. Train and test indices are returned in ascending order.

Example
import { StratifiedKFold } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const skf = new StratifiedKFold({ nSplits: 2 });const splits = skf.split(tensor([[1], [2], [3], [4]]), tensor([0, 0, 1, 1]));
Members (3)
  • constructor(options?: { nSplits?: number; shuffle?: boolean; randomState?: number; })
  • split(X: Tensor, y: Tensor): SplitResult[]

    Generate stratified train/test indices for every fold.

  • getNSplits(): number

    Number of folds.

StratifiedShuffleSplit

Stratified ShuffleSplit cross-validator.

Provides train/test indices that preserve the percentage of samples for each class. Like ShuffleSplit but with stratification: every split contains exactly the requested number of train and test samples, divided among the classes by largest remainder rounding. Every class needs at least 2 samples, and both sets must be at least as large as the number of classes. With neither trainSize nor testSize given, the test set gets 10% of the samples. Iteration i shuffles with a seed derived from randomState and i (a hash, so that neighbouring seeds do not share iterations).

Example
import { StratifiedShuffleSplit } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const sss = new StratifiedShuffleSplit({ nSplits: 5, testSize: 0.2, randomState: 42 });const X = tensor([[1],[2],[3],[4],[5],[6],[7],[8],[9],[10]]);const y = tensor([0,0,0,0,0,1,1,1,1,1]);const splits = sss.split(X, y);
Members (3)
  • constructor(options?: { nSplits?: number; testSize?: number; trainSize?: number; randomState?: number; })
  • split(X: Tensor, y: Tensor): SplitResult[]

    Generate nSplits stratified random train/test splits.

  • getNSplits(): number

    Number of re-shuffling iterations.

TimeSeriesSplit

Time Series cross-validator.

Provides train/test indices for time series data. In each split, test indices must be higher than before, and thus shuffling in cross validator is inappropriate. The test sets are the last nSplits blocks of testSize samples; each train set is everything before its test block, minus gap samples, optionally capped to the most recent maxTrainSize samples.

Example
import { TimeSeriesSplit } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const tscv = new TimeSeriesSplit({ nSplits: 3 });const X = tensor([[1], [2], [3], [4], [5], [6]]);const splits = tscv.split(X);// Split 0: train=[0,1,2], test=[3]// Split 1: train=[0,1,2,3], test=[4]// Split 2: train=[0,1,2,3,4], test=[5]
Members (3)
  • constructor(options?: { nSplits?: number; maxTrainSize?: number; testSize?: number; gap?: number; })
  • split(X: Tensor): SplitResult[]

    Generate the forward-chaining splits, oldest first.

  • getNSplits(): number

    Number of splits.

Functions

1

trainTestSplit

function trainTestSplit(X: Tensor, y?: Tensor, options?: { testSize?: number; trainSize?: number; randomState?: number; shuffle?: boolean; stratify?: Tensor; }): Tensor[];

Split arrays into random train and test subsets.

Details

X and y may have any number of dimensions (at least one); rows are taken along the first axis. Inputs are never modified. Sizes follow scikit-learn: with neither trainSize nor testSize given, the test set gets 25% of the samples; fractions round the test size up and the train size down.

With stratify, each class contributes to the train and test sets in proportion to its size (largest remainder rounding, so the requested sizes are matched exactly). Every class needs at least 2 samples, and both the train and the test set must be at least as large as the number of classes.

Parameters

X
Tensor
Data tensor; rows are samples (shape [nSamples, ...])
yoptional
Tensor
Optional targets with the same number of rows as X
optionsoptional
{ testSize?: number; trainSize?: number; randomState?: number; shuffle?: boolean; stratify?: Tensor; }
Split configuration options

Returns

Tensor[][XTrain, XTest], or [XTrain, XTest, yTrain, yTest] when y is given

Throws

  • InvalidParameterErrorIf sizes are invalid, X is empty, or lengths disagree
  • ShapeErrorIf X is 0-d or stratify is not 1D
Example
import { trainTestSplit } from 'deepbox/preprocess';import { tensor } from 'deepbox/ndarray'; const X = tensor([[1, 2], [3, 4], [5, 6], [7, 8]]);const y = tensor([0, 1, 0, 1]);const [XTrain, XTest, yTrain, yTest] = trainTestSplit(X, y, { testSize: 0.25 });
preprocess-splitting.ts
import {  KFold,  StratifiedKFold,  TimeSeriesSplit,  trainTestSplit,} from "deepbox/preprocess";import { tensor } from "deepbox/ndarray"; const X = tensor([[1], [2], [3], [4], [5], [6]]);const y = tensor([0, 0, 1, 1, 0, 1]); const [XTrain, XTest, yTrain, yTest] = trainTestSplit(X, y, {  testSize: 0.33,  randomState: 42,  stratify: y,});console.log(XTrain.shape, XTest.shape, yTrain.shape, yTest.shape); console.log(new KFold({ nSplits: 3 }).split(X));console.log(new StratifiedKFold({ nSplits: 3 }).split(X, y));console.log(new TimeSeriesSplit({ nSplits: 3 }).split(X));