- Je berekent de empirische bias-variantie-identiteit voor herhaalde voorspellingen.
- Je onderzoekt modelcapaciteit met polynomiale features en regularisatie.
Een model voorspelt voor dezelfde plant telkens iets anders wanneer je het op een nieuwe steekproef traint. Een ander model voorspelt juist bijna steeds hetzelfde, maar zit structureel te laag. Deze twee problemen vragen om een andere diagnose dan alleen één trainingsscore.
Bias beschrijft de afwijking van de gemiddelde voorspelling; variantie (variance) beschrijft de spreiding tussen herhaalde fits. Een model met te weinig vrijheid kan een patroon missen: underfitting. Een flexibel model kan toevallige trainingsdetails volgen: overfitting.
1. Houd de invoer vast en herhaal de training
Stel dat je voor één vaste invoer de voorspellingen [0,2] krijgt uit twee verschillende trainingssets. In deze simulatie kennen we de ruisvrije waarheid f = 4. De gemiddelde voorspelling m is 1, dus de gekwadrateerde bias is (1−4)² = 9.
De afwijkingen rond het gemiddelde zijn −1 en 1; hun gemiddelde kwadraat is 1. De directe fouten tegen f zijn −4 en −2: MSE = (16+4)/2 = 10. Inderdaad: bias² + variantie = 9+1 = 10.
N telt de herhaalde voorspellingen; p_i is één voorspelling en V hun populatievariantie. Gebruik hier deler N, niet N−1, zodat de identiteit exact voor deze gegeven lijst geldt.
predictions = [0, 2]
f = 4
m = sum(predictions) / len(predictions)
bias2 = (m - f) ** 2
v, mse = 0, 0
for p in predictions:
v = v + (p - m) ** 2
mse = mse + (p - f) ** 2
v = v / len(predictions)
mse = mse / len(predictions)
print(bias2, v, mse) # 9.0 1.0 10.0
Maak decompositie(predictions,true_value) als (bias2,variance,mse) en weiger lege invoer. Veelgemaakte fout: spreiding tussen voorspellingen bij verschillende planten gebruiken; dan meng je verschillende invoeren met trainingsvariatie.
Bij een nieuw doel met onafhankelijke, nulgemiddelde ruis komt in verwachting de ruisvariantie bij de fout. In echte data ken je f meestal niet: deze oefening is een inzichtelijke identiteit, geen truc om verborgen waarheid uit metingen te halen.
012. Geef het model meer mogelijke vormen
Een rechte lijn kan geen bocht maken. Polynomiale features voegen machten van x toe: graad 2 maakt van x de rij [1,x,x²]. Het model combineert die kolommen nog steeds lineair met coëfficiënten.
w_0 is het intercept; de andere gewichten horen bij hun machten. Bij x = −1,0,1 zijn de featurerijen [1,−1,1], [1,0,0] en [1,1,1]. Coëfficiënten [1,2,0] geven voorspellingen −1,1,3.
xs = [-1, 0, 1]
matrix = []
for x in xs:
rij = []
for macht in range(3):
rij.append(x ** macht)
matrix.append(rij)
print(matrix)
# [[1, -1, 1], [1, 0, 0], [1, 1, 1]]
w = [1, 2, 0]
for rij in matrix:
p = sum(a * b for a, b in zip(rij, w))
print(p)
# -1, 1, 3
Maak poly_features(xs,graad) voor een niet-negatieve gehele graad; ongeldige graden geven ValueError. Graad nul geeft alleen de constante kolom. Meer machten betekenen meer vrijheid, maar garanderen geen betere voorspelling op onbekende data.
Twaalf vaste trainingspunten: sin(πx) plus ruis. De oranje curve is het bekende simulatiepatroon; groen is je gefitte polynoom.
Validatie gebruikt 41 andere x-waarden met ruisvrije doelen. Die waarheid kennen we alleen doordat dit een simulatie is.
Laat alpha op nul staan en vergelijk graad 1,3 en 9. Voorspel eerst of de trainingsfout daalt en of validatie mee blijft verbeteren; controleer daarna de getallen. Het diagram kent de ruisvrije sinus alleen doordat dit gesimuleerde gegevens zijn.
023. Straf grote coëfficiënten, behalve het intercept
Ridge minimaliseert hier de som van kwadratische trainingsfouten plus alpha maal de som van gekwadrateerde gewichten, met uitzondering van w_0. Alpha is niet-negatief; groter betekent meer straf. Die schaal hoort bij een som van fouten, niet bij een gemiddelde.
Neem voor graad 1 x = [−1,0,1] en y = [−1,1,3]. De ontwerp-matrix X heeft rijen [1,−1], [1,0] en [1,1]. Vermenigvuldigen geeft XᵀX met diagonaal [3,2] en nullen daarbuiten; Xᵀy is [3,4].
D is een diagonale strafmatrix: eerst nul, daarna enen. Zonder straf lossen 3w_0 = 3 en 2w_1 = 4 op naar [1,2]. Met alpha = 2 wordt de tweede vergelijking 4w_1 = 4: [1,1], terwijl het intercept hier gelijk blijft.
import numpy as np
X = np.array([[1, -1], [1, 0], [1, 1]])
y = np.array([-1, 1, 3])
D = np.eye(2)
D[0, 0] = 0
for alpha in [0, 2]:
A = X.T @ X + alpha * D
rhs = X.T @ y
w = np.linalg.solve(A, rhs)
print(w.tolist()) # [1, 2]; [1, 1]
X.T wisselt rijen en kolommen; @ is matrixvermenigvuldiging. np.eye(2) maakt een eenheidsmatrix en solve(A,rhs) lost A maal w = rhs op. Gebruik geen elementgewijze deling: buiten dit symmetrische voorbeeld kan A ook niet-nulwaarden buiten de diagonaal hebben.
Maak ridge_fit(xs,ys,graad,alpha) met een floatmatrix uit je eigen features en geef de coëfficiënten als lijst in oplopende macht terug. Weiger negatieve alpha of graad en lege/ongelijke paren. Gebruik bij alpha nul gegevens waarvoor het stelsel uniek oplosbaar is; gedrag bij een singulier stelsel valt buiten deze opdracht.
Zet in het diagram graad 9 vast en verhoog alpha. Bekijk hoeveel de curve en beide fouten veranderen. Schaling beïnvloedt de straf; kies graad en alpha met validatie en bewaar de eindtest voor de laatste beoordeling.
03Wat neem je mee?
- Bias en variantie bekijken herhaalde fits bij dezelfde invoer.
- Polynomiale features vergroten de modelvrijheid; ridge begrenst de coëfficiënten.
- De simulatie verklaart gedrag, terwijl onafhankelijke evaluatie de uiteindelijke keuze onderbouwt.
Hierna onderzoek je wat je kunt leren wanneer er helemaal geen labels beschikbaar zijn.