Werkplaats / De werkplaats
In jouw eigen tempo
← Klassieke machine learning
MODULE 01 · LES 01

Vind de lijn die het beste past

Voorspel een getal met een rechte lijn en bereken de kleinste-kwadratenoplossing met gecentreerde meetparen.

50 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je interpreteert helling en intercept van een lineair model.
  • Je berekent de kleinste-kwadratenlijn voor één feature.

Hoeveel groeit een plant als je één dag langer wacht? Een eenvoudig model laat de voorspelde hoogte iedere dag met hetzelfde bedrag toenemen. Bij regressie (regression) voorspel je een getal; een rechte lijn is een eerste, controleerbare benadering.

Stel je een lat voor die je kunt kantelen en omhoogschuiven. Kantelen verandert de groei per dag, omhoogschuiven verandert alle voorspellingen evenveel. De gemeten punten hoeven niet precies op die lat te liggen.

1. Twee instellingen, één voorspelling

De helling (slope) w bepaalt de voorspelde verandering per extra eenheid x. Het intercept, ook startwaarde genoemd, b is de voorspelling bij x gelijk aan nul. Samen geven ze:

y^=wx+b

x is de invoer, y de werkelijke meting en het dakje boven y betekent voorspelling. Bij w = 2 en b = 1 krijgt x = 2 de voorspelling 5. Bij x = 0, 1 en 2 worden de voorspellingen dus 1, 3 en 5.

xs = [0, 1, 2]
w = 2
b = 1
pred = []
for i in range(len(xs)):
    pred.append(w * xs[i] + b)
print(pred)  # [1, 3, 5]

Maak voorspel_lijn(xs,w,b) met een nieuwe lijst, ook als xs leeg is. De waarden in xs blijven behouden. Een grotere w is een sterkere stijging, terwijl een negatieve w een daling voorspelt.

01
CHECKPOINTGeef de parameters betekenis

Zet hieronder w op 2 en b op 1: alle vijf punten liggen op de lijn. Verander alleen b naar 0 en voorspel eerst het patroon: alle voorspellingen komen één lager. De oranje stukken verbinden meting en voorspelling; de weergegeven MSE is hun gemiddelde gekwadrateerde lengte.

EEN LIJN EN HAAR RESIDUENWaar mist je voorspelling het doel?

Vijf vaste punten volgen y=2x+1. De groene lijn is jouw model; oranje lijnen tonen de afwijkingen.

-4-20246-2-1012
Helling1.0Intercept0.0MSE3.000

2. Zoek een compromis voor punten naast de lijn

Neem nu x = [0, 1, 2] en y = [1, 2, 6]. Geen rechte lijn gaat door alle drie de punten. Kleinste kwadraten (ordinary least squares) kiest w en b zodat de som van de gekwadrateerde verticale fouten zo klein mogelijk wordt.

Eerst centreer je beide reeksen: hun gemiddelden zijn 1 en 3. De x-afwijkingen zijn −1, 0 en 1; de y-afwijkingen −2, −1 en 3. Hun paarsgewijze producten tellen op tot 5, terwijl de gekwadrateerde x-afwijkingen optellen tot 2.

w=∑(xi−x¯)(yi−y¯)∑(xi−x¯)2

Een streep boven x of y benoemt het gemiddelde; i wijst hetzelfde meetpaar aan. Het somteken ∑ telt over alle paren. De teller meet samen bewegen, de noemer de spreiding in x: hier wordt de helling 5/2 = 2.5.

De beste lijn met intercept gaat door het punt met beide gemiddelden. Kies daarom b als het y-gemiddelde min w maal het x-gemiddelde: 3 − 2.5 × 1 = 0.5. Deze gesloten formule geeft het optimum direct; later leer je ook stapsgewijs zoeken.

xs = [0, 1, 2]
ys = [1, 2, 6]
mx = sum(xs) / len(xs)
my = sum(ys) / len(ys)
teller = 0
noemer = 0
for i in range(len(xs)):
    dx = xs[i] - mx
    dy = ys[i] - my
    teller = teller + dx * dy
    noemer = noemer + dx ** 2
