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

Leeg is niet hetzelfde als nul

Herken ontbrekende waarden, schat een invulwaarde en behoud het onderscheid tussen ontbreken en nul.

45 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je herkent None en NaN zonder echte nullen weg te gooien.
  • Je legt uit waarom invullen een keuze is en ontbrekende data niet automatisch herstelt.

Een hoogtesensor geeft bij één plant 0 centimeter en bij een andere plant geen meting. Die twee gevallen betekenen iets anders: nul is een waarneming, leeg zegt dat je de hoogte niet kent. Een ontbrekende waarde zomaar door nul vervangen kan dus een verzonnen meting aan je gegevens toevoegen.

Een sensor kan uitvallen of een plant kan te groot zijn voor het instrument. Beide leveren lege vakken op, maar alleen het tweede mechanisme verbergt juist grote waarden. We onderzoeken zowel het herkennen van leegte als de gevolgen van een invulkeuze.

1. Maak zichtbaar welke posities ontbreken

Neem de lijst [0, None, 4, NaN]. Op posities 0 en 2 staan metingen; op posities 1 en 3 ontbreekt de waarde. Een ontbreekmasker (missingness mask) bewaart dat onderscheid als [False, True, False, True].

Een masker heeft dezelfde lengte en volgorde als de oorspronkelijke lijst. True betekent hier “ontbreekt”, niet “geldige meting”. In deze oefening zijn alleen None en een float-NaN ontbrekend; overige getallen zijn eindig.

import math
xs = [0, None, 4, float("nan")]
masker = []
for i in range(len(xs)):
    mist = False
    if xs[i] is None:
        mist = True
    if type(xs[i]) == float:
        if math.isnan(xs[i]):
            mist = True
    masker.append(mist)
print(masker)
# [False, True, False, True]

is None is de expliciete Pythoncontrole op de bijzondere waarde None. math.isnan controleert een float op NaN; de extra inspringing betekent dat die controle alleen binnen de voorafgaande typecontrole draait. De bekende import math maakt deze functie beschikbaar.

Veelgemaakte fout: NaN met == proberen te herkennen. Zelfs NaN vergelijken met zichzelf geeft False; daarom gebruiken we math.isnan. Maak nu ontbreekmasker(xs), ook voor een lege lijst; die levert een leeg masker op.

01
CHECKPOINTMarkeer wat ontbreekt

2. Leer één invulwaarde uit wat bekend is

Van onze lijst blijven 0 en 4 over. Hun som is 4 en hun aantal is 2, dus het gemiddelde is 2. Nul telt mee in het aantal: alleen waarden weglaten omdat ze niet positief zijn zou het gemiddelde ten onrechte 4 maken.

m=0+42=2

m noemt de gekozen invulwaarde. Gebruik het masker uit de vorige berekening om alleen bekende metingen op te tellen:

totaal = 0
aantal = 0
for i in range(len(xs)):
    if masker[i] == False:
        totaal = totaal + xs[i]
        aantal = aantal + 1
invulwaarde = totaal / aantal
print(invulwaarde)   # 2.0

Maak fit_gemiddelde(xs) met je maskerfunctie. Fit betekent hier “een instelling uit gegevens leren”: je berekent één getal, niet een ingevulde lijst. Als geen bekende waarde overblijft, geef je None vóór de deling; een lege groep heeft geen te schatten gemiddelde.

02
CHECKPOINTLeer de invulwaarde uit bekende metingen

Een gemiddelde uit de zichtbare waarden hoeft niet representatief te zijn voor de verborgen waarden. Het volgende diagram kent als oefening de volledige reeks 2, 4, 6, 8, 10, 12, 14, 16: gemiddelde 9. Verberg bij Hoogste waarden twee metingen; de resterende som is 42, gedeeld door zes geeft 7.

DE OORZAAK VAN ONTBREKEN TELT MEEWat verdwijnt uit je dataset?

In deze simulatie kennen we de volledige reeks: 2, 4, 6, 8, 10, 12, 14, 16. Verberg daarna een deel.

Meting 12
Meting 24
Meting 36
Meting 48
Meting 510
Meting 612
Meting 7—
Meting 8—
volledige reeks9.00zichtbare reeks7.00
Ontbreekt 2 / 8Zichtbaar gemiddelde 7.00

Vergelijk met Verspreid bij hetzelfde aantal. Er zijn evenveel lege vakken, maar andere waarden verdwijnen en dus verandert het zichtbare gemiddelde anders. De getoonde volledige reeks is in deze simulatie bekend; bij echte ontbrekende metingen heb je dat controleantwoord meestal niet.

3. Pas de gekozen waarde toe zonder opnieuw te leren

Imputeren (imputation) betekent ontbrekende waarden volgens een afgesproken regel invullen. Met invulwaarde 2 wordt onze lijst [0, 2, 4, 2]. De nul en vier blijven echt gemeten; de twee ingevulde waarden krijgen niet ineens dezelfde bewijskracht.

