Machine Learning Academy · Les

train_test_split: verhoudingen, seeds en stratificatie

U gebruikt sklearn's train_test_split met verschillende testgroottes, stelt random seeds in voor reproduceerbaarheid en past stratificatie toe voor gebalanceerde splitsingen.

Les 2 van 412 stappen

train_test_split: verhoudingen, seeds en stratificatie is een gratis Machine Learning Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Machine Learning Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Machine Learning Academy bevat in totaal 4 lessen.

De functie train_test_split

De functie train_test_split() van scikit-learn is het standaardhulpmiddel om datasets op te delen in trainings- en testsubsets. De functie husselt de gegevens willekeurig en wijst het opgegeven aandeel toe aan de testset. Vervolgens retourneert de functie vier arrays: X_train, X_test, y_train, y_test.

Het is belangrijk om de parameters volledig te begrijpen, omdat slechte keuzes bij het splitsen de betrouwbaarheid van alle daaropvolgende evaluaties kunnen aantasten. Een te kleine testset levert ruisachtige schattingen op; een te grote testset verspilt trainingsgegevens. De juiste keuze hangt af van de omvang van je dataset en van de variantie die je in de prestatieschattingen kunt accepteren.

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
import numpy as np

X, y = load_breast_cancer(return_X_y=True)

X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.20,     # 20% of data goes to test set
    random_state=42,    # reproducible random shuffle
    shuffle=True,       # default: shuffle before splitting
    stratify=y          # preserve class proportions
)

print(f'Training size: {X_train.shape}')
print(f'Test size:     {X_test.shape}')

De verhouding van de testgrootte kiezen

De parameter test_size accepteert een kommagetal (aandeel) of een geheel getal (absoluut aantal):

  • Grote datasets (>100k voorbeelden): gebruik 10–15% voor de testset (er zijn genoeg trainingsgegevens; een grote testset levert zeer stabiele schattingen op).
  • Middelgrote datasets (1k–100k): 20–30% voor de testset is gebruikelijk (splitsingen van 80/20 of 70/30).
  • Kleine datasets (<1k): overweeg kruisvalidatie in plaats van één splitsing, omdat een vaste splitsing toevallig ongunstig kan uitvallen.

Er bestaat geen verhouding die altijd juist is. Het doel is om genoeg testvoorbeelden te hebben voor een statistisch stabiele prestatieschatting en tegelijk genoeg trainingsgegevens over te houden zodat het model goed kan leren.

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
import numpy as np

X, y = load_breast_cancer(return_X_y=True)

# Compare different test sizes
for test_size in [0.1, 0.2, 0.3, 0.4]:
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=42)
    model = LogisticRegression(max_iter=1000)
    model.fit(X_train, y_train)
    acc = model.score(X_test, y_test)
    print(f'test_size={test_size}: train={len(X_train)}, test={len(X_test)}, acc={acc:.3f}')

Willekeurige zaden voor reproduceerbaarheid

De parameter random_state initialiseert de generator voor willekeurige getallen die de gegevens vóór het splitsen husselt. Met hetzelfde zaad is de splitsing elke keer identiek. Zonder zaad verandert de splitsing bij elke uitvoering.

Reproduceerbaarheid is belangrijk voor het eerlijk vergelijken van modellen (dezelfde splitsing voor alle modellen), het delen van code met collega's, het opsporen van fouten (elke keer dezelfde gegevens) en wetenschappelijke publicaties (resultaten kunnen worden gecontroleerd). Gebruik voor alle experimenten een vast zaad, maar probeer twee of drie verschillende zaden om te bevestigen dat je model niet toevallig voordeel of nadeel ondervindt van één gunstige splitsing.

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer

X, y = load_breast_cancer(return_X_y=True)

