Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

train_test_split / StratifiedKFold

API Reference

Signature

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=None, stratify=False
)

kf = sp.StratifiedKFold(n_splits=5, shuffle=True, random_state=None)

for train_idx, test_idx in kf.split(X, y):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    ...

Parameters — train_test_split

ParameterTypeDefaultDescription
Xndarray (n, p)Feature matrix
ylist | ndarrayTarget vector
test_sizefloat0.2Fraction of samples to hold out
random_stateint | NoneNoneSeed for reproducibility
stratifyboolFalsePreserve class proportions in each split

Constructor parameters — StratifiedKFold

ParameterTypeDefaultDescription
n_splitsint5Number of folds $k$
shuffleboolTrueShuffle data before splitting
random_stateint | NoneNoneSeed for reproducibility

Returns — train_test_split

Return valueTypeDescription
X_trainndarrayTraining features
X_testndarrayTest features
y_trainlistTraining labels
y_testlistTest labels
Example
import seraplot as sp
import numpy as np

X = np.random.randn(500, 6)
y = (X[:, 0] + X[:, 1] > 0).astype(int)

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=True
)
print(f"Train: {len(y_train)}, Test: {len(y_test)}")

kf = sp.StratifiedKFold(n_splits=5, random_state=0)
for fold, (tr, te) in enumerate(kf.split(X, y)):
    clf = sp.LogisticRegression()
    clf.fit(X[tr], np.array(y)[tr].tolist())
    print(f"Fold {fold}: {clf.score(X[te], np.array(y)[te].tolist()):.4f}")

Algorithmic Functioning


train_test_split

Non-stratified split — randomly shuffle indices and cut at position $\lfloor n \cdot (1 - \texttt{test_size})\rfloor$:

$$\text{train} = \sigma([0,n))[:n_{\text{tr}}], \qquad \text{test} = \sigma([0,n))[n_{\text{tr}}:]$$

where $\sigma$ is a random permutation seeded by random_state.

Stratified split — class proportions are preserved by splitting each class independently:

$$\forall k:\quad n_{\text{test},k} = \text{round}(n_k \cdot \texttt{test\_size})$$

then combining and shuffling all per-class test/train sets. This ensures that rare classes are not accidentally excluded from the test set.


StratifiedKFold

Splits the dataset into $k$ non-overlapping folds whilst preserving class distributions in each fold.

Algorithm:

1. For each class $c$, collect its indices $\mathcal{I}_c = {i : y_i = c}$.

2. Optionally shuffle $\mathcal{I}_c$ with random_state.

3. Divide $\mathcal{I}_c$ into $k$ roughly equal sub-arrays of size $\lfloor|\mathcal{I}_c|/k\rfloor$ or $\lceil|\mathcal{I}_c|/k\rceil$.

4. For fold $f \in {0,\ldots,k-1}$: the test set is $\bigcup_c \mathcal{I}_c[f]$ and the train set is its complement.

The $f$-th fold test error estimate $\hat{e}_f$ gives the cross-validated score:

$$\widehat{\text{CV}} = \frac{1}{k}\sum_{f=0}^{k-1} \hat{e}_f$$

This estimate has lower variance than a single train/test split, especially for small datasets.

Référence API

Signature

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=None, stratify=False
)

kf = sp.StratifiedKFold(n_splits=5, shuffle=True, random_state=None)

for train_idx, test_idx in kf.split(X, y):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    ...

Paramètres — train_test_split

ParamètreTypeDéfautDescription
Xndarray (n, p)Matrice de features
ylist | ndarrayVecteur cible
test_sizefloat0.2Fraction des échantillons à mettre de côté
random_stateint | NoneNoneGraine pour la reproductibilité
stratifyboolFalsePréserver les proportions de classes dans chaque partition

Paramètres du constructeur — StratifiedKFold

ParamètreTypeDéfautDescription
n_splitsint5Nombre de plis $k$
shuffleboolTrueMélanger les données avant de diviser
random_stateint | NoneNoneGraine pour la reproductibilité

Valeurs de retour — train_test_split

Valeur de retourTypeDescription
X_trainndarrayFeatures d'entraînement
X_testndarrayFeatures de test
y_trainlistÉtiquettes d'entraînement
y_testlistÉtiquettes de test
Exemple
import seraplot as sp
import numpy as np

X = np.random.randn(500, 6)
y = (X[:, 0] + X[:, 1] > 0).astype(int)

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=True
)
print(f"Train : {len(y_train)}, Test : {len(y_test)}")

kf = sp.StratifiedKFold(n_splits=5, random_state=0)
for pli, (tr, te) in enumerate(kf.split(X, y)):
    clf = sp.LogisticRegression()
    clf.fit(X[tr], np.array(y)[tr].tolist())
    print(f"Pli {pli} : {clf.score(X[te], np.array(y)[te].tolist()):.4f}")

Fonctionnement algorithmique


train_test_split

Division non stratifiée — mélange aléatoire des indices et coupe à la position $\lfloor n \cdot (1 - \texttt{test_size})\rfloor$ :

$$\text{train} = \sigma([0,n))[:n_{\text{tr}}], \qquad \text{test} = \sigma([0,n))[n_{\text{tr}}:]$$

où $\sigma$ est une permutation aléatoire initialisée par random_state.

Division stratifiée — les proportions de classes sont préservées en divisant chaque classe indépendamment :

$$\forall k:\quad n_{\text{test},k} = \text{round}(n_k \cdot \texttt{test\_size})$$

puis en combinant et mélangeant tous les ensembles test/train par classe. Cela garantit que les classes rares ne sont pas accidentellement exclues de l'ensemble de test.


StratifiedKFold

Divise le jeu de données en $k$ plis non-chevauchants tout en préservant les distributions de classes dans chaque pli.

Algorithme :

1. Pour chaque classe $c$, collecter ses indices $\mathcal{I}_c = {i : y_i = c}$.

2. Optionnellement mélanger $\mathcal{I}_c$ avec random_state.

3. Diviser $\mathcal{I}_c$ en $k$ sous-tableaux approximativement égaux de taille $\lfloor|\mathcal{I}_c|/k\rfloor$ ou $\lceil|\mathcal{I}_c|/k\rceil$.

4. Pour le pli $f \in {0,\ldots,k-1}$ : l'ensemble de test est $\bigcup_c \mathcal{I}_c[f]$ et l'ensemble d'entraînement est son complément.

L'estimation d'erreur du $f$-ième pli $\hat{e}_f$ donne le score de validation croisée :

$$\widehat{\text{VC}} = \frac{1}{k}\sum_{f=0}^{k-1} \hat{e}_f$$

Cette estimation a une variance plus faible qu'une seule division train/test, notamment pour les petits jeux de données.