nieuw = []
for i in range(len(xs)):
    waarde = xs[i]
    if masker[i] == True:
        waarde = invulwaarde
    nieuw.append(waarde)
print(nieuw)   # [0, 2.0, 4, 2.0]
print(xs[1] is None)       # True

We maken een nieuwe lijst zodat de oorspronkelijke ontbrekende posities bewaard blijven. Maak vul_in(xs, waarde): gebruik de meegegeven waarde en je masker, zonder daarin nog een gemiddelde te berekenen. Dit toepassen van een eerder geleerde instelling heet transform.

03
CHECKPOINTPas dezelfde keuze consequent toe

Later leer je modellen op trainingsgegevens en controleer je ze op apart gehouden gegevens. Leer ook de invulwaarde uitsluitend uit de trainingsgegevens, anders beïnvloedt de controleverzameling vooraf je bewerking. Bij een nieuwe controlelijst [10, None] blijft onze eerder geleerde invulwaarde daarom 2:

controle = [10, None]
ingevuld = [controle[0], invulwaarde]
print(ingevuld)   # [10, 2.0]

Opnieuw leren uit die controlelijst zou 10 als invulwaarde geven. Dan is de regel veranderd door de gevallen waarop je hem juist wilde beoordelen. Fit en transform apart houden maakt dit verschil controleerbaar.

Vergelijk nu drie invulregels voor een andere lijst. De vijf bekende waarden 2, 3, 5, 50 en 8 tellen op tot 68; hun gemiddelde is 13.6, hun mediaan 5. Twee keer 5 invullen geeft een totaalsom van 78 over zeven waarden:

68+2×57≈11.143
print((68 + 2 * 5) / 7)   # ongeveer 11.143
INVULLEN IS EEN AANNAMEDrie keuzes, drie datasets

Gegeven: 2, 3, leeg, 5, 50, leeg, 8. Oranje punten zijn ingevuld, groene punten echt gemeten.

01020304050waarde
Invulwaarde 13.600Gemiddelde na invullen 13.600

De echte ontbrekende waarden zijn onbekend. Dit experiment vergelijkt aannames; het vertelt niet welke invulling waar is.

Kies Mediaan en controleer dat resultaat. Wissel daarna naar Gemiddelde en Nul: het gemiddelde van de hele lijst verandert door jouw keuze. Geen van deze knoppen onthult wat oorspronkelijk in de lege vakken stond.

Wat neem je mee?

  • Bewaar een masker: nul en ontbreken zijn verschillende toestanden.
  • Leer een invulwaarde alleen uit bekende trainingsmetingen; geen bekende waarden betekent hier None.
  • Pas diezelfde waarde later toe in een nieuwe lijst. Invullen voegt een aanname toe, geen teruggevonden meting.

Hierna onderzoek je rijen die vaker voorkomen. Ook daar begint de juiste behandeling bij de betekenis van de gegevens.

Verder lezen & bronnen

Inhoud gecontroleerd op 2026-10-27.
DE VOLGENDE STAPWanneer zijn twee rijen hetzelfde?
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
Markeer wat ontbreekt

Schrijf ontbreekmasker(xs): True voor None of float-NaN, False voor aanwezige eindige getallen. Een lege lijst geeft [].

Een hint

Start elke positie met False. Controleer is None; pas math.isnan alleen toe binnen een float-typecontrole.

02
Leer de invulwaarde uit bekende metingen

Schrijf fit_gemiddelde(xs). Negeer None en float-NaN; geef None als geen bekende waarde overblijft.

Een hint

Gebruik je masker. Tel alleen bij False de waarde en het aantal op, zodat nul gewoon meetelt. Controleer het aantal vóór delen.

03
Pas dezelfde keuze consequent toe

Schrijf vul_in(xs, waarde) met de meegegeven invulwaarde. Behoud alle gemeten waarden en wijzig xs niet.

Een hint

Maak een nieuwe lijst. Start per positie met de oorspronkelijke waarde en vervang alleen als je masker True aangeeft; leer hier geen nieuwe invulwaarde.

Vastgelopen? Bekijk de voorbeeldoplossing
import math


def ontbreekmasker(xs):
    masker = []
    for i in range(len(xs)):
        mist = False
        if xs[i] is None:
            mist = True
        if type(xs[i]) == float:
            if math.isnan(xs[i]):
                mist = True
        masker.append(mist)
    return masker


def fit_gemiddelde(xs):
    masker = ontbreekmasker(xs)
    totaal = 0
    aantal = 0
    for i in range(len(xs)):
        if masker[i] == False:
            totaal = totaal + xs[i]
            aantal = aantal + 1
    if aantal == 0:
        return None
    return totaal / aantal


def vul_in(xs, waarde):
    masker = ontbreekmasker(xs)
    nieuw = []
    for i in range(len(xs)):
        element = xs[i]
        if masker[i] == True:
            element = waarde
        nieuw.append(element)
    return nieuw

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