Model Training
Dit hoofdstuk behandelt het trainen van machine learning modellen, het maken van voorspellingen, het evalueren van resultaten en het herkennen van overfitting en underfitting.
Model trainen
Het trainen van een model betekent dat je het algoritme laat leren van je data. Het model past zijn interne parameters aan om zo goed mogelijk te presteren op de trainingstaak.
Basis workflow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
# 1. Data splitsen
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 2. Model instantiëren
model = RandomForestClassifier(n_estimators=100, random_state=42)
# 3. Model trainen
model.fit(X_train, y_train)
# 4. Model is nu klaar voor voorspellingen
|
Wat gebeurt er tijdens training?
| Model type |
Wat het leert |
| Linear Regression |
Gewichten (coëfficiënten) voor elke feature |
| Decision Tree |
Splitsingspunten en drempelwaarden |
| Random Forest |
Meerdere decision trees |
| Neural Network |
Gewichten en biases in alle lagen |
| KNN |
Niets — slaat alleen data op (lazy learning) |
Training parameters
| Parameter |
Beschrijving |
| Hyperparameters |
Instellingen die je vóór training kiest (learning rate, max_depth) |
| Epochs |
Aantal keer dat het model de hele dataset ziet (neural networks) |
| Batch size |
Aantal samples per update (neural networks) |
| Early stopping |
Stop training als validatie-performance niet meer verbetert |
Voorbeeld: Neural Network training
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | from tensorflow import keras
model = keras.Sequential([
keras.layers.Dense(64, activation='relu', input_shape=(n_features,)),
keras.layers.Dense(32, activation='relu'),
keras.layers.Dense(1, activation='sigmoid')
])
model.compile(
optimizer='adam',
loss='binary_crossentropy',
metrics=['accuracy']
)
# Training met validatie
history = model.fit(
X_train, y_train,
epochs=100,
batch_size=32,
validation_split=0.2,
callbacks=[keras.callbacks.EarlyStopping(patience=5)]
)
|
Runnen van predictions
Na het trainen kun je het model gebruiken om voorspellingen te doen op nieuwe, ongeziene data.
Basis voorspellingen
| # Voorspel klassen (classificatie)
y_pred = model.predict(X_test)
# Voorspel waarschijnlijkheden (classificatie)
y_pred_proba = model.predict_proba(X_test)
# Voorspel continue waarden (regressie)
y_pred = model.predict(X_test)
|
Verschil predict vs. predict_proba
| Methode |
Output |
Voorbeeld |
predict() |
Klasse-labels |
[0, 1, 1, 0, 1] |
predict_proba() |
Kansen per klasse |
[[0.8, 0.2], [0.3, 0.7], ...] |
Voorspellingen interpreteren
1
2
3
4
5
6
7
8
9
10
11
12 | # Classificatie
y_pred = model.predict(X_test)
print(f"Voorspelde klasse: {y_pred[0]}")
# Met waarschijnlijkheden
y_pred_proba = model.predict_proba(X_test)
print(f"Kans op klasse 0: {y_pred_proba[0][0]:.2%}")
print(f"Kans op klasse 1: {y_pred_proba[0][1]:.2%}")
# Pas threshold aan (standaard 0.5)
threshold = 0.7
y_pred_custom = (y_pred_proba[:, 1] >= threshold).astype(int)
|
Voorspelling op nieuwe data
1
2
3
4
5
6
7
8
9
10
11
12 | # Nieuwe, ongeziene data
nieuwe_klant = [[35, 50000, 2, 1]] # leeftijd, inkomen, producten, actief
# Let op: zelfde preprocessing als trainingsdata!
nieuwe_klant_scaled = scaler.transform(nieuwe_klant)
# Voorspelling
voorspelling = model.predict(nieuwe_klant_scaled)
kans = model.predict_proba(nieuwe_klant_scaled)
print(f"Voorspelling: {'Churn' if voorspelling[0] == 1 else 'Geen churn'}")
print(f"Zekerheid: {max(kans[0]):.1%}")
|
!!! warning "Preprocessing niet vergeten"
Nieuwe data moet exact dezelfde preprocessing ondergaan als de trainingsdata (scaling, encoding, etc.). Gebruik dezelfde scaler/encoder objecten die je op de trainingsdata hebt gefit.
Evaluatiemetrics
Evaluatiemetrics meten hoe goed je model presteert. Welke metric je kiest hangt af van je probleem.
Classificatie metrics
Confusion Matrix basis
|
Voorspeld: Positief |
Voorspeld: Negatief |
| Werkelijk: Positief |
True Positive (TP) |
False Negative (FN) |
| Werkelijk: Negatief |
False Positive (FP) |
True Negative (TN) |
Accuracy
Formule: $(TP + TN) / (TP + TN + FP + FN)$
| Wanneer gebruiken |
Wanneer niet |
| Gebalanceerde klassen |
Ongebalanceerde data (90% negatief) |
| Alle fouten even erg |
FP en FN hebben verschillende kosten |
| from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2%}")
|
Precision
Formule: $TP / (TP + FP)$
"Van alle positieve voorspellingen, hoeveel waren correct?"
| Wanneer belangrijk |
| False positives zijn kostbaar (spam detectie, fraude alerts) |
Recall (Sensitivity)
Formule: $TP / (TP + FN)$
"Van alle werkelijk positieve cases, hoeveel hebben we gevonden?"
| Wanneer belangrijk |
| False negatives zijn kostbaar (ziekte detectie, security threats) |
F1-Score
Formule: $2 \times (Precision \times Recall) / (Precision + Recall)$
Het harmonisch gemiddelde van precision en recall. Nuttig wanneer je beide wilt balanceren.
| from sklearn.metrics import precision_score, recall_score, f1_score
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
print(f"Precision: {precision:.2%}")
print(f"Recall: {recall:.2%}")
print(f"F1-Score: {f1:.2%}")
|
Classification Report
| from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
|
Output:
| precision recall f1-score support
0 0.85 0.90 0.87 100
1 0.78 0.70 0.74 50
accuracy 0.83 150
macro avg 0.81 0.80 0.81 150
weighted avg 0.83 0.83 0.83 150
|
ROC en AUC
ROC (Receiver Operating Characteristic) curve toont de trade-off tussen True Positive Rate en False Positive Rate bij verschillende thresholds.
AUC (Area Under Curve) is de oppervlakte onder de ROC curve — hoe hoger (max 1.0), hoe beter.
| AUC waarde |
Interpretatie |
| 0.5 |
Random gokken |
| 0.7 - 0.8 |
Acceptabel |
| 0.8 - 0.9 |
Goed |
| 0.9+ |
Uitstekend |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
# Bereken ROC curve
y_pred_proba = model.predict_proba(X_test)[:, 1]
fpr, tpr, thresholds = roc_curve(y_test, y_pred_proba)
# Bereken AUC
auc = roc_auc_score(y_test, y_pred_proba)
# Plot
plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, label=f'ROC curve (AUC = {auc:.2f})')
plt.plot([0, 1], [0, 1], 'k--', label='Random')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend()
plt.show()
|
Regressie metrics
| Metric |
Formule |
Interpretatie |
| MAE |
Gemiddelde absolute fout |
Makkelijk te interpreteren, zelfde eenheid als target |
| MSE |
Gemiddelde kwadratische fout |
Straft grote fouten zwaarder |
| RMSE |
Wortel van MSE |
Zelfde eenheid als target |
| R² |
Verklaarde variantie |
0-1, hoe hoger hoe beter |
| from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)
print(f"MAE: {mae:.2f}")
print(f"RMSE: {rmse:.2f}")
print(f"R²: {r2:.2f}")
|
NLP metrics
Voor tekstgeneratie en vertaling worden specifieke metrics gebruikt:
BLEU (Bilingual Evaluation Understudy)
Meet overlap van n-grams tussen gegenereerde tekst en referentietekst. Vooral gebruikt voor machine translation.
| from nltk.translate.bleu_score import sentence_bleu
reference = [['dit', 'is', 'een', 'test', 'zin']]
candidate = ['dit', 'is', 'een', 'voorbeeld', 'zin']
bleu = sentence_bleu(reference, candidate)
print(f"BLEU score: {bleu:.2f}")
|
ROUGE (Recall-Oriented Understudy for Gisting Evaluation)
Meet overlap tussen gegenereerde samenvatting en referentiesamenvatting. Vooral voor summarization.
| Variant |
Meet |
| ROUGE-1 |
Overlap van individuele woorden |
| ROUGE-2 |
Overlap van bigrammen |
| ROUGE-L |
Langste gemeenschappelijke subsequentie |
| from rouge_score import rouge_scorer
scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'])
scores = scorer.score(
'dit is de referentie tekst',
'dit is de gegenereerde tekst'
)
for metric, score in scores.items():
print(f"{metric}: Precision={score.precision:.2f}, Recall={score.recall:.2f}")
|
Overfitting en Underfitting
Overfitting en underfitting zijn de twee hoofdproblemen bij model training.
Underfitting
Underfitting betekent dat je model te simpel is om de patronen in de data te leren.
| Symptomen |
Oorzaken |
| Lage training score |
Model te simpel |
| Lage validatie score |
Te weinig features |
| Training ≈ Validatie (beide laag) |
Te veel regularisatie |
| Training accuracy: 65%
Validation accuracy: 63%
→ Beide laag = underfitting
|
Overfitting
Overfitting betekent dat je model de trainingsdata "uit het hoofd leert", inclusief de ruis, en niet generaliseert naar nieuwe data.
| Symptomen |
Oorzaken |
| Hoge training score |
Model te complex |
| Lage validatie score |
Te weinig data |
| Groot verschil train/val |
Te lang getraind |
| Training accuracy: 98%
Validation accuracy: 72%
→ Groot verschil = overfitting
|
Visueel
| Error
│
High │ Underfitting Overfitting
│ ╲ ╱
│ ╲ ┌─────────┐ ╱
│ ╲ │ Optimal │ ╱
│ ╲ │ Zone │ ╱
Low │ ╲─┴─────────┴─────╱
│
└────────────────────────────────▶
Simple Model Complexity Complex
|
Diagnose
1
2
3
4
5
6
7
8
9
10
11
12
13 | # Train en validatie scores vergelijken
train_score = model.score(X_train, y_train)
val_score = model.score(X_val, y_val)
print(f"Training score: {train_score:.2%}")
print(f"Validation score: {val_score:.2%}")
if train_score < 0.7 and val_score < 0.7:
print("→ Mogelijk underfitting")
elif train_score - val_score > 0.1:
print("→ Mogelijk overfitting")
else:
print("→ Goede balans")
|
Learning curves
Learning curves helpen bij het diagnosticeren:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
train_sizes, train_scores, val_scores = learning_curve(
model, X, y, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10)
)
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_scores.mean(axis=1), label='Training score')
plt.plot(train_sizes, val_scores.mean(axis=1), label='Validation score')
plt.xlabel('Training set size')
plt.ylabel('Score')
plt.title('Learning Curve')
plt.legend()
plt.show()
|
Oplossingen
Underfitting oplossen
| Strategie |
Implementatie |
| Complexer model |
Meer layers, meer bomen, hogere max_depth |
| Meer features |
Feature engineering |
| Minder regularisatie |
Verlaag alpha, C, dropout |
| Langer trainen |
Meer epochs |
| Ander algoritme |
Probeer non-lineair model |
Overfitting oplossen
| Strategie |
Implementatie |
| Meer data |
Verzamel meer training samples |
| Simpeler model |
Minder layers, lagere max_depth |
| Regularisatie |
L1/L2, dropout, early stopping |
| Data augmentatie |
Meer variatie in trainingsdata |
| Cross-validation |
Robuustere evaluatie |
| Feature selection |
Verwijder irrelevante features |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | # Voorbeeld: Regularisatie in Random Forest
from sklearn.ensemble import RandomForestClassifier
# Voorkom overfitting met constraints
model = RandomForestClassifier(
n_estimators=100,
max_depth=10, # Beperk diepte
min_samples_split=10, # Minimum samples voor split
min_samples_leaf=5, # Minimum samples per blad
random_state=42
)
# Voorbeeld: Early stopping in neural networks
from tensorflow.keras.callbacks import EarlyStopping
early_stop = EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True
)
model.fit(X_train, y_train,
validation_split=0.2,
callbacks=[early_stop])
|
Samenvatting
| Situatie |
Train Score |
Val Score |
Actie |
| Underfitting |
Laag |
Laag |
Complexer model, meer features |
| Overfitting |
Hoog |
Laag |
Regularisatie, meer data, simpeler model |
| Goed |
Hoog |
Hoog (vergelijkbaar) |
Model is klaar |
!!! tip "Altijd beginnen met de data"
Voordat je aan modelcomplexiteit sleutelt, kijk eerst naar je data. Vaak is meer of betere data effectiever dan een complexer model.