w = teller / noemer
b = my - w * mx
print(w, b)  # 2.5 0.5

sum telt de getallen op. Maak fit_lijn(xs,ys) en geef het paar (w,b) terug. Weiger lege of ongelijk lange lijsten met ValueError; iedere x moet zijn eigen y houden.

Als alle x gelijk zijn, is de noemer nul: je kunt geen unieke helling uit die metingen leren. Ook dan vraagt deze oefening ValueError. De oefengetallen zijn klein en eindig; extreme numerieke stabiliteit behandelen we hier niet.

02
CHECKPOINTMinimaliseer de som van gekwadrateerde fouten

3. Lees de fouten zonder wegstrepen

Onze nieuwe voorspellingen zijn [0.5, 3, 5.5]. Het residu (residual) is meting min voorspelling: [0.5, −1, 0.5]. Positief betekent dus dat het model te laag voorspelt.

pred = []
rest = []
for i in range(len(xs)):
    pred.append(w * xs[i] + b)
    rest.append(ys[i] - pred[i])
print(rest)       # [0.5, -1.0, 0.5]
print(sum(rest))  # 0.0

Maak residuen(ys,pred); ongelijke lengtes geven ValueError en twee lege lijsten geven een lege lijst. Bij deze optimale trainingslijn met intercept is de som ongeveer nul. Veelgemaakte fout: daaruit besluiten dat iedere voorspelling goed is; positieve en negatieve fouten vallen hier tegen elkaar weg.

03
CHECKPOINTBekijk wat de lijn niet verklaart

Wat neem je mee?

  • Helling kantelt de lijn, intercept verschuift haar.
  • Kleinste kwadraten kiest een compromis met behulp van gekoppelde, gecentreerde trainingsmetingen.
  • Residuen laten zien waar de lijn mist; hun som kan fouten verbergen.

Een geleerd verband bewijst geen oorzaak, en buiten het gemeten x-bereik blijft de lijn een aanname. Hierna vergelijk je foutmaten die tegengestelde fouten niet laten verdwijnen.

Verder lezen & bronnen

Inhoud gecontroleerd op 2026-10-28.
DE VOLGENDE STAPKies wat een fout je kost
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
Geef de parameters betekenis

Schrijf voorspel_lijn(xs,w,b) als lijst voorspellingen.

Een hint

Bereken w*x+b voor ieder element, zonder de invoer te wijzigen.

02
Minimaliseer de som van gekwadrateerde fouten

Schrijf fit_lijn(xs,ys) en geef (w,b) terug.

Een hint

Bereken beide gemiddelden; de noemer is de som van gekwadrateerde x-afwijkingen.

03
Bekijk wat de lijn niet verklaart

Schrijf residuen(ys,pred), met ValueError bij ongelijke lengtes.

Een hint

Trek per paar de voorspelling van de waarneming af.

Vastgelopen? Bekijk de voorbeeldoplossing
def voorspel_lijn(xs, w, b):
    result = []
    for i in range(len(xs)):
        result.append(w * xs[i] + b)
    return result


def fit_lijn(xs, ys):
    if not xs or len(xs) != len(ys):
        raise ValueError("Evenveel niet-lege paren vereist")
    mx = sum(xs) / len(xs)
    my = sum(ys) / len(ys)
    teller = 0
    noemer = 0
    for i in range(len(xs)):
        dx = xs[i] - mx
        dy = ys[i] - my
        teller = teller + dx * dy
        noemer = noemer + dx ** 2
    if noemer == 0:
        raise ValueError("Constante feature")
    w = teller / noemer
    return w, my - w * mx


def residuen(ys, pred):
    if len(ys) != len(pred):
        raise ValueError("Ongelijke lengtes")
    result = []
    for i in range(len(ys)):
        result.append(ys[i] - pred[i])
    return result

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