# Test variance across random seeds
results = []
for seed in [0, 1, 42, 123, 999]:
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=seed
    )
    model = LogisticRegression(max_iter=1000)
    model.fit(X_train, y_train)
    acc = model.score(X_test, y_test)
    results.append(acc)
    print(f'seed={seed}: accuracy={acc:.4f}')

import numpy as np
print(f'\nMean: {np.mean(results):.4f}  Std: {np.std(results):.4f}')

Het probleem zonder stratificatie

Zonder stratificatie kan een willekeurige splitsing een testset opleveren waarvan de klassenaandelen sterk afwijken van die in de volledige dataset. Als je dataset voor 90% uit klasse 0 en voor 10% uit klasse 1 bestaat, kan een willekeurige splitsing toevallig een testset opleveren met slechts 3% klasse 1.

Dit is belangrijk omdat prestatiemetrieken die zijn berekend op een atypische klassendistributie geen representatief beeld geven van de prestaties in productie. Een model kan perfect scoren op een testset die bijna geen voorbeelden van de minderheidsklasse bevat, waardoor je ten onrechte vertrouwen krijgt in een model dat in werkelijkheid slecht presteert op de positieve klasse.

from sklearn.model_selection import train_test_split
import numpy as np

# Imbalanced dataset: 90% class 0, 10% class 1
np.random.seed(0)
n = 1000
y_imb = np.array([0]*900 + [1]*100)

results = []
for seed in range(10):
    _, _, y_train, y_test = train_test_split(y_imb, y_imb, test_size=0.2, random_state=seed)
    results.append(y_test.mean())
    print(f'seed={seed}: test positive rate = {y_test.mean():.3f} (expected: 0.100)')

print(f'\nMin: {min(results):.3f}  Max: {max(results):.3f}')

Stratificatie: klassenaandelen behouden

Met stratify=y zorg je ervoor dat zowel de trainings- als de testset hetzelfde aandeel van elke klasse bevatten als de volledige dataset. Dit is essentieel voor classificatieproblemen met een ongelijke klassendistributie en moet standaard worden gebruikt wanneer je een classificatiedoelvariabele hebt.

Stratificatie werkt door elke klasse afzonderlijk te splitsen en de resultaten daarna te combineren: als je dataset voor 90% uit klasse 0 en voor 10% uit klasse 1 bestaat, hebben zowel de trainingsset als de testset ongeveer dezelfde verhouding van 90%/10%. Hierdoor worden prestatieschattingen op de testset veel stabieler en representatiever.

from sklearn.model_selection import train_test_split
import numpy as np

np.random.seed(0)
n = 1000
y_imb = np.array([0]*900 + [1]*100)
X_imb = np.random.randn(n, 5)

# Without stratification
_, _, y_train_no, y_test_no = train_test_split(X_imb, y_imb, test_size=0.2, random_state=42)
print(f'Without stratify: test positive rate = {y_test_no.mean():.3f}')

# With stratification
_, _, y_train_s, y_test_s = train_test_split(X_imb, y_imb, test_size=0.2, random_state=42, stratify=y_imb)
print(f'With stratify:    test positive rate = {y_test_s.mean():.3f}  (exactly 0.100)')

Stratificatie bij problemen met meerdere klassen

Stratificatie werkt ook goed voor doelvariabelen met meerdere klassen. Wanneer je stratify=y doorgeeft met een y met meerdere klassen, zorgt scikit-learn ervoor dat alle klassen in beide splitsingen in dezelfde verhoudingen vertegenwoordigd zijn.

Dit is vooral belangrijk voor zeldzame klassen. Als klasse C in slechts 2% van de voorbeelden voorkomt en je een dataset met 500 voorbeelden hebt, kan een willekeurige splitsing alle 10 voorbeelden van klasse C in de trainingsset plaatsen en geen enkel voorbeeld in de testset — waardoor de testset onbruikbaar wordt om de prestaties voor klasse C te evalueren. Stratificatie voorkomt dit.

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
import numpy as np

