Werkplaats / De werkplaats
In jouw eigen tempo
← Data
MODULE 02 · LES 05

Ook je voorbereiding kan het antwoord lekken

Scheid fit en transform zodat testgegevens de aangeleerde voorbereiding niet veranderen.

45 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je leert preprocessing uitsluitend van de trainingsset.
  • Je bewijst dat veranderende testdata de aangeleerde toestand niet beïnvloeden.

Je hebt planten keurig over training en test verdeeld. Toch gebruik je alvast alle hoogtes om een gemiddelde te berekenen waarmee je de gegevens voorbereidt. De test heeft dan invloed voordat het model zijn eerste voorspelling maakt.

Dit heet datalekkage (data leakage): informatie gebruiken die je tijdens het leren niet mocht kennen. Het kan een toekomstig antwoord zijn, maar ook een instelling die ongemerkt uit de testgegevens komt. We bouwen een kleine bewerking waarin je die invloed precies kunt aanwijzen.

1. Kies het nulpunt uitsluitend uit training

Stel je een meetlat voor waarop je een nieuw nulpunt markeert. Centreren (centering) betekent dat je van iedere waarde hetzelfde gemiddelde aftrekt. Je bewaart zo verschillen tussen waarden, maar beschrijft ze als afwijkingen van een gekozen referentie.

Onze trainingshoogtes zijn 2, 4 en 6. Hun som is 12 en hun aantal is 3, dus het gemiddelde is 4. De fit-stap, het leren van een instelling, slaat dat getal op voor later gebruik.

m=2+4+63=4

m noemt ons nieuwe nulpunt. Zoals bij de invulwaarde in de vorige module mag alleen training dit getal bepalen. De dictionary state, Engels voor toestand, bewaart de geleerde waarde onder sleutel "mean".

def fit_centrum(train):
    if len(train) == 0:
        raise ValueError("Lege training")
    totaal = 0
    for i in range(len(train)):
        totaal = totaal + train[i]
    return {"mean": totaal / len(train)}

train = [2, 4, 6]
state = fit_centrum(train)
print(state)   # {'mean': 4.0}

Maak fit_centrum(train) met deze berekening. We oefenen met kleine eindige getallen; bij een lege trainingslijst geef je ValueError vóór de deling. Zonder waarnemingen is geen gemiddelde geleerd: nul teruggeven zou een verzonnen instelling opleveren.

01
CHECKPOINTLeer één toestand uit training

De functie heeft bewust alleen train als argument. Zo kun je aan haar invoer al zien welke gegevens deze leerstap mogen beïnvloeden. Bewaar de oorspronkelijke lijst; de toestand bevat alleen het resultaat van de berekening.

2. Gebruik overal dezelfde meetlat

De transform-stap past de eerder geleerde instelling toe. Training 2, 4 en 6 wordt dus −2, 0 en 2. Een testplant met hoogte 100 wordt 96: ver boven het trainingsgemiddelde, precies wat de bewerking zichtbaar moet laten.

z=x−m=100−4=96

x is de oorspronkelijke waarde, m het bewaarde trainingsgemiddelde en z de gecentreerde waarde. Er komt hier geen nieuwe fit aan te pas. Je trekt simpelweg hetzelfde getal van iedere invoerwaarde af.

def centreer(xs, state):
    nieuw = []
    for i in range(len(xs)):
        waarde = xs[i] - state["mean"]
        nieuw.append(waarde)
    return nieuw

test = [100]
print(centreer(train, state))
# [-2.0, 0.0, 2.0]
print(centreer(test, state))  # [96.0]

Maak centreer(xs, state) met een nieuwe uitvoerlijst. Verander xs en state niet; een lege lijst geeft weer een lege lijst. Of xs training, validatie of test bevat, verandert niets aan de gebruikte instelling.

02
CHECKPOINTPas dezelfde toestand overal toe

Veelgemaakte fout: iedere verzameling rond haar eigen gemiddelde centreren. Voor de testlijst [100] zou je dan 100 aftrekken en nul krijgen. Dat verbergt het verschil met training én geeft de test een andere meetlat.

De volgende visualisatie houdt training vast op 2, 4 en 6. Zet Testwaarde op 100: de correcte fit blijft 4, maar fit op alle vier de waarden samen geeft 28. De correcte testuitvoer blijft 96.

gelekt = (2 + 4 + 6 + 100) / 4
print(gelekt)   # 28.0
TESTDATA MOGEN FIT NIET VERANDERENWie bepaalt het gemiddelde?

