You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
400 lines
15 KiB
400 lines
15 KiB
<!--
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
{
|
|
"original_hash": "482bccabe1df958496ea71a3667995cd",
|
|
"translation_date": "2025-09-05T19:07:00+00:00",
|
|
"source_file": "7-TimeSeries/3-SVR/README.md",
|
|
"language_code": "nl"
|
|
}
|
|
-->
|
|
# Tijdreeksvoorspelling met Support Vector Regressor
|
|
|
|
In de vorige les heb je geleerd hoe je het ARIMA-model kunt gebruiken om voorspellingen te maken voor tijdreeksen. Nu ga je kijken naar het Support Vector Regressor-model, een regressiemodel dat wordt gebruikt om continue gegevens te voorspellen.
|
|
|
|
## [Pre-lecture quiz](https://ff-quizzes.netlify.app/en/ml/)
|
|
|
|
## Introductie
|
|
|
|
In deze les ontdek je een specifieke manier om modellen te bouwen met [**SVM**: **S**upport **V**ector **M**achine](https://en.wikipedia.org/wiki/Support-vector_machine) voor regressie, oftewel **SVR: Support Vector Regressor**.
|
|
|
|
### SVR in de context van tijdreeksen [^1]
|
|
|
|
Voordat je het belang van SVR in tijdreeksvoorspelling begrijpt, zijn hier enkele belangrijke concepten die je moet kennen:
|
|
|
|
- **Regressie:** Een techniek voor begeleid leren om continue waarden te voorspellen op basis van een gegeven set invoerwaarden. Het idee is om een curve (of lijn) in de kenmerkenruimte te passen die het maximale aantal datapunten bevat. [Klik hier](https://en.wikipedia.org/wiki/Regression_analysis) voor meer informatie.
|
|
- **Support Vector Machine (SVM):** Een type begeleid machine learning-model dat wordt gebruikt voor classificatie, regressie en het detecteren van uitschieters. Het model is een hypervlak in de kenmerkenruimte, dat in het geval van classificatie fungeert als een grens en in het geval van regressie als de best passende lijn. In SVM wordt meestal een kernfunctie gebruikt om de dataset te transformeren naar een ruimte met een hoger aantal dimensies, zodat ze gemakkelijker te scheiden zijn. [Klik hier](https://en.wikipedia.org/wiki/Support-vector_machine) voor meer informatie over SVM's.
|
|
- **Support Vector Regressor (SVR):** Een type SVM dat de best passende lijn (die in het geval van SVM een hypervlak is) vindt die het maximale aantal datapunten bevat.
|
|
|
|
### Waarom SVR? [^1]
|
|
|
|
In de vorige les heb je geleerd over ARIMA, een zeer succesvol statistisch lineair model om tijdreeksgegevens te voorspellen. Echter, in veel gevallen hebben tijdreeksgegevens *non-lineariteit*, die niet kan worden gemodelleerd door lineaire modellen. In dergelijke gevallen maakt het vermogen van SVM om non-lineariteit in de gegevens te overwegen voor regressietaken SVR succesvol in tijdreeksvoorspelling.
|
|
|
|
## Oefening - bouw een SVR-model
|
|
|
|
De eerste paar stappen voor gegevensvoorbereiding zijn hetzelfde als die van de vorige les over [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA).
|
|
|
|
Open de [_/working_](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/3-SVR/working) map in deze les en vind het [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/7-TimeSeries/3-SVR/working/notebook.ipynb) bestand.[^2]
|
|
|
|
1. Voer de notebook uit en importeer de benodigde bibliotheken: [^2]
|
|
|
|
```python
|
|
import sys
|
|
sys.path.append('../../')
|
|
```
|
|
|
|
```python
|
|
import os
|
|
import warnings
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
import pandas as pd
|
|
import datetime as dt
|
|
import math
|
|
|
|
from sklearn.svm import SVR
|
|
from sklearn.preprocessing import MinMaxScaler
|
|
from common.utils import load_data, mape
|
|
```
|
|
|
|
2. Laad de gegevens uit het `/data/energy.csv` bestand in een Pandas dataframe en bekijk ze: [^2]
|
|
|
|
```python
|
|
energy = load_data('../../data')[['load']]
|
|
```
|
|
|
|
3. Plot alle beschikbare energiedata van januari 2012 tot december 2014: [^2]
|
|
|
|
```python
|
|
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
|
|
plt.xlabel('timestamp', fontsize=12)
|
|
plt.ylabel('load', fontsize=12)
|
|
plt.show()
|
|
```
|
|
|
|

|
|
|
|
Nu gaan we ons SVR-model bouwen.
|
|
|
|
### Maak trainings- en testdatasets
|
|
|
|
Nu je gegevens zijn geladen, kun je ze scheiden in trainings- en testsets. Vervolgens vorm je de gegevens om tot een dataset op basis van tijdstappen, wat nodig zal zijn voor de SVR. Je traint je model op de trainingsset. Nadat het model is getraind, evalueer je de nauwkeurigheid op de trainingsset, testset en vervolgens de volledige dataset om de algehele prestaties te zien. Je moet ervoor zorgen dat de testset een latere periode in de tijd omvat dan de trainingsset om te voorkomen dat het model informatie uit toekomstige tijdsperioden verkrijgt [^2] (een situatie die bekend staat als *overfitting*).
|
|
|
|
1. Wijs een periode van twee maanden toe van 1 september tot 31 oktober 2014 aan de trainingsset. De testset omvat de periode van twee maanden van 1 november tot 31 december 2014: [^2]
|
|
|
|
```python
|
|
train_start_dt = '2014-11-01 00:00:00'
|
|
test_start_dt = '2014-12-30 00:00:00'
|
|
```
|
|
|
|
2. Visualiseer de verschillen: [^2]
|
|
|
|
```python
|
|
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
|
|
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
|
|
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
|
|
plt.xlabel('timestamp', fontsize=12)
|
|
plt.ylabel('load', fontsize=12)
|
|
plt.show()
|
|
```
|
|
|
|

|
|
|
|
|
|
|
|
### Bereid de gegevens voor op training
|
|
|
|
Nu moet je de gegevens voorbereiden op training door filtering en schaling van je gegevens uit te voeren. Filter je dataset om alleen de benodigde tijdsperioden en kolommen op te nemen, en schaal de gegevens zodat ze worden geprojecteerd in het interval 0,1.
|
|
|
|
1. Filter de originele dataset om alleen de eerder genoemde tijdsperioden per set op te nemen en alleen de benodigde kolom 'load' plus de datum: [^2]
|
|
|
|
```python
|
|
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]
|
|
test = energy.copy()[energy.index >= test_start_dt][['load']]
|
|
|
|
print('Training data shape: ', train.shape)
|
|
print('Test data shape: ', test.shape)
|
|
```
|
|
|
|
```output
|
|
Training data shape: (1416, 1)
|
|
Test data shape: (48, 1)
|
|
```
|
|
|
|
2. Schaal de trainingsgegevens naar het bereik (0, 1): [^2]
|
|
|
|
```python
|
|
scaler = MinMaxScaler()
|
|
train['load'] = scaler.fit_transform(train)
|
|
```
|
|
|
|
4. Nu schaal je de testgegevens: [^2]
|
|
|
|
```python
|
|
test['load'] = scaler.transform(test)
|
|
```
|
|
|
|
### Maak gegevens met tijdstappen [^1]
|
|
|
|
Voor de SVR transformeer je de invoergegevens naar de vorm `[batch, timesteps]`. Dus, je herschikt de bestaande `train_data` en `test_data` zodat er een nieuwe dimensie is die verwijst naar de tijdstappen.
|
|
|
|
```python
|
|
# Converting to numpy arrays
|
|
train_data = train.values
|
|
test_data = test.values
|
|
```
|
|
|
|
Voor dit voorbeeld nemen we `timesteps = 5`. Dus, de invoer voor het model zijn de gegevens voor de eerste 4 tijdstappen, en de uitvoer zal de gegevens voor de 5e tijdstap zijn.
|
|
|
|
```python
|
|
timesteps=5
|
|
```
|
|
|
|
Converteer trainingsgegevens naar een 2D-tensor met behulp van geneste lijstbegrippen:
|
|
|
|
```python
|
|
train_data_timesteps=np.array([[j for j in train_data[i:i+timesteps]] for i in range(0,len(train_data)-timesteps+1)])[:,:,0]
|
|
train_data_timesteps.shape
|
|
```
|
|
|
|
```output
|
|
(1412, 5)
|
|
```
|
|
|
|
Converteer testgegevens naar een 2D-tensor:
|
|
|
|
```python
|
|
test_data_timesteps=np.array([[j for j in test_data[i:i+timesteps]] for i in range(0,len(test_data)-timesteps+1)])[:,:,0]
|
|
test_data_timesteps.shape
|
|
```
|
|
|
|
```output
|
|
(44, 5)
|
|
```
|
|
|
|
Selecteer invoer en uitvoer uit trainings- en testgegevens:
|
|
|
|
```python
|
|
x_train, y_train = train_data_timesteps[:,:timesteps-1],train_data_timesteps[:,[timesteps-1]]
|
|
x_test, y_test = test_data_timesteps[:,:timesteps-1],test_data_timesteps[:,[timesteps-1]]
|
|
|
|
print(x_train.shape, y_train.shape)
|
|
print(x_test.shape, y_test.shape)
|
|
```
|
|
|
|
```output
|
|
(1412, 4) (1412, 1)
|
|
(44, 4) (44, 1)
|
|
```
|
|
|
|
### Implementeer SVR [^1]
|
|
|
|
Nu is het tijd om SVR te implementeren. Voor meer informatie over deze implementatie kun je [deze documentatie](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html) raadplegen. Voor onze implementatie volgen we deze stappen:
|
|
|
|
1. Definieer het model door `SVR()` aan te roepen en de modelhyperparameters door te geven: kernel, gamma, c en epsilon
|
|
2. Bereid het model voor op de trainingsgegevens door de functie `fit()` aan te roepen
|
|
3. Maak voorspellingen door de functie `predict()` aan te roepen
|
|
|
|
Nu maken we een SVR-model. Hier gebruiken we de [RBF-kernel](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel), en stellen we de hyperparameters gamma, C en epsilon in op respectievelijk 0.5, 10 en 0.05.
|
|
|
|
```python
|
|
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
|
|
```
|
|
|
|
#### Pas het model toe op trainingsgegevens [^1]
|
|
|
|
```python
|
|
model.fit(x_train, y_train[:,0])
|
|
```
|
|
|
|
```output
|
|
SVR(C=10, cache_size=200, coef0=0.0, degree=3, epsilon=0.05, gamma=0.5,
|
|
kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
|
|
```
|
|
|
|
#### Maak modelvoorspellingen [^1]
|
|
|
|
```python
|
|
y_train_pred = model.predict(x_train).reshape(-1,1)
|
|
y_test_pred = model.predict(x_test).reshape(-1,1)
|
|
|
|
print(y_train_pred.shape, y_test_pred.shape)
|
|
```
|
|
|
|
```output
|
|
(1412, 1) (44, 1)
|
|
```
|
|
|
|
Je hebt je SVR gebouwd! Nu moeten we het evalueren.
|
|
|
|
### Evalueer je model [^1]
|
|
|
|
Voor evaluatie schalen we eerst de gegevens terug naar onze originele schaal. Vervolgens, om de prestaties te controleren, plotten we de originele en voorspelde tijdreeksplot en printen we ook het MAPE-resultaat.
|
|
|
|
Schaal de voorspelde en originele uitvoer:
|
|
|
|
```python
|
|
# Scaling the predictions
|
|
y_train_pred = scaler.inverse_transform(y_train_pred)
|
|
y_test_pred = scaler.inverse_transform(y_test_pred)
|
|
|
|
print(len(y_train_pred), len(y_test_pred))
|
|
```
|
|
|
|
```python
|
|
# Scaling the original values
|
|
y_train = scaler.inverse_transform(y_train)
|
|
y_test = scaler.inverse_transform(y_test)
|
|
|
|
print(len(y_train), len(y_test))
|
|
```
|
|
|
|
#### Controleer modelprestaties op trainings- en testgegevens [^1]
|
|
|
|
We halen de tijdstempels uit de dataset om te tonen op de x-as van onze plot. Merk op dat we de eerste ```timesteps-1``` waarden gebruiken als invoer voor de eerste uitvoer, dus de tijdstempels voor de uitvoer beginnen daarna.
|
|
|
|
```python
|
|
train_timestamps = energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)].index[timesteps-1:]
|
|
test_timestamps = energy[test_start_dt:].index[timesteps-1:]
|
|
|
|
print(len(train_timestamps), len(test_timestamps))
|
|
```
|
|
|
|
```output
|
|
1412 44
|
|
```
|
|
|
|
Plot de voorspellingen voor trainingsgegevens:
|
|
|
|
```python
|
|
plt.figure(figsize=(25,6))
|
|
plt.plot(train_timestamps, y_train, color = 'red', linewidth=2.0, alpha = 0.6)
|
|
plt.plot(train_timestamps, y_train_pred, color = 'blue', linewidth=0.8)
|
|
plt.legend(['Actual','Predicted'])
|
|
plt.xlabel('Timestamp')
|
|
plt.title("Training data prediction")
|
|
plt.show()
|
|
```
|
|
|
|

|
|
|
|
Print MAPE voor trainingsgegevens
|
|
|
|
```python
|
|
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
|
|
```
|
|
|
|
```output
|
|
MAPE for training data: 1.7195710200875551 %
|
|
```
|
|
|
|
Plot de voorspellingen voor testgegevens
|
|
|
|
```python
|
|
plt.figure(figsize=(10,3))
|
|
plt.plot(test_timestamps, y_test, color = 'red', linewidth=2.0, alpha = 0.6)
|
|
plt.plot(test_timestamps, y_test_pred, color = 'blue', linewidth=0.8)
|
|
plt.legend(['Actual','Predicted'])
|
|
plt.xlabel('Timestamp')
|
|
plt.show()
|
|
```
|
|
|
|

|
|
|
|
Print MAPE voor testgegevens
|
|
|
|
```python
|
|
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
|
|
```
|
|
|
|
```output
|
|
MAPE for testing data: 1.2623790187854018 %
|
|
```
|
|
|
|
🏆 Je hebt een zeer goed resultaat op de testdataset!
|
|
|
|
### Controleer modelprestaties op volledige dataset [^1]
|
|
|
|
```python
|
|
# Extracting load values as numpy array
|
|
data = energy.copy().values
|
|
|
|
# Scaling
|
|
data = scaler.transform(data)
|
|
|
|
# Transforming to 2D tensor as per model input requirement
|
|
data_timesteps=np.array([[j for j in data[i:i+timesteps]] for i in range(0,len(data)-timesteps+1)])[:,:,0]
|
|
print("Tensor shape: ", data_timesteps.shape)
|
|
|
|
# Selecting inputs and outputs from data
|
|
X, Y = data_timesteps[:,:timesteps-1],data_timesteps[:,[timesteps-1]]
|
|
print("X shape: ", X.shape,"\nY shape: ", Y.shape)
|
|
```
|
|
|
|
```output
|
|
Tensor shape: (26300, 5)
|
|
X shape: (26300, 4)
|
|
Y shape: (26300, 1)
|
|
```
|
|
|
|
```python
|
|
# Make model predictions
|
|
Y_pred = model.predict(X).reshape(-1,1)
|
|
|
|
# Inverse scale and reshape
|
|
Y_pred = scaler.inverse_transform(Y_pred)
|
|
Y = scaler.inverse_transform(Y)
|
|
```
|
|
|
|
```python
|
|
plt.figure(figsize=(30,8))
|
|
plt.plot(Y, color = 'red', linewidth=2.0, alpha = 0.6)
|
|
plt.plot(Y_pred, color = 'blue', linewidth=0.8)
|
|
plt.legend(['Actual','Predicted'])
|
|
plt.xlabel('Timestamp')
|
|
plt.show()
|
|
```
|
|
|
|

|
|
|
|
```python
|
|
print('MAPE: ', mape(Y_pred, Y)*100, '%')
|
|
```
|
|
|
|
```output
|
|
MAPE: 2.0572089029888656 %
|
|
```
|
|
|
|
|
|
|
|
🏆 Zeer mooie plots, die een model met goede nauwkeurigheid laten zien. Goed gedaan!
|
|
|
|
---
|
|
|
|
## 🚀Uitdaging
|
|
|
|
- Probeer de hyperparameters (gamma, C, epsilon) aan te passen bij het maken van het model en evalueer op de gegevens om te zien welke set hyperparameters de beste resultaten geeft op de testgegevens. Voor meer informatie over deze hyperparameters kun je [deze documentatie](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel) raadplegen.
|
|
- Probeer verschillende kernfuncties te gebruiken voor het model en analyseer hun prestaties op de dataset. Een nuttige documentatie is te vinden [hier](https://scikit-learn.org/stable/modules/svm.html#kernel-functions).
|
|
- Probeer verschillende waarden voor `timesteps` te gebruiken zodat het model terugkijkt om voorspellingen te maken.
|
|
|
|
## [Post-lecture quiz](https://ff-quizzes.netlify.app/en/ml/)
|
|
|
|
## Review & Zelfstudie
|
|
|
|
Deze les was bedoeld om de toepassing van SVR voor tijdreeksvoorspelling te introduceren. Voor meer informatie over SVR kun je [deze blog](https://www.analyticsvidhya.com/blog/2020/03/support-vector-regression-tutorial-for-machine-learning/) raadplegen. Deze [documentatie over scikit-learn](https://scikit-learn.org/stable/modules/svm.html) biedt een meer uitgebreide uitleg over SVM's in het algemeen, [SVR's](https://scikit-learn.org/stable/modules/svm.html#regression) en ook andere implementatiedetails zoals de verschillende [kernfuncties](https://scikit-learn.org/stable/modules/svm.html#kernel-functions) die kunnen worden gebruikt, en hun parameters.
|
|
|
|
## Opdracht
|
|
|
|
[Een nieuw SVR-model](assignment.md)
|
|
|
|
|
|
|
|
## Credits
|
|
|
|
|
|
[^1]: De tekst, code en output in deze sectie is bijgedragen door [@AnirbanMukherjeeXD](https://github.com/AnirbanMukherjeeXD)
|
|
[^2]: De tekst, code en output in deze sectie is afkomstig van [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA)
|
|
|
|
---
|
|
|
|
**Disclaimer**:
|
|
Dit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we ons best doen voor nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in zijn oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling. |