X, y = load_iris(return_X_y=True)  # 3 balanced classes

# Stratified split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)

# Verify class proportions are preserved
for cls in [0, 1, 2]:
    full_ratio = (y == cls).mean()
    train_ratio = (y_train == cls).mean()
    test_ratio = (y_test == cls).mean()
    print(f'Class {cls}: full={full_ratio:.2f} train={train_ratio:.2f} test={test_ratio:.2f}')

Husselen: waarom de volgorde belangrijk is

Standaard husselt shuffle=True de gegevens willekeurig voordat ze worden gesplitst. Dit is cruciaal omdat echte datasets vaak niet in willekeurige volgorde staan — ze kunnen bijvoorbeeld op datum, gebruikers-ID of label zijn gesorteerd. Zonder husselen zou de testset alleen de laatste voorbeelden van de dataset bevatten, die systematisch kunnen verschillen van eerdere voorbeelden.

De uitzondering is tijdreeksdata, waarbij je NIET mag husselen. Bij gegevens die op tijd zijn geordend, moet de testset uit de toekomst komen ten opzichte van de trainingsgegevens. Met shuffle=False behoud je de tijdsvolgorde. De TimeSeriesSplit van scikit-learn biedt geavanceerdere kruisvalidatie met tijdsvolgorde.

from sklearn.model_selection import train_test_split
import numpy as np

# Time-series data: ordered by date
dates = np.arange(1000)           # day 0 to 999
sales = dates * 0.5 + np.random.randn(1000) * 10

# WRONG for time series: shuffling leaks future data into training
X_train_wrong, X_test_wrong, _, _ = train_test_split(dates.reshape(-1,1), sales, shuffle=True)
print(f'Wrong: test date range = {X_test_wrong.min():.0f} to {X_test_wrong.max():.0f}')

# CORRECT for time series: last 20% of time is the test set
X_train_right, X_test_right, _, _ = train_test_split(dates.reshape(-1,1), sales, shuffle=False)
print(f'Right: test date range = {X_test_right.min():.0f} to {X_test_right.max():.0f}')

Meerdere arrays consistent splitsen

Vaak moet je meerdere arrays tegelijk splitsen — bijvoorbeeld X-kenmerken, y-labels en een afzonderlijke ID-array — terwijl je ervoor zorgt dat dezelfde indices uitgelijnd blijven. train_test_split accepteert een willekeurig aantal arrays als positionele argumenten en past dezelfde husseling en splitsing op alle arrays toe.

Op deze manier splits je ook vooraf verwerkte kenmerkmatrices samen met oorspronkelijke DataFrames als je wilt bijhouden welke oorspronkelijke rijen in welke splitsing terechtkwamen voor foutanalyse.

from sklearn.model_selection import train_test_split
import numpy as np

# Multiple arrays with same sample dimension
X = np.random.randn(100, 5)
y = np.random.randint(0, 2, 100)
sample_ids = np.arange(100)  # e.g., customer IDs

# Split all three together
X_train, X_test, y_train, y_test, ids_train, ids_test = train_test_split(
    X, y, sample_ids,
    test_size=0.2,
    random_state=42
)

print('Train IDs sample:', ids_train[:5])
print('Test IDs sample:', ids_test[:5])
print('All arrays remain aligned.')

Wanneer je in plaats daarvan kruisvalidatie gebruikt

Een enkele splitsing in training en test heeft een hoge variantie — de exacte splitsing kan prestatieschattingen opleveren die meerdere procentpunten uiteenlopen. Kruisvalidatie neemt het gemiddelde van de prestaties over meerdere splitsingen, wat een stabielere en betrouwbaardere schatting oplevert.

Gebruik kruisvalidatie (niet één enkele splitsing) wanneer:

  • je dataset klein is (minder dan enkele duizenden voorbeelden);
  • je een betrouwbare schatting met lage variantie wilt;
  • je modellen vergelijkt of hyperparameters afstemt.