Training: 2, 4, 6. Verander alleen het onbekende testvoorbeeld. Groen leert uit training; oranje kijkt ook naar test.

020406080100waarde · lijnen: correct en gelekt gemiddelde
Fit op training4.00Fit met test erbij13.00Correcte test − 436.00

Zet de schuif daarna op 20. De oranje fit verandert naar 8 terwijl de groene fit 4 blijft; alleen die groene instelling is onafhankelijk van test. Dit toont beïnvloeding van de voorbereiding, niet hoeveel een modelscore zou veranderen: we hebben hier nog geen model beoordeeld.

3. Bouw een controleerbare keten

Een pipeline is een vaste keten van bewerkingen. Onze keten leert één toestand op training en gebruikt haar daarna tweemaal: voor training en voor test. De drie resultaten gaan samen terug als tuple, zodat ook de geleerde instelling inspecteerbaar blijft.

Dit voorbeeld gebruikt de twee functies die je zojuist hebt gemaakt. De namen links bewaren hun resultaten; iedere aanroep voert één stap uit:

def centreer_pipeline(train, test):
    state = fit_centrum(train)
    a = centreer(train, state)
    b = centreer(test, state)
    return (a, b, state)

print(centreer_pipeline([2, 4, 6], [100]))
# ([-2.0, 0.0, 2.0], [96.0], {'mean': 4.0})

Voor training [2,4,6] en test [100] verwacht je ([-2,0,2], [96], {"mean":4}). Maak centreer_pipeline(train, test) en controleer ook een andere testlijst: met [10] wordt alleen de testuitvoer [6]. De trainingsuitvoer en toestand blijven precies gelijk.

03
CHECKPOINTBewijs dat de test onbekend blijft

Dit is een bruikbare controle-eigenschap: verander wat onbekend moest blijven en kijk of de geleerde toestand toch verandert. Ook bij het eerder behandelde imputeren hoort de invulwaarde deze controle te doorstaan. Een pipeline helpt alleen als je haar stappen daadwerkelijk de juiste gegevens geeft.

Wat neem je mee?

  • Splits vóór je instellingen uit gegevens leert; ook voorbereiding kan informatie lekken.
  • Fit leert het nulpunt uit training, transform gebruikt datzelfde nulpunt voor iedere verzameling.
  • Een andere testlijst mag de training en geleerde toestand niet veranderen.

Hierna onderzoek je welke records samen moeten blijven als planten vaker gemeten worden of de tijd een rol speelt.

Verder lezen & bronnen

Inhoud gecontroleerd op 2026-10-28.
DE VOLGENDE STAPKies een split die je echte vraag nabootst
JOUW EXPERIMENT

Probeer het zelf

Python
main.py

Python start zodra jij code uitvoert.

UITVOER

Je uitvoer verschijnt hier.
Alles rekent in je eigen browser.

Jouw checkpoints0 / 3
01
Leer één toestand uit training

Maak fit_centrum(train) voor kleine eindige oefengetallen: geef een dictionary met sleutel mean en het trainingsgemiddelde. Weiger lege training met ValueError.

Een hint

Controleer de lengte, tel waarden met een lus op en deel door het aantal. De functie krijgt alleen training.

02
Pas dezelfde toestand overal toe

Maak centreer(xs, state): geef een nieuwe lijst met van iedere waarde state["mean"] afgetrokken. Verander xs en state niet.

Een hint

Maak een lege uitvoerlijst. Gebruik in iedere lus hetzelfde opgeslagen gemiddelde, zonder opnieuw fit uit te voeren.

03
Bewijs dat de test onbekend blijft

Maak centreer_pipeline(train, test) en geef (train_nieuw, test_nieuw, state). Leer alleen op training; pas dezelfde toestand op beide lijsten toe.

Een hint

Roep fit_centrum op train aan en daarna centreer tweemaal met die ene state. Een andere testlijst mag state en train_nieuw niet veranderen.

Vastgelopen? Bekijk de voorbeeldoplossing
def fit_centrum(train):
    if len(train) == 0:
        raise ValueError("Lege training")
    totaal = 0
    for i in range(len(train)):
        totaal = totaal + train[i]
    return {"mean": totaal / len(train)}


def centreer(xs, state):
    nieuw = []
    for i in range(len(xs)):
        waarde = xs[i] - state["mean"]
        nieuw.append(waarde)
    return nieuw


def centreer_pipeline(train, test):
    state = fit_centrum(train)
    a = centreer(train, state)
    b = centreer(test, state)
    return (a, b, state)

Voer de code uit en verklaar voor jezelf waarom elke stap werkt.