Added Support Vector Regressor for Time Series Prediction (#384)

* Create README.md

* Uploaded images

* Create utils.py

* Update README.md

* Update README.md

* Update README.md

* Updated images

* Update README.md

- Added epsilon hyperparameter

* Update README.md

* Update README.md

* Delete utils.py

* Added utils

* Added data

* Create notebook.ipynb

* Update notebook.ipynb

* Update README.md

* Update notebook.ipynb

* Update notebook.ipynb

* Create notebook.ipynb

* Update README.md

Added link to SVR

* Update README.md

* Update README.md

* Update README.md

Credits added

* Update README.md

Credits

* Update README.md

Credits

* Create assignment.md

* Create /translations/README.es.md

* Update README.md

* Update README.md

Review & Self Study added for further reading

* Added questions and answers for quiz on SVR

* Removed duplicates for 'common\utils.py'

Placed one 'common\utils.py' in the folder '7-TimeSeries'

* Removed duplicates of 'data\energy.csv' from SVR

Placed one 'data\energy.csv' in the folder '7-TimeSeries'

* Removed duplicated

* Update notebook.ipynb

* Update README.md

- Changed path of data
- Changed import of common\utils.py
pull/399/head
Anirban Mukherjee 3 years ago committed by GitHub
parent ad1656d884
commit 5ce844f8fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,386 @@
# Time series forecasting with Support Vector Regressor
In the previous lesson, you learned how to use ARIMA model to make time series predictions. Now you'll be looking at Support Vector Regressor model which is a regressor model used to predict continuous data.
## [Pre-lecture quiz](https://white-water-09ec41f0f.azurestaticapps.net/quiz/51/)
## Introduction
In this lesson, you will discover a specific way to build models with [**SVM**: **S**upport **V**ector **M**achine](https://en.wikipedia.org/wiki/Support-vector_machine) for regression, or **SVR: Support Vector Regressor**.
### SVR in the context of time series [^1]
Before understanding the importance of SVR in time series prediction, here are some of the important concepts that you need to know:
- **Regression:** Supervised learning technique to predict continuous values from a given set of inputs. The idea is to fit a curve (or line) in the feature space that has the maximum number of data points. [Click here](https://en.wikipedia.org/wiki/Regression_analysis) for more information.
- **Support Vector Machine (SVM):** A type of supervised machine learning model used for classification, regression and outliers detection. The model is a hyperplane in the feature space, which in case of classification acts as a boundary, and in case of regression acts as the best-fit line. In SVM, a Kernel function is generally used to transform the dataset to a space of higher number of dimensions, so that they can be easily separable. [Click here](https://en.wikipedia.org/wiki/Support-vector_machine) for more information on SVMs.
- **Support Vector Regressor (SVR):** A type of SVM, to find the best fit line (which in the case of SVM is a hyperplane) that has the maximum number of data points.
### Why SVR? [^1]
In the last lesson you learned about ARIMA, which is a very successful statistical linear method to forecast time series data. However, in many cases, time series data have *non-linearity*, which cannot be mapped by linear models. In such cases, the ability of SVM to consider non-linearity in the data for regression tasks makes SVR successful in time series forecasting.
## Exercise - build an SVR model
The first few steps for data preparation are the same as that of the previous lesson on [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA).
Open the _/working_ folder in this lesson and find the _notebook.ipynb_ file.[^2]
1. Run the notebook and import the necessary libraries: [^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. Load the data from the `/data/energy.csv` file into a Pandas dataframe and take a look: [^2]
```python
energy = load_data('../../data')[['load']]
```
3. Plot all the available energy data from January 2012 to 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()
```
![full data](images/full-data.png)
Now, let's build our SVR model.
### Create training and testing datasets
Now your data is loaded, so you can separate it into train and test sets. Then you'll reshape the data to create a time-step based dataset which will be needed for the SVR. You'll train your model on the train set. After the model has finished training, you'll evaluate its accuracy on the training set, testing set and then the full dataset to see the overall performance. You need to ensure that the test set covers a later period in time from the training set to ensure that the model does not gain information from future time periods [^2] (a situation known as *Overfitting*).
1. Allocate a two-month period from September 1 to October 31, 2014 to the training set. The test set will include the two-month period of November 1 to December 31, 2014: [^2]
```python
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
```
2. Visualize the differences: [^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()
```
![training and testing data](images/train-test.png)
### Prepare the data for training
Now, you need to prepare the data for training by performing filtering and scaling of your data. Filter your dataset to only include the time periods and columns you need, and scaling to ensure the data is projected in the interval 0,1.
1. Filter the original dataset to include only the aforementioned time periods per set and only including the needed column 'load' plus the date: [^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. Scale the training data to be in the range (0, 1): [^2]
```python
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
```
4. Now, you scale the testing data: [^2]
```python
test['load'] = scaler.transform(test)
```
### Create data with time-steps [^1]
For the SVR, you transform the input data to be of the form `[batch, timesteps]`. So, you reshape the existing `train_data` and `test_data` such that there is a new dimension which refers to the timesteps.
```python
# Converting to numpy arrays
train_data = train.values
test_data = test.values
```
For this example, we take `timesteps = 5`. So, the inputs to the model are the data for the first 4 timesteps, and the output will be the data for the 5th timestep.
```python
timesteps=5
```
Converting training data to 2D tensor using nested list comprehension:
```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)
```
Converting testing data to 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)
```
Selecting inputs and outputs from training and testing data:
```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)
```
### Implement SVR [^1]
Now, it's time to implement SVR. To read more about this implementation, you can refer to [this documentation](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html). For our implementation, we follow these steps:
1. Define the model by calling `SVR()` and passing in the model hyperparameters: kernel, gamma, c and epsilon
2. Prepare the model for the training data by calling the `fit()` function
3. Make predictions calling the `predict()` function
Now we create an SVR model. Here we use the [RBF kernel](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel), and set the hyperparameters gamma, C and epsilon as 0.5, 10 and 0.05 respectively.
```python
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
```
#### Fit the model on training data [^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)
```
#### Make model predictions [^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)
```
You've built your SVR! Now we need to evaluate it.
### Evaluate your model [^1]
For evaluation, first we will scale back the data to our original scale. Then, to check the performance, we will plot the original and predicted time series plot, and also print the MAPE result.
Scale the predicted and original output:
```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))
```
#### Check model performance on training and testing data [^1]
We extract the timestamps from the dataset to show in the x-axis of our plot. Note that we are using the first ```timesteps-1``` values as out input for the first output, so the timestamps for the output will start after that.
```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 the predictions for training data:
```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()
```
![training data prediction](images/train-data-predict.png)
Print MAPE for training data
```python
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
```
```output
MAPE for training data: 1.7195710200875551 %
```
Plot the predictions for testing data
```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()
```
![testing data prediction](images/test-data-predict.png)
Print MAPE for testing data
```python
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
```
```output
MAPE for testing data: 1.2623790187854018 %
```
🏆 You have a very good result on the testing dataset!
### Check model performance on full 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()
```
![full data prediction](images/full-data-predict.png)
```python
print('MAPE: ', mape(Y_pred, Y)*100, '%')
```
```output
MAPE: 2.0572089029888656 %
```
🏆 Very nice plots, showing a model with good accuracy. Well done!
---
## 🚀Challenge
- Try to tweak the hyperparameters (gamma, C, epsilon) while creating the model and evaluate on the data to see which set of hyperparameters give the best results on the testing data. To know more about these hyperparameters, you can refer to the document [here](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel).
- Try to use different kernel functions for the model and analyze their performances on the dataset. A helpful document can be found [here](https://scikit-learn.org/stable/modules/svm.html#kernel-functions).
- Try using different values for `timesteps` for the model to look back to make prediction.
## [Post-lecture quiz](https://white-water-09ec41f0f.azurestaticapps.net/quiz/52/)
## Review & Self Study
This lesson was to introduce the application of SVR for Time Series Forecasting. To read more about SVR, you can refer to [this blog](https://www.analyticsvidhya.com/blog/2020/03/support-vector-regression-tutorial-for-machine-learning/). This [documentation on scikit-learn](https://scikit-learn.org/stable/modules/svm.html) provides a more comprehensive explanation about SVMs in general, [SVRs](https://scikit-learn.org/stable/modules/svm.html#regression) and also other implementation details such as the different [kernel functions](https://scikit-learn.org/stable/modules/svm.html#kernel-functions) that can be used, and their parameters.
## Assignment
[A new SVR model](assignment.md)
## Credits
[^1]: The text, code and output in this section was contributed by [@AnirbanMukherjeeXD](https://github.com/AnirbanMukherjeeXD)
[^2]: The text, code and output in this section was taken from [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA)

@ -0,0 +1,14 @@
# A new SVR model
## Instructions [^1]
Now that you have built an SVR model, build a new one with fresh data (try one of [these datasets from Duke](http://www2.stat.duke.edu/~mw/ts_data_sets.html). Annotate your work in a notebook, visualize the data and your model, and test its accuracy using appropriate plots and MAPE. Also try tweaking the different hyperparameters and also using different values for the timesteps.
## Rubric [^1]
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | ------------------------------------------------------------ | --------------------------------------------------------- | ----------------------------------- |
| | A notebook is presented with an SVR model built, tested and explained with visualizations and accuracy stated. | The notebook presented is not annotated or contains bugs. | An incomplete notebook is presented |
[^1]:The text in this section was based on the [assignment from ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA/assignment.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

File diff suppressed because one or more lines are too long

@ -0,0 +1,698 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "fv9OoQsMFk5A"
},
"source": [
"# Time series prediction using Support Vector Regressor"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this notebook, we demonstrate how to:\n",
"\n",
"- prepare 2D time series data for training an SVM regressor model\n",
"- implement SVR using RBF kernel\n",
"- evaluate the model using plots and MAPE"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Importing modules"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../../')"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"id": "M687KNlQFp0-"
},
"outputs": [],
"source": [
"import os\n",
"import warnings\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import pandas as pd\n",
"import datetime as dt\n",
"import math\n",
"\n",
"from sklearn.svm import SVR\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from common.utils import load_data, mape"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Cj-kfVdMGjWP"
},
"source": [
"## Preparing data"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8fywSjC6GsRz"
},
"source": [
"### Load data"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 363
},
"id": "aBDkEB11Fumg",
"outputId": "99cf7987-0509-4b73-8cc2-75d7da0d2740"
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>load</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2012-01-01 00:00:00</th>\n",
" <td>2698.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 01:00:00</th>\n",
" <td>2558.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 02:00:00</th>\n",
" <td>2444.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 03:00:00</th>\n",
" <td>2402.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 04:00:00</th>\n",
" <td>2403.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" load\n",
"2012-01-01 00:00:00 2698.0\n",
"2012-01-01 01:00:00 2558.0\n",
"2012-01-01 02:00:00 2444.0\n",
"2012-01-01 03:00:00 2402.0\n",
"2012-01-01 04:00:00 2403.0"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"energy = load_data('../../data')[['load']]\n",
"energy.head(5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "O0BWP13rGnh4"
},
"source": [
"### Plot the data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 486
},
"id": "hGaNPKu_Gidk",
"outputId": "7f89b326-9057-4f49-efbe-cb100ebdf76d"
},
"outputs": [],
"source": [
"energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)\n",
"plt.xlabel('timestamp', fontsize=12)\n",
"plt.ylabel('load', fontsize=12)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "IPuNor4eGwYY"
},
"source": [
"### Create training and testing data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ysvsNyONGt0Q"
},
"outputs": [],
"source": [
"train_start_dt = '2014-11-01 00:00:00'\n",
"test_start_dt = '2014-12-30 00:00:00'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 548
},
"id": "SsfdLoPyGy9w",
"outputId": "d6d6c25b-b1f4-47e5-91d1-707e043237d7"
},
"outputs": [],
"source": [
"energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \\\n",
" .join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \\\n",
" .plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)\n",
"plt.xlabel('timestamp', fontsize=12)\n",
"plt.ylabel('load', fontsize=12)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XbFTqBw6G1Ch"
},
"source": [
"### Preparing data for training"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, you need to prepare the data for training by performing filtering and scaling of your data."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cYivRdQpHDj3",
"outputId": "a138f746-461c-4fd6-bfa6-0cee094c4aa1"
},
"outputs": [],
"source": [
"train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]\n",
"test = energy.copy()[energy.index >= test_start_dt][['load']]\n",
"\n",
"print('Training data shape: ', train.shape)\n",
"print('Test data shape: ', test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Scale the data to be in the range (0, 1)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 363
},
"id": "3DNntGQnZX8G",
"outputId": "210046bc-7a66-4ccd-d70d-aa4a7309949c"
},
"outputs": [],
"source": [
"scaler = MinMaxScaler()\n",
"train['load'] = scaler.fit_transform(train)\n",
"train.head(5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 206
},
"id": "26Yht-rzZexe",
"outputId": "20326077-a38a-4e78-cc5b-6fd7af95d301"
},
"outputs": [],
"source": [
"test['load'] = scaler.transform(test)\n",
"test.head(5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "x0n6jqxOQ41Z"
},
"source": [
"### Creating data with time-steps"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fdmxTZtOQ8xs"
},
"source": [
" For our SVR, we transform the input data to be of the form `[batch, timesteps]`. So, we reshape the existing `train_data` and `test_data` such that there is a new dimension which refers to the timesteps. For our example, we take `timesteps = 5`. So, the inputs to the model are the data for the first 4 timesteps, and the output will be the data for the 5<sup>th</sup> timestep."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Rpju-Sc2HFm0"
},
"outputs": [],
"source": [
"# Converting to numpy arrays\n",
"\n",
"train_data = train.values\n",
"test_data = test.values"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Selecting the timesteps\n",
"\n",
"timesteps=None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "O-JrsrsVJhUQ",
"outputId": "c90dbe71-bacc-4ec4-b452-f82fe5aefaef"
},
"outputs": [],
"source": [
"# Converting data to 2D tensor\n",
"\n",
"train_data_timesteps=None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "exJD8AI7KE4g",
"outputId": "ce90260c-f327-427d-80f2-77307b5a6318"
},
"outputs": [],
"source": [
"# Converting test data to 2D tensor\n",
"\n",
"test_data_timesteps=None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2u0R2sIsLuq5"
},
"outputs": [],
"source": [
"x_train, y_train = None\n",
"x_test, y_test = None\n",
"\n",
"print(x_train.shape, y_train.shape)\n",
"print(x_test.shape, y_test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8wIPOtAGLZlh"
},
"source": [
"## Creating SVR model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EhA403BEPEiD"
},
"outputs": [],
"source": [
"# Create model using RBF kernel\n",
"\n",
"model = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GS0UA3csMbqp",
"outputId": "d86b6f05-5742-4c1d-c2db-c40510bd4f0d"
},
"outputs": [],
"source": [
"# Fit model on training data"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Rz_x8S3UrlcF"
},
"source": [
"### Make model prediction"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XR0gnt3MnuYS",
"outputId": "157e40ab-9a23-4b66-a885-0d52a24b2364"
},
"outputs": [],
"source": [
"# Making predictions\n",
"\n",
"y_train_pred = None\n",
"y_test_pred = None"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "_2epncg-SGzr"
},
"source": [
"## Analyzing model performance"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Scaling the predictions\n",
"\n",
"y_train_pred = scaler.inverse_transform(y_train_pred)\n",
"y_test_pred = scaler.inverse_transform(y_test_pred)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xmm_YLXhq7gV",
"outputId": "18392f64-4029-49ac-c71a-a4e2411152a1"
},
"outputs": [],
"source": [
"# Scaling the original values\n",
"\n",
"y_train = scaler.inverse_transform(y_train)\n",
"y_test = scaler.inverse_transform(y_test)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "u3LBj93coHEi",
"outputId": "d4fd49e8-8c6e-4bb0-8ef9-ca0b26d725b4"
},
"outputs": [],
"source": [
"# Extract the timesteps for x-axis\n",
"\n",
"train_timestamps = None\n",
"test_timestamps = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(25,6))\n",
"# plot original output\n",
"# plot predicted output\n",
"plt.legend(['Actual','Predicted'])\n",
"plt.xlabel('Timestamp')\n",
"plt.title(\"Training data prediction\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LnhzcnYtXHCm",
"outputId": "f5f0d711-f18b-4788-ad21-d4470ea2c02b"
},
"outputs": [],
"source": [
"print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 225
},
"id": "53Q02FoqQH4V",
"outputId": "53e2d59b-5075-4765-ad9e-aed56c966583"
},
"outputs": [],
"source": [
"plt.figure(figsize=(10,3))\n",
"# plot original output\n",
"# plot predicted output\n",
"plt.legend(['Actual','Predicted'])\n",
"plt.xlabel('Timestamp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "clOAUH-SXCJG",
"outputId": "a3aa85ff-126a-4a4a-cd9e-90b9cc465ef5"
},
"outputs": [],
"source": [
"print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "DHlKvVCId5ue"
},
"source": [
"## Full dataset prediction"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cOFJ45vreO0N",
"outputId": "35628e33-ecf9-4966-8036-f7ea86db6f16"
},
"outputs": [],
"source": [
"# Extracting load values as numpy array\n",
"data = None\n",
"\n",
"# Scaling\n",
"data = None\n",
"\n",
"# Transforming to 2D tensor as per model input requirement\n",
"data_timesteps=None\n",
"\n",
"# Selecting inputs and outputs from data\n",
"X, Y = None, None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ESSAdQgwexIi"
},
"outputs": [],
"source": [
"# Make model predictions\n",
"\n",
"# Inverse scale and reshape\n",
"Y_pred = None\n",
"Y = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 328
},
"id": "M_qhihN0RVVX",
"outputId": "a89cb23e-1d35-437f-9d63-8b8907e12f80"
},
"outputs": [],
"source": [
"plt.figure(figsize=(30,8))\n",
"# plot original output\n",
"# plot predicted output\n",
"plt.legend(['Actual','Predicted'])\n",
"plt.xlabel('Timestamp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "AcN7pMYXVGTK",
"outputId": "7e1c2161-47ce-496c-9d86-7ad9ae0df770"
},
"outputs": [],
"source": [
"print('MAPE: ', mape(Y_pred, Y)*100, '%')"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"collapsed_sections": [],
"name": "Recurrent_Neural_Networks.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

@ -16,6 +16,7 @@ Photo by <a href="https://unsplash.com/@shutter_log?utm_source=unsplash&utm_medi
1. [Introduction to time series forecasting](1-Introduction/README.md)
2. [Building ARIMA time series models](2-ARIMA/README.md)
3. [Building Support Vector Regressor for time series forcasting](3-SVR/README.md)
## Credits

@ -0,0 +1,147 @@
import numpy as np
import pandas as pd
import os
from collections import UserDict
def load_data(data_dir):
"""Load the GEFCom 2014 energy load data"""
energy = pd.read_csv(os.path.join(data_dir, 'energy.csv'), parse_dates=['timestamp'])
# Reindex the dataframe such that the dataframe has a record for every time point
# between the minimum and maximum timestamp in the time series. This helps to
# identify missing time periods in the data (there are none in this dataset).
energy.index = energy['timestamp']
energy = energy.reindex(pd.date_range(min(energy['timestamp']),
max(energy['timestamp']),
freq='H'))
energy = energy.drop('timestamp', axis=1)
return energy
def mape(predictions, actuals):
"""Mean absolute percentage error"""
predictions = np.array(predictions)
actuals = np.array(actuals)
return (np.absolute(predictions - actuals) / actuals).mean()
def create_evaluation_df(predictions, test_inputs, H, scaler):
"""Create a data frame for easy evaluation"""
eval_df = pd.DataFrame(predictions, columns=['t+'+str(t) for t in range(1, H+1)])
eval_df['timestamp'] = test_inputs.dataframe.index
eval_df = pd.melt(eval_df, id_vars='timestamp', value_name='prediction', var_name='h')
eval_df['actual'] = np.transpose(test_inputs['target']).ravel()
eval_df[['prediction', 'actual']] = scaler.inverse_transform(eval_df[['prediction', 'actual']])
return eval_df
class TimeSeriesTensor(UserDict):
"""A dictionary of tensors for input into the RNN model.
Use this class to:
1. Shift the values of the time series to create a Pandas dataframe containing all the data
for a single training example
2. Discard any samples with missing values
3. Transform this Pandas dataframe into a numpy array of shape
(samples, time steps, features) for input into Keras
The class takes the following parameters:
- **dataset**: original time series
- **target** name of the target column
- **H**: the forecast horizon
- **tensor_structures**: a dictionary describing the tensor structure of the form
{ 'tensor_name' : (range(max_backward_shift, max_forward_shift), [feature, feature, ...] ) }
if features are non-sequential and should not be shifted, use the form
{ 'tensor_name' : (None, [feature, feature, ...])}
- **freq**: time series frequency (default 'H' - hourly)
- **drop_incomplete**: (Boolean) whether to drop incomplete samples (default True)
"""
def __init__(self, dataset, target, H, tensor_structure, freq='H', drop_incomplete=True):
self.dataset = dataset
self.target = target
self.tensor_structure = tensor_structure
self.tensor_names = list(tensor_structure.keys())
self.dataframe = self._shift_data(H, freq, drop_incomplete)
self.data = self._df2tensors(self.dataframe)
def _shift_data(self, H, freq, drop_incomplete):
# Use the tensor_structures definitions to shift the features in the original dataset.
# The result is a Pandas dataframe with multi-index columns in the hierarchy
# tensor - the name of the input tensor
# feature - the input feature to be shifted
# time step - the time step for the RNN in which the data is input. These labels
# are centred on time t. the forecast creation time
df = self.dataset.copy()
idx_tuples = []
for t in range(1, H+1):
df['t+'+str(t)] = df[self.target].shift(t*-1, freq=freq)
idx_tuples.append(('target', 'y', 't+'+str(t)))
for name, structure in self.tensor_structure.items():
rng = structure[0]
dataset_cols = structure[1]
for col in dataset_cols:
# do not shift non-sequential 'static' features
if rng is None:
df['context_'+col] = df[col]
idx_tuples.append((name, col, 'static'))
else:
for t in rng:
sign = '+' if t > 0 else ''
shift = str(t) if t != 0 else ''
period = 't'+sign+shift
shifted_col = name+'_'+col+'_'+period
df[shifted_col] = df[col].shift(t*-1, freq=freq)
idx_tuples.append((name, col, period))
df = df.drop(self.dataset.columns, axis=1)
idx = pd.MultiIndex.from_tuples(idx_tuples, names=['tensor', 'feature', 'time step'])
df.columns = idx
if drop_incomplete:
df = df.dropna(how='any')
return df
def _df2tensors(self, dataframe):
# Transform the shifted Pandas dataframe into the multidimensional numpy arrays. These
# arrays can be used to input into the keras model and can be accessed by tensor name.
# For example, for a TimeSeriesTensor object named "model_inputs" and a tensor named
# "target", the input tensor can be acccessed with model_inputs['target']
inputs = {}
y = dataframe['target']
y = y.as_matrix()
inputs['target'] = y
for name, structure in self.tensor_structure.items():
rng = structure[0]
cols = structure[1]
tensor = dataframe[name][cols].as_matrix()
if rng is None:
tensor = tensor.reshape(tensor.shape[0], len(cols))
else:
tensor = tensor.reshape(tensor.shape[0], len(cols), len(rng))
tensor = np.transpose(tensor, axes=[0, 2, 1])
inputs[name] = tensor
return inputs
def subset_data(self, new_dataframe):
# Use this function to recreate the input tensors if the shifted dataframe
# has been filtered.
self.dataframe = new_dataframe
self.data = self._df2tensors(self.dataframe)

File diff suppressed because it is too large Load Diff

@ -2809,6 +2809,120 @@
]
}
]
},
{
"id": 51,
"title": "Time Series SVR: Pre-Lecture Quiz",
"quiz": [
{
"questionText": "SVM stands for",
"answerOptions": [
{
"answerText": "Statistical Vector Machine",
"isCorrect": "false"
},
{
"answerText": "Support Vector Machine",
"isCorrect": "true"
},
{
"answerText": "Statistical Vector Model",
"isCorrect": "false"
}
]
},
{
"questionText": "Which of these ML techniques is used to predict continuous values?",
"answerOptions": [
{
"answerText": "Clustering",
"isCorrect": "false"
},
{
"answerText": "Classification",
"isCorrect": "false"
},
{
"answerText": "Regression",
"isCorrect": "true"
}
]
},
{
"questionText": "Which of these models is popularly used for time series forecasting?",
"answerOptions": [
{
"answerText": "ARIMA",
"isCorrect": "true"
},
{
"answerText": "K-Means Clustering",
"isCorrect": "false"
},
{
"answerText": "Logistic Regression",
"isCorrect": "false"
}
]
}
]
},
{
"id": 52,
"title": "Time Series SVR: Post-Lecture Quiz",
"quiz": [
{
"questionText": "By which of these methods does an SVR learn?",
"answerOptions": [
{
"answerText": "Finding the best fit hyperplane that has the maximum number of data points",
"isCorrect": "true"
},
{
"answerText": "Learning the probability distribution of the dataset",
"isCorrect": "false"
},
{
"answerText": "Finding clusters in the dataset",
"isCorrect": "false"
}
]
},
{
"questionText": "What is the purpose of a kernel in SVMs?",
"answerOptions": [
{
"answerText": "To measure the accuracy of the model predictions",
"isCorrect": "false"
},
{
"answerText": "To transform the dataset to a higher dimension space",
"isCorrect": "true"
},
{
"answerText": "To standardize the values of the dataset",
"isCorrect": "false"
}
]
},
{
"questionText": "Which of these models consider the non-linearity in the dataset?",
"answerOptions": [
{
"answerText": "Simple Linear Regression",
"isCorrect": "false"
},
{
"answerText": "ARIMA",
"isCorrect": "false"
},
{
"answerText": "SVR using RBF kernel",
"isCorrect": "true"
}
]
}
]
}
]
}

Loading…
Cancel
Save