Gebruik één enkele splitsing wanneer je zeer grote datasets hebt waarvoor kruisvalidatie te veel rekentijd zou kosten.

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
import numpy as np

X, y = load_breast_cancer(return_X_y=True)

# 5-fold cross-validation (more reliable than single split)
scores = cross_val_score(
    LogisticRegression(max_iter=1000),
    X, y,
    cv=5,
    scoring='accuracy'
)

print('CV scores:', scores.round(4))
print(f'Mean: {scores.mean():.4f}  Std: {scores.std():.4f}')
# Much more stable estimate than any single split

Volledige evaluatiewerkstroom

De volledige evaluatiewerkstroom die alle valkuilen uit deze les vermijdt:

  1. Splits 20% af als definitieve testset (gestratificeerd, met ingesteld willekeurig zaad).
  2. Gebruik de resterende 80% voor alle ontwikkeling (training, kruisvalidatie en het afstemmen van hyperparameters).
  3. Pas het model, zodra de ontwikkeling is voltooid en je je definitieve model hebt geselecteerd, aan op de volledige trainingsgegevens van 80%.
  4. Evalueer precies één keer op de testset van 20% en rapporteer die score.

Als je deze werkstroom volgt, krijg je een betrouwbare schatting van hoe je model op toekomstige, ongeziene gegevens zal presteren.

from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

X, y = load_breast_cancer(return_X_y=True)

# Step 1: Reserve test set FIRST
X_dev, X_test, y_dev, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# Step 2: Cross-validate on development set
pipeline = Pipeline([('scaler', StandardScaler()), ('clf', LogisticRegression(max_iter=1000))])
cv_scores = cross_val_score(pipeline, X_dev, y_dev, cv=5, scoring='accuracy')
print(f'Dev CV accuracy: {cv_scores.mean():.4f} (+/- {cv_scores.std():.4f})')

# Step 3: Fit final model on all dev data
pipeline.fit(X_dev, y_dev)

# Step 4: One-time final evaluation
print(f'Final test accuracy: {pipeline.score(X_test, y_test):.4f}')

Snelle controle

Test je begrip van de concepten rond machinaal leren met Python uit deze les.

Samenvatting van de les

In deze les heb je geleerd dat test_size het aandeel gegevens bepaalt dat wordt achtergehouden voor de eindevaluatie, dat random_state het husselen initialiseert voor reproduceerbaarheid en een eerlijke modelvergelijking en dat stratify=y de klassenaandelen in beide splitsingen behoudt, wat cruciaal is voor datasets met een ongelijke klassendistributie. Hierna bestudeer je de afweging tussen vertekening en variantie en leer je onderaanpassing en overaanpassing te herkennen door foutcurven voor training en validatie te tekenen.

Gratis beginnen

Leer Python met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “train_test_split: verhoudingen, seeds en stratificatie” gratis?

Ja — de volledige tekst van “train_test_split: verhoudingen, seeds en stratificatie” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Machine Learning Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Machine Learning Academy bevat in totaal 4 lessen.

Wat leer ik in “train_test_split: verhoudingen, seeds en stratificatie”?

U gebruikt sklearn's train_test_split met verschillende testgroottes, stelt random seeds in voor reproduceerbaarheid en past stratificatie toe voor gebalanceerde splitsingen. Je oefent met Machine Learning Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Machine Learning Academy te beginnen?

Ervaring vooraf is niet nodig. Machine Learning Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “train_test_split: verhoudingen, seeds en stratificatie”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Machine Learning Academy?

Ja. Elke les over Machine Learning Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Waarom u niet op trainingsgegevens kunt evalueren
  2. train_test_split: verhoudingen, seeds en stratificatie
  3. Bias-variantieafweging: underfitting versus overfitting
  4. Basismodellen: versla altijd de DummyClassifier
← Terug naar Machine Learning Academy