#
Introduction to Time Series Forecasting with Python
By Prof. Angel Colmenares
The goal of this codes is to show you how to get results on univariate time series forecasting problems using the Python ecosystem. This goal cannot be achieved until you apply the lessons from this book on your own projects and get results. This is a guidebook or a cookbook designed for immediate use
Quarto enables you to weave together content and executable code into a finished document. To learn more about Quarto see https://quarto.org.
Chapter I traditional models on Python
Index
1.1 Basics concepts:
Create a rolling mean feature, statistics feature
Create expanding window features
Create a line plot, dot plot, stacked line plots, histogram plot, density plot
1.2 Plots of:
Box and Whisker Plots
Heat Maps
Lag Scatter Plots
Autocorrelation Plots
1.3 Resampling and Interpolation, Upsampling and Downsampling Data
1.4 Power Transforms, Square Root Transform, Log Transform, Box-Cox Transform
1.5 Moving Average Smoothing , Introduction to White Noise, Random Walk
1.6 Decompose Time Series Data
1.7 Use and Remove Trends, Seasonality , Stationarity in Time Series
1.8 Data Backtest Forecast Models, Forecasting Performance Measures
1.9 Persistence Model for Forecasting
1.10 Autoregression Models for Forecasting
1.11 Visualize Residual Forecast Errors
Chapter II Time Series Forecasting Using Generative AI: Leveraging AI for Precision Forecasting on Python
2.1 Multilayer Perceptron (MLP)
2.2 Temporal Convolutional Networks (TCN)
2.3 Bidirectional Temporal Convolutional Network (BiTCN)
2.4 Recurrent Neural Network (RNN)
2.5 Long Short-Term Memory (LSTM)
2.6 Neural Networks Based on Autoregression (DeepAR)
2.7 Neural Basis Expansion Analysis (NBEATS)
2.8 Transformers for Time Series
Vanilla Transformer
Inverted Transformers
2.9 DLinear
2.10 NLinear
2.11 Patch Time Series Transformer (PatchTST)
2.12 Reprogramming Large Language Model (Time-LLM)
Basics concepts:
#!pip install
from pandas import read_csv
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series print(type(series))
<class 'pandas.core.series.Series'>
print(series.head(10))
Date
1959-01-01 35
1959-01-02 32
1959-01-03 30
1959-01-04 31
1959-01-05 44
1959-01-06 29
1959-01-07 45
1959-01-08 43
1959-01-09 38
1959-01-10 27
Name: Births, dtype: int64
print(series.size)
365
print(series['1959-01'])
Date
1959-01-01 35
1959-01-02 32
1959-01-03 30
1959-01-04 31
1959-01-05 44
1959-01-06 29
1959-01-07 45
1959-01-08 43
1959-01-09 38
1959-01-10 27
1959-01-11 38
1959-01-12 33
1959-01-13 55
1959-01-14 47
1959-01-15 45
1959-01-16 37
1959-01-17 50
1959-01-18 43
1959-01-19 41
1959-01-20 52
1959-01-21 34
1959-01-22 53
1959-01-23 39
1959-01-24 32
1959-01-25 37
1959-01-26 43
1959-01-27 39
1959-01-28 35
1959-01-29 44
1959-01-30 38
1959-01-31 24
Name: Births, dtype: int64
print(series.describe())
count 365.000000
mean 41.980822
std 7.348257
min 23.000000
25% 37.000000
50% 42.000000
75% 46.000000
max 73.000000
Name: Births, dtype: float64
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
= read_csv('daily-minimum-temperatures.csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= DataFrame()
dataframe 'month'] = [series.index[i].month for i in range(len(series))]
dataframe['day'] = [series.index[i].day for i in range(len(series))]
dataframe['temperature'] = [series[i] for i in range(len(series))] dataframe[
<string>:1: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
print(dataframe.head(5))
month day temperature
0 1 1 20.7
1 1 2 17.9
2 1 3 18.8
3 1 4 14.6
4 1 5 15.8
= DataFrame(series.values)
temps = concat([temps.shift(3), temps.shift(2), temps.shift(1), temps], axis=1)
dataframe = ['t-2', 't-1', 't', 't+1']
dataframe.columns print(dataframe.head(5))
t-2 t-1 t t+1
0 NaN NaN NaN 20.7
1 NaN NaN 20.7 17.9
2 NaN 20.7 17.9 18.8
3 20.7 17.9 18.8 14.6
4 17.9 18.8 14.6 15.8
# create a rolling mean feature
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
= read_csv('daily-minimum-temperatures.csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= DataFrame(series.values)
temps = temps.shift(1)
shifted = shifted.rolling(window=2)
window = window.mean()
means = concat([means, temps], axis=1)
dataframe = ['mean(t-1,t)', 't+1']
dataframe.columns print(dataframe.head(5))
mean(t-1,t) t+1
0 NaN 20.7
1 NaN 17.9
2 19.30 18.8
3 18.35 14.6
4 16.70 15.8
= DataFrame(series.values)
temps
# create rolling statistics feature
= 3
width = temps.shift(width - 1)
shifted = shifted.rolling(window=width)
window = concat([window.min(), window.mean(), window.max(), temps], axis=1)
dataframe = ['min', 'mean', 'max', 't+1']
dataframe.columns print(dataframe.head(5))
min mean max t+1
0 NaN NaN NaN 20.7
1 NaN NaN NaN 17.9
2 NaN NaN NaN 18.8
3 NaN NaN NaN 14.6
4 17.9 19.133333 20.7 15.8
# create expanding window features
= temps.expanding()
window = concat([window.min(), window.mean(), window.max(), temps.shift(-1)], axis=1)
dataframe = ['min', 'mean', 'max', 't+1']
dataframe.columns print(dataframe.head(5))
min mean max t+1
0 20.7 20.700000 20.7 17.9
1 17.9 19.300000 20.7 18.8
2 17.9 19.133333 20.7 14.6
3 14.6 18.000000 20.7 15.8
4 14.6 17.560000 20.7 15.8
# create a line plot
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates
series.plot() pyplot.show()
# create a dot plot
='k.')
series.plot(style pyplot.show()
# create stacked line plots
from pandas import read_csv
from pandas import DataFrame
from pandas import Grouper
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.groupby(Grouper(freq='Y'))
groups = DataFrame()
years for name, group in groups:
= group.values
years[name.year] =True, legend=False) years.plot(subplots
array([<Axes: >, <Axes: >, <Axes: >, <Axes: >, <Axes: >, <Axes: >,
<Axes: >, <Axes: >, <Axes: >, <Axes: >], dtype=object)
pyplot.show()
pyplot.close()
# create a histogram plot
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates
series.hist() pyplot.show()
pyplot.close()
# create a density plot
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates='kde')
series.plot(kind pyplot.show()
pyplot.close()
## 6.5 Box and Whisker Plots by Interval
# create a boxplot of yearly data
from pandas import read_csv
from pandas import DataFrame
from pandas import Grouper
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.groupby(Grouper(freq='Y'))
groups = DataFrame()
years for name, group in groups:
= group.values
years[name.year]
years.boxplot() pyplot.show()
pyplot.close()
# create a boxplot of monthly data
from pandas import read_csv
from pandas import DataFrame
from pandas import Grouper
from matplotlib import pyplot
from pandas import concat
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series['1990']
one_year = one_year.groupby(Grouper(freq='M'))
groups = concat([DataFrame(x[1].values) for x in groups], axis=1)
months = DataFrame(months)
months = range(1,13)
months.columns
months.boxplot() pyplot.show()
pyplot.close()
## 6.6 Heat Maps
# create a heat map of yearly data
from pandas import read_csv
from pandas import DataFrame
from pandas import Grouper
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.groupby(Grouper(freq='Y'))
groups = DataFrame()
years for name, group in groups:
= group.values
years[name.year] = years.T
years =None, aspect='auto')
pyplot.matshow(years, interpolation pyplot.show()
pyplot.close()
# create a heat map of monthly data
from pandas import read_csv
from pandas import DataFrame
from pandas import Grouper
from matplotlib import pyplot
from pandas import concat
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series['1990']
one_year = one_year.groupby(Grouper(freq='M'))
groups = concat([DataFrame(x[1].values) for x in groups], axis=1)
months = DataFrame(months)
months = range(1,13)
months.columns =None, aspect='auto')
pyplot.matshow(months, interpolation pyplot.show()
pyplot.close()
## 6.7 Lag Scatter Plots
# create a scatter plot
from pandas import read_csv
from matplotlib import pyplot
from pandas.plotting import lag_plot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates
lag_plot(series) pyplot.show()
# create multiple scatter plots
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= DataFrame(series.values)
values = 7
lags = [values]
columns for i in range(1,(lags + 1)):
columns.append(values.shift(i))= concat(columns, axis=1)
dataframe = ['t']
columns for i in range(1,(lags + 1)):
't-' + str(i))
columns.append(= columns
dataframe.columns 1)
pyplot.figure(for i in range(1,(lags + 1)):
= pyplot.subplot(240 + i)
ax 't vs t-' + str(i))
ax.set_title(=dataframe['t'].values, y=dataframe['t-'+str(i)].values)
pyplot.scatter(x pyplot.show()
## 6.8 Autocorrelation Plots
# create an autocorrelation plot
from pandas import read_csv
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates
autocorrelation_plot(series) pyplot.show()
pyplot.close()
### Chapter 7 Resampling and Interpolation
## 7.3 Upsampling Data
# upsample to daily intervals
from pandas import read_csv
from datetime import datetime
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:1: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
= series.resample('D').mean()
upsampled print(upsampled.head(32))
Month
1901-01-01 266.0
1901-01-02 NaN
1901-01-03 NaN
1901-01-04 NaN
1901-01-05 NaN
1901-01-06 NaN
1901-01-07 NaN
1901-01-08 NaN
1901-01-09 NaN
1901-01-10 NaN
1901-01-11 NaN
1901-01-12 NaN
1901-01-13 NaN
1901-01-14 NaN
1901-01-15 NaN
1901-01-16 NaN
1901-01-17 NaN
1901-01-18 NaN
1901-01-19 NaN
1901-01-20 NaN
1901-01-21 NaN
1901-01-22 NaN
1901-01-23 NaN
1901-01-24 NaN
1901-01-25 NaN
1901-01-26 NaN
1901-01-27 NaN
1901-01-28 NaN
1901-01-29 NaN
1901-01-30 NaN
1901-01-31 NaN
1901-02-01 145.9
Freq: D, Name: Sales, dtype: float64
# upsample to daily intervals with linear interpolation
from pandas import read_csv
from datetime import datetime
from matplotlib import pyplot
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:1: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
= series.resample('D').mean()
upsampled = upsampled.interpolate(method='linear')
interpolated print(interpolated.head(32))
Month
1901-01-01 266.000000
1901-01-02 262.125806
1901-01-03 258.251613
1901-01-04 254.377419
1901-01-05 250.503226
1901-01-06 246.629032
1901-01-07 242.754839
1901-01-08 238.880645
1901-01-09 235.006452
1901-01-10 231.132258
1901-01-11 227.258065
1901-01-12 223.383871
1901-01-13 219.509677
1901-01-14 215.635484
1901-01-15 211.761290
1901-01-16 207.887097
1901-01-17 204.012903
1901-01-18 200.138710
1901-01-19 196.264516
1901-01-20 192.390323
1901-01-21 188.516129
1901-01-22 184.641935
1901-01-23 180.767742
1901-01-24 176.893548
1901-01-25 173.019355
1901-01-26 169.145161
1901-01-27 165.270968
1901-01-28 161.396774
1901-01-29 157.522581
1901-01-30 153.648387
1901-01-31 149.774194
1901-02-01 145.900000
Freq: D, Name: Sales, dtype: float64
interpolated.plot() pyplot.show()
pyplot.close()
## 7.4 Downsampling Data
# downsample to quarterly intervals
from pandas import read_csv
from datetime import datetime
from matplotlib import pyplot
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:1: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
= series.resample('Q')
resample = resample.mean()
quarterly_mean_sales print(quarterly_mean_sales.head())
Month
1901-03-31 198.333333
1901-06-30 156.033333
1901-09-30 216.366667
1901-12-31 215.100000
1902-03-31 184.633333
Freq: Q-DEC, Name: Sales, dtype: float64
quarterly_mean_sales.plot() pyplot.show()
pyplot.close()
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:2: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
= series.resample('Y')
resample = resample.sum()
yearly_mean_sales print(yearly_mean_sales.head())
Month
1901-12-31 2357.5
1902-12-31 3153.5
1903-12-31 5742.6
Freq: A-DEC, Name: Sales, dtype: float64
yearly_mean_sales.plot() pyplot.show()
pyplot.close()
### Chapter 8 Power Transforms
## 8.1 Airline Passengers Dataset
# load and plot a time series
from pandas import read_csv
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series 1)
pyplot.figure(# line plot
211)
pyplot.subplot(
pyplot.plot(series)# histogram
212)
pyplot.subplot(
pyplot.hist(series) pyplot.show()
pyplot.close()
## 8.2 Square Root Transform
# contrive a quadratic time series
from matplotlib import pyplot
= [i**2 for i in range(1,100)]
series 1)
pyplot.figure(# line plot
211)
pyplot.subplot(
pyplot.plot(series)# histogram
212)
pyplot.subplot(
pyplot.hist(series) pyplot.show()
pyplot.close()
# square root transform a contrived quadratic time series
from matplotlib import pyplot
from numpy import sqrt
= [i**2 for i in range(1,100)]
series # sqrt transform
= series = sqrt(series)
transform 1)
pyplot.figure(# line plot
211)
pyplot.subplot(
pyplot.plot(transform)# histogram
212)
pyplot.subplot(
pyplot.hist(transform) pyplot.show()
pyplot.close()
# square root transform a time series
from pandas import read_csv
from pandas import DataFrame
from numpy import sqrt
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = DataFrame(series.values)
dataframe = ['passengers']
dataframe.columns 'passengers'] = sqrt(dataframe['passengers'])
dataframe[1)
pyplot.figure(# line plot
211)
pyplot.subplot('passengers'])
pyplot.plot(dataframe[# histogram
212)
pyplot.subplot('passengers'])
pyplot.hist(dataframe[ pyplot.show()
pyplot.close()
## 8.3 Log Transform
# create and plot an exponential time series
from matplotlib import pyplot
from math import exp
= [exp(i) for i in range(1,100)]
series 1)
pyplot.figure(# line plot
211)
pyplot.subplot(
pyplot.plot(series)# histogram
212)
pyplot.subplot(
pyplot.hist(series) pyplot.show()
pyplot.close()
# log transform a contrived exponential time series
from matplotlib import pyplot
from math import exp
from numpy import log
= [exp(i) for i in range(1,100)]
series = log(series)
transform 1)
pyplot.figure(# line plot
211)
pyplot.subplot(
pyplot.plot(transform)# histogram
212)
pyplot.subplot(
pyplot.hist(transform) pyplot.show()
pyplot.close()
# log transform a time series
from pandas import read_csv
from pandas import DataFrame
from numpy import log
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = DataFrame(series.values)
dataframe = ['passengers']
dataframe.columns 'passengers'] = log(dataframe['passengers'])
dataframe[1)
pyplot.figure(# line plot
211)
pyplot.subplot('passengers'])
pyplot.plot(dataframe[# histogram
212)
pyplot.subplot('passengers'])
pyplot.hist(dataframe[ pyplot.show()
pyplot.close()
## 8.4 Box-Cox Transform
# manually box-cox transform a time series
from pandas import read_csv
from pandas import DataFrame
from scipy.stats import boxcox
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = DataFrame(series.values)
dataframe = ['passengers']
dataframe.columns 'passengers'] = boxcox(dataframe['passengers'], lmbda=0.0)
dataframe[1)
pyplot.figure(# line plot
211)
pyplot.subplot('passengers'])
pyplot.plot(dataframe[# histogram
212)
pyplot.subplot('passengers'])
pyplot.hist(dataframe[ pyplot.show()
pyplot.close()
# automatically box-cox transform a time series
from pandas import read_csv
from pandas import DataFrame
from scipy.stats import boxcox
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = DataFrame(series.values)
dataframe = ['passengers']
dataframe.columns 'passengers'], lam = boxcox(dataframe['passengers'])
dataframe[print('Lambda: %f' % lam)
Lambda: 0.148023
1)
pyplot.figure(# line plot
211)
pyplot.subplot('passengers'])
pyplot.plot(dataframe[# histogram
212)
pyplot.subplot('passengers'])
pyplot.hist(dataframe[ pyplot.show()
pyplot.close()
### Chapter 9 Moving Average Smoothing
## 9.4 Moving Average as Data Preparation
# moving average smoothing as data preparation
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # tail-rolling average transform
= series.rolling(window=3)
rolling = rolling.mean()
rolling_mean print(rolling_mean.head(10))
Date
1959-01-01 NaN
1959-01-02 NaN
1959-01-03 32.333333
1959-01-04 31.000000
1959-01-05 35.000000
1959-01-06 34.666667
1959-01-07 39.333333
1959-01-08 39.000000
1959-01-09 42.000000
1959-01-10 36.000000
Name: Births, dtype: float64
# plot original and transformed dataset
series.plot()='red')
rolling_mean.plot(color pyplot.show()
pyplot.close()# zoomed plot original and transformed dataset
100].plot()
series[:100].plot(color='red')
rolling_mean[: pyplot.show()
pyplot.close()
## 9.5 Moving Average as Feature Engineering
# moving average smoothing as feature engineering
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = DataFrame(series.values)
df = 3
width = df.shift(1)
lag1 = df.shift(width - 1)
lag3 = lag3.rolling(window=width)
window = window.mean()
means = concat([means, lag1, df], axis=1)
dataframe = ['mean', 't', 't+1']
dataframe.columns print(dataframe.head(10))
mean t t+1
0 NaN NaN 35
1 NaN 35.0 32
2 NaN 32.0 30
3 NaN 30.0 31
4 32.333333 31.0 44
5 31.000000 44.0 29
6 35.000000 29.0 45
7 34.666667 45.0 43
8 39.333333 43.0 38
9 39.000000 38.0 27
## 9.6 Moving Average as Prediction
# moving average smoothing as a forecast model
#!pip install scikit-learn
from math import sqrt
from pandas import read_csv
from numpy import mean
from sklearn.metrics import mean_squared_error
from matplotlib import pyplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # prepare situation
= series.values
X X
array([35, 32, 30, 31, 44, 29, 45, 43, 38, 27, 38, 33, 55, 47, 45, 37, 50,
43, 41, 52, 34, 53, 39, 32, 37, 43, 39, 35, 44, 38, 24, 23, 31, 44,
38, 50, 38, 51, 31, 31, 51, 36, 45, 51, 34, 52, 47, 45, 46, 39, 48,
37, 35, 52, 42, 45, 39, 37, 30, 35, 28, 45, 34, 36, 50, 44, 39, 32,
39, 45, 43, 39, 31, 27, 30, 42, 46, 41, 36, 45, 46, 43, 38, 34, 35,
56, 36, 32, 50, 41, 39, 41, 47, 34, 36, 33, 35, 38, 38, 34, 53, 34,
34, 38, 35, 32, 42, 34, 46, 30, 46, 45, 54, 34, 37, 35, 40, 42, 58,
51, 32, 35, 38, 33, 39, 47, 38, 52, 30, 34, 40, 35, 42, 41, 42, 38,
24, 34, 43, 36, 55, 41, 45, 41, 37, 43, 39, 33, 43, 40, 38, 45, 46,
34, 35, 48, 51, 36, 33, 46, 42, 48, 34, 41, 35, 40, 34, 30, 36, 40,
39, 45, 38, 47, 33, 30, 42, 43, 41, 41, 59, 43, 45, 38, 37, 45, 42,
57, 46, 51, 41, 47, 26, 35, 44, 41, 42, 36, 45, 45, 45, 47, 38, 42,
35, 36, 39, 45, 43, 47, 36, 41, 50, 39, 41, 46, 64, 45, 34, 38, 44,
48, 46, 44, 37, 39, 44, 45, 33, 44, 38, 46, 46, 40, 39, 44, 48, 50,
41, 42, 51, 41, 44, 38, 68, 40, 42, 51, 44, 45, 36, 57, 44, 42, 53,
42, 34, 40, 56, 44, 53, 55, 39, 59, 55, 73, 55, 44, 43, 40, 47, 51,
56, 49, 54, 56, 47, 44, 43, 42, 45, 50, 48, 43, 40, 59, 41, 42, 51,
49, 45, 43, 42, 38, 47, 38, 36, 42, 35, 28, 44, 36, 45, 46, 48, 49,
43, 42, 59, 45, 52, 46, 42, 40, 40, 45, 35, 35, 40, 39, 33, 42, 47,
51, 44, 40, 57, 49, 45, 49, 51, 46, 44, 52, 45, 32, 46, 41, 34, 33,
36, 49, 43, 43, 34, 39, 35, 52, 47, 52, 39, 40, 42, 42, 53, 39, 40,
38, 44, 34, 37, 52, 48, 55, 50], dtype=int64)
= 3
window = [X[i] for i in range(window)]
history history
[35, 32, 30]
= [X[i] for i in range(window, len(X))]
test test
[31, 44, 29, 45, 43, 38, 27, 38, 33, 55, 47, 45, 37, 50, 43, 41, 52, 34, 53, 39, 32, 37, 43, 39, 35, 44, 38, 24, 23, 31, 44, 38, 50, 38, 51, 31, 31, 51, 36, 45, 51, 34, 52, 47, 45, 46, 39, 48, 37, 35, 52, 42, 45, 39, 37, 30, 35, 28, 45, 34, 36, 50, 44, 39, 32, 39, 45, 43, 39, 31, 27, 30, 42, 46, 41, 36, 45, 46, 43, 38, 34, 35, 56, 36, 32, 50, 41, 39, 41, 47, 34, 36, 33, 35, 38, 38, 34, 53, 34, 34, 38, 35, 32, 42, 34, 46, 30, 46, 45, 54, 34, 37, 35, 40, 42, 58, 51, 32, 35, 38, 33, 39, 47, 38, 52, 30, 34, 40, 35, 42, 41, 42, 38, 24, 34, 43, 36, 55, 41, 45, 41, 37, 43, 39, 33, 43, 40, 38, 45, 46, 34, 35, 48, 51, 36, 33, 46, 42, 48, 34, 41, 35, 40, 34, 30, 36, 40, 39, 45, 38, 47, 33, 30, 42, 43, 41, 41, 59, 43, 45, 38, 37, 45, 42, 57, 46, 51, 41, 47, 26, 35, 44, 41, 42, 36, 45, 45, 45, 47, 38, 42, 35, 36, 39, 45, 43, 47, 36, 41, 50, 39, 41, 46, 64, 45, 34, 38, 44, 48, 46, 44, 37, 39, 44, 45, 33, 44, 38, 46, 46, 40, 39, 44, 48, 50, 41, 42, 51, 41, 44, 38, 68, 40, 42, 51, 44, 45, 36, 57, 44, 42, 53, 42, 34, 40, 56, 44, 53, 55, 39, 59, 55, 73, 55, 44, 43, 40, 47, 51, 56, 49, 54, 56, 47, 44, 43, 42, 45, 50, 48, 43, 40, 59, 41, 42, 51, 49, 45, 43, 42, 38, 47, 38, 36, 42, 35, 28, 44, 36, 45, 46, 48, 49, 43, 42, 59, 45, 52, 46, 42, 40, 40, 45, 35, 35, 40, 39, 33, 42, 47, 51, 44, 40, 57, 49, 45, 49, 51, 46, 44, 52, 45, 32, 46, 41, 34, 33, 36, 49, 43, 43, 34, 39, 35, 52, 47, 52, 39, 40, 42, 42, 53, 39, 40, 38, 44, 34, 37, 52, 48, 55, 50]
= list()
predictions # walk forward over time steps in test
for t in range(len(test)):
= len(history)
length = mean([history[i] for i in range(length-window,length)])
yhat = test[t]
obs
predictions.append(yhat)
history.append(obs)#print('predicted=%f, expected=%f' % (yhat, obs))
= sqrt(mean_squared_error(test, predictions))
rmse print('Test RMSE: %.3f' % rmse)
Test RMSE: 7.834
# plot
pyplot.plot(test)='red')
pyplot.plot(predictions, color pyplot.show()
# zoom plot
100])
pyplot.plot(test[:100], color='red')
pyplot.plot(predictions[: pyplot.show()
### Chapter 10 A Gentle Introduction to White Noise
## 10.4 Example of White Noise Time Series
from random import gauss
from random import seed
from pandas import Series
from pandas.plotting import autocorrelation_plot
from matplotlib import pyplot
# seed random number generator
1)
seed(# create white noise series
= [gauss(0.0, 1.0) for i in range(1000)]
series = Series(series)
series # summary stats
print(series.describe())
count 1000.000000
mean -0.013222
std 1.003685
min -2.961214
25% -0.684192
50% -0.010934
75% 0.703915
max 2.737260
dtype: float64
# line plot
series.plot() pyplot.show()
pyplot.close()# histogram plot
series.hist() pyplot.show()
pyplot.close()# autocorrelation
autocorrelation_plot(series) pyplot.show()
pyplot.close()
# calculate and plot a white noise series
from random import gauss
from random import seed
from pandas import Series
from pandas.plotting import autocorrelation_plot
from matplotlib import pyplot
# seed random number generator
1)
seed(# create white noise series
= [gauss(0.0, 1.0) for i in range(1000)]
series = Series(series)
series # summary stats
print(series.describe())
count 1000.000000
mean -0.013222
std 1.003685
min -2.961214
25% -0.684192
50% -0.010934
75% 0.703915
max 2.737260
dtype: float64
# line plot
series.plot() pyplot.show()
pyplot.close()# histogram plot
series.hist() pyplot.show()
pyplot.close()# autocorrelation
autocorrelation_plot(series) pyplot.show()
pyplot.close()
### Chapter 11 A Gentle Introduction to the Random Walk
#!pip install statsmodels
# 11.1 Random Series
# create and plot a random series
from random import seed
from random import randrange
from matplotlib import pyplot
1)
seed(= [randrange(10) for i in range(1000)]
series
pyplot.plot(series) pyplot.show()
pyplot.close()
# 11.2 Random Walk
# create and plot a random walk
from random import seed
from random import random
from matplotlib import pyplot
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(
for i in range(1,1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)
pyplot.plot(random_walk) pyplot.show()
pyplot.close()
# 11.3 Random Walk and Autocorrelation
# plot the autocorrelation of a random walk
from random import seed
from random import random
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(for i in range(1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)
autocorrelation_plot(random_walk) pyplot.show()
pyplot.close()
# 11.4 Random Walk and Stationarity
# calculate the stationarity of a random walk
from random import seed
from random import random
from statsmodels.tsa.stattools import adfuller
# generate random walk
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(for i in range(1,1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)print()
# statistical test
= adfuller(random_walk)
result print('ADF Statistic: %f' % result[0])
ADF Statistic: 0.341605
print('p-value: %f' % result[1])
p-value: 0.979175
print('Critical Values:')
Critical Values:
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
1%: -3.437
5%: -2.864
10%: -2.568
# calculate and plot a differenced random walk
from random import seed
from random import random
from matplotlib import pyplot
# create random walk
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(for i in range(1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)# take difference
= list()
diff for i in range(1, len(random_walk)):
= random_walk[i] - random_walk[i - 1]
value
diff.append(value)# line plot
pyplot.plot(diff) pyplot.show()
pyplot.close()
# plot the autocorrelation of a differenced random walk
from random import seed
from random import random
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
# create random walk
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(for i in range(1, 1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)# take difference
= list()
diff for i in range(1, len(random_walk)):
= random_walk[i] - random_walk[i - 1]
value
diff.append(value)# line plot
autocorrelation_plot(diff) pyplot.show()
pyplot.close()
# 11.5 Predicting a Random Walk
# persistence forecasts for a random walk
from random import seed
from random import random
from sklearn.metrics import mean_squared_error
from math import sqrt
# generate the random walk
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(for i in range(1, 1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)# prepare dataset
= int(len(random_walk) * 0.66)
train_size = random_walk[0:train_size], random_walk[train_size:]
train, test # persistence
= list()
predictions = train[-1]
history for i in range(len(test)):
= history
yhat
predictions.append(yhat)= test[i]
history = sqrt(mean_squared_error(test, predictions))
rmse print('Persistence RMSE: %.3f' % rmse)
Persistence RMSE: 1.000
# random predictions for a random walk
from random import seed
from random import random
from sklearn.metrics import mean_squared_error
from math import sqrt
# generate the random walk
1)
seed(= list()
random_walk -1 if random() < 0.5 else 1)
random_walk.append(for i in range(1000):
= -1 if random() < 0.5 else 1
movement = random_walk[i-1] + movement
value
random_walk.append(value)# prepare dataset
= int(len(random_walk) * 0.66)
train_size = random_walk[0:train_size], random_walk[train_size:]
train, test # random prediction
= list()
predictions = train[-1]
history for i in range(len(test)):
= history + (-1 if random() < 0.5 else 1)
yhat
predictions.append(yhat)= test[i]
history = sqrt(mean_squared_error(test, predictions))
rmse print('Random RMSE: %.3f' % rmse)
Random RMSE: 9.827
### Chapter 12 Decompose Time Series Data
# 12.4 Automatic Time Series Decomposition
# 12.4.1 Additive Decomposition
# additive decompose a contrived additive time series
from random import randrange
from matplotlib import pyplot
from statsmodels.tsa.seasonal import seasonal_decompose
= [i+randrange(10) for i in range(1,100)]
series = seasonal_decompose(series, model='additive', period=1)
result
result.plot() pyplot.show()
pyplot.close()
# 12.4.2 Multiplicative Decomposition
# multiplicative decompose a contrived multiplicative time series
from matplotlib import pyplot
from statsmodels.tsa.seasonal import seasonal_decompose
= [i**2.0 for i in range(1,100)]
series = seasonal_decompose(series, model='multiplicative', period=1)
result
result.plot() pyplot.show()
pyplot.close()
# 12.4.3 Airline Passengers Dataset
# multiplicative decompose time series
from pandas import read_csv
from matplotlib import pyplot
from statsmodels.tsa.seasonal import seasonal_decompose
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = seasonal_decompose(series, model='multiplicative')
result
result.plot() pyplot.show()
pyplot.close()
### Chapter 13 Use and Remove Trends
# detrend a time series using differencing
from pandas import read_csv
from datetime import datetime
from matplotlib import pyplot
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:1: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
= series.values
X = list()
diff for i in range(1, len(X)):
= X[i] - X[i - 1]
value
diff.append(value)
pyplot.plot(diff) pyplot.show()
# use a linear model to detrend a time series
from pandas import read_csv
from datetime import datetime
from sklearn.linear_model import LinearRegression
from matplotlib import pyplot
import numpy
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:1: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
# fit linear model
= [i for i in range(0, len(series))]
X = numpy.reshape(X, (len(X), 1))
X = series.values
y = LinearRegression()
model model.fit(X, y)
LinearRegression()In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LinearRegression()
# calculate trend
= model.predict(X)
trend # plot trend
pyplot.plot(y)
pyplot.plot(trend) pyplot.show()
# detrend
= [y[i]-trend[i] for i in range(0, len(series))]
detrended # plot detrended
pyplot.plot(detrended) pyplot.show()
pyplot.close()
### Chapter 14 Use and Remove Seasonality
# 14.3 Seasonal Adjustment with Differencing
# deseasonalize a time series using differencing
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.values
X = list()
diff = 365
days_in_year for i in range(days_in_year, len(X)):
= X[i] - X[i - days_in_year]
value
diff.append(value)
pyplot.plot(diff) pyplot.show()
pyplot.close()
# calculate and plot monthly average
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.resample('M')
resample = resample.mean()
monthly_mean print(monthly_mean.head(13))
Date
1981-01-31 17.712903
1981-02-28 17.678571
1981-03-31 13.500000
1981-04-30 12.356667
1981-05-31 9.490323
1981-06-30 7.306667
1981-07-31 7.577419
1981-08-31 7.238710
1981-09-30 10.143333
1981-10-31 10.087097
1981-11-30 11.890000
1981-12-31 13.680645
1982-01-31 16.567742
Freq: M, Name: Temp, dtype: float64
monthly_mean.plot() pyplot.show()
pyplot.close()
# deseasonalize monthly data by differencing
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.resample('M')
resample = resample.mean()
monthly_mean = series.values
X = list()
diff = 12
months_in_year for i in range(months_in_year, len(monthly_mean)):
= monthly_mean[i] - monthly_mean[i - months_in_year]
value diff.append(value)
<string>:2: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
pyplot.plot(diff) pyplot.show()
pyplot.close()
# deseasonalize a time series using month-based differencing
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= series.values
X = list()
diff = 365
days_in_year for i in range(days_in_year, len(X)):
= str(series.index[i].year-1)+'-'+str(series.index[i].month)
month_str = series[month_str].mean()
month_mean_last_year = X[i] - month_mean_last_year
value
diff.append(value)
pyplot.plot(diff) pyplot.show()
pyplot.close()
# model seasonality with a polynomial model
from pandas import read_csv
from matplotlib import pyplot
from numpy import polyfit
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates# fit polynomial: x^2*b1 + x*b2 + ... + bn
= [i%365 for i in range(0, len(series))]
X = series.values
y = 4
degree = polyfit(X, y, degree)
coef print('Coefficients: %s' % coef)
Coefficients: [-1.17308000e-08 9.30253946e-06 -2.15977594e-03 1.19147966e-01
1.38980178e+01]
# create curve
= list()
curve for i in range(len(X)):
= coef[-1]
value for d in range(degree):
+= X[i]**(degree-d) * coef[d]
value
curve.append(value)# plot curve over original data
pyplot.plot(series.values)='red', linewidth=3)
pyplot.plot(curve, color pyplot.show()
pyplot.close()
# deseasonalize by differencing with a polynomial model
from pandas import read_csv
from matplotlib import pyplot
from numpy import polyfit
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates# fit polynomial: x^2*b1 + x*b2 + ... + bn
= [i%365 for i in range(0, len(series))]
X = series.values
y = 4
degree = polyfit(X, y, degree)
coef # create curve
= list()
curve for i in range(len(X)):
= coef[-1]
value for d in range(degree):
+= X[i]**(degree-d) * coef[d]
value
curve.append(value)# create seasonally adjusted
= series.values
values = list()
diff for i in range(len(values)):
= values[i] - curve[i]
value
diff.append(value)
pyplot.plot(diff) pyplot.show()
pyplot.close()
### Chapter 15 Stationarity in Time Series Data
## 15.1 Stationary Time Series
# load time series data
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series
series.plot() pyplot.show()
pyplot.close()
#15.2 Non-Stationary Time Series
# load time series data
from pandas import read_csv
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series
series.plot() pyplot.show()
pyplot.close()
# 15.6.1 Daily Births Dataset
# plot a histogram of a time series
from pandas import read_csv
from matplotlib import pyplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series
series.hist() pyplot.show()
pyplot.close()
# calculate statistics of partitioned time series data
from pandas import read_csv
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = int(len(X) / 2)
split = X[0:split], X[split:]
X1, X2 = X1.mean(), X2.mean()
mean1, mean2 = X1.var(), X2.var()
var1, var2 print('mean1=%f, mean2=%f' % (mean1, mean2))
mean1=39.763736, mean2=44.185792
print('variance1=%f, variance2=%f' % (var1, var2))
variance1=49.213410, variance2=48.708651
# 15.6.2 Airline Passengers Dataset
# calculate statistics of partitioned time series data
from pandas import read_csv
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = int(len(X) / 2)
split = X[0:split], X[split:]
X1, X2 = X1.mean(), X2.mean()
mean1, mean2 = X1.var(), X2.var()
var1, var2 print('mean1=%f, mean2=%f' % (mean1, mean2))
mean1=182.902778, mean2=377.694444
print('variance1=%f, variance2=%f' % (var1, var2))
variance1=2244.087770, variance2=7367.962191
# plot a histogram of a time series
from pandas import read_csv
from matplotlib import pyplot
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series
series.hist() pyplot.show()
# histogram and line plot of log transformed time series
from pandas import read_csv
from matplotlib import pyplot
from numpy import log
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = log(X)
X
pyplot.hist(X) pyplot.show()
pyplot.plot(X) pyplot.show()
# calculate statistics of partitioned log transformed time series data
from pandas import read_csv
from numpy import log
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = log(X)
X = int(len(X) / 2)
split = X[0:split], X[split:]
X1, X2 = X1.mean(), X2.mean()
mean1, mean2 = X1.var(), X2.var()
var1, var2 print('mean1=%f, mean2=%f' % (mean1, mean2))
mean1=5.175146, mean2=5.909206
print('variance1=%f, variance2=%f' % (var1, var2))
variance1=0.068375, variance2=0.049264
# 15.7 Augmented Dickey-Fuller test
# calculate stationarity test of time series data
from pandas import read_csv
from statsmodels.tsa.stattools import adfuller
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = adfuller(X)
result print('ADF Statistic: %f' % result[0])
ADF Statistic: -4.808291
print('p-value: %f' % result[1])
p-value: 0.000052
print('Critical Values:')
Critical Values:
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
1%: -3.449
5%: -2.870
10%: -2.571
# calculate stationarity test of time series data
from pandas import read_csv
from statsmodels.tsa.stattools import adfuller
= read_csv('monthly-airline-passengers.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = adfuller(X)
result print('ADF Statistic: %f' % result[0])
ADF Statistic: 0.815369
print('p-value: %f' % result[1])
p-value: 0.991880
print('Critical Values:')
Critical Values:
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
1%: -3.482
5%: -2.884
10%: -2.579
### Chapter 16 Backtest Forecast Models
# calculate a train-test split of a time series dataset
from pandas import read_csv
= read_csv('sunspots.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = int(len(X) * 0.66)
train_size = X[0:train_size], X[train_size:len(X)]
train, test print('Observations: %d' % (len(X)))
Observations: 2820
print('Training Observations: %d' % (len(train)))
Training Observations: 1861
print('Testing Observations: %d' % (len(test)))
Testing Observations: 959
# plot train-test split of time series data
from pandas import read_csv
from matplotlib import pyplot
= read_csv('sunspots.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = int(len(X) * 0.66)
train_size = X[0:train_size], X[train_size:len(X)]
train, test print('Observations: %d' % (len(X)))
Observations: 2820
print('Training Observations: %d' % (len(train)))
Training Observations: 1861
print('Testing Observations: %d' % (len(test)))
Testing Observations: 959
pyplot.plot(train)None for i in train] + [x for x in test])
pyplot.plot([ pyplot.show()
# calculate repeated train-test splits of time series data
from pandas import read_csv
from sklearn.model_selection import TimeSeriesSplit
from matplotlib import pyplot
= read_csv('sunspots.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = TimeSeriesSplit(n_splits=3)
splits 1)
pyplot.figure(= 1
index for train_index, test_index in splits.split(X):
= X[train_index]
train = X[test_index]
test #print('Observations: %d' % (len(train) + len(test)))
#print('Training Observations: %d' % (len(train)))
#print('Testing Observations: %d' % (len(test)))
310 + index)
pyplot.subplot(
pyplot.plot(train)None for i in train] + [x for x in test])
pyplot.plot([+= 1
index pyplot.show()
# 16.5 Walk Forward Validation
# walk forward evaluation model for time series data
from pandas import read_csv
= read_csv('sunspots.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = series.values
X = 500
n_train = len(X)
n_records for i in range(n_train, n_records):
= X[0:i], X[i:i+1]
train, test print('train=%d, test=%d' % (len(train), len(test)))
train=2819, test=1
### Chapter 17 Forecasting Performance Measures
# calculate forecast error
= [0.0, 0.5, 0.0, 0.5, 0.0]
expected = [0.2, 0.4, 0.1, 0.6, 0.2]
predictions = [expected[i]-predictions[i] for i in range(len(expected))]
forecast_errors print('Forecast Errors: %s' % forecast_errors)
Forecast Errors: [-0.2, 0.09999999999999998, -0.1, -0.09999999999999998, -0.2]
# 17.2 Mean Forecast Error (or Forecast Bias)
# calculate mean forecast error
= [0.0, 0.5, 0.0, 0.5, 0.0]
expected = [0.2, 0.4, 0.1, 0.6, 0.2]
predictions = [expected[i]-predictions[i] for i in range(len(expected))]
forecast_errors = sum(forecast_errors) * 1.0/len(expected)
bias print('Bias: %f' % bias)
Bias: -0.100000
# 17.3 Mean Absolute Error
# calculate mean absolute error
from sklearn.metrics import mean_absolute_error
= [0.0, 0.5, 0.0, 0.5, 0.0]
expected = [0.2, 0.4, 0.1, 0.6, 0.2]
predictions = mean_absolute_error(expected, predictions)
mae print('MAE: %f' % mae)
MAE: 0.140000
# 17.4 Mean Squared Error
# calculate mean squared error
from sklearn.metrics import mean_squared_error
= [0.0, 0.5, 0.0, 0.5, 0.0]
expected = [0.2, 0.4, 0.1, 0.6, 0.2]
predictions = mean_squared_error(expected, predictions)
mse print('MSE: %f' % mse)
MSE: 0.022000
#17.5 Root Mean Squared Error
# calculate root mean squared error
from sklearn.metrics import mean_squared_error
from math import sqrt
= [0.0, 0.5, 0.0, 0.5, 0.0]
expected = [0.2, 0.4, 0.1, 0.6, 0.2]
predictions = mean_squared_error(expected, predictions)
mse = sqrt(mse)
rmse print('RMSE: %f' % rmse)
RMSE: 0.148324
# Chapter 18 Persistence Model for Forecasting
# 18.4.1 Step 1: Define the Supervised Learning Problem
# Create lagged dataset
# evaluate a persistence forecast model
from pandas import read_csv
from datetime import datetime
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
from sklearn.metrics import mean_squared_error
from math import sqrt
# load dataset
def parser(x):
return datetime.strptime('190'+x, '%Y-%m')
= read_csv('monthly-shampoo-sales.csv', header=0, index_col=0, parse_dates=True,date_parser=parser).squeeze("columns") series
<string>:1: FutureWarning: The argument 'date_parser' is deprecated and will be removed in a future version. Please use 'date_format' instead, or read your data in as 'object' dtype and then call 'to_datetime'.
# create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns print(dataframe.head(5))
t t+1
0 NaN 266.0
1 266.0 145.9
2 145.9 183.1
3 183.1 119.3
4 119.3 180.3
# split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
def model_persistence(x):
return x
# walk-forward validation
= list()
predictions for x in test_X:
= model_persistence(x)
yhat
predictions.append(yhat)= sqrt(mean_squared_error(test_y, predictions))
rmse print('Test RMSE: %.3f' % rmse)
Test RMSE: 133.156
# plot predictions and expected results
pyplot.plot(train_y)None for i in train_y] + [x for x in test_y])
pyplot.plot([None for i in train_y] + [x for x in predictions])
pyplot.plot([ pyplot.show()
### Chapter 19 Visualize Residual Forecast Errors
# create lagged dataset
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series = DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals
# calculate residuals from a persistence forecast
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals = DataFrame(residuals)
residuals print(residuals.head())
0
0 9.0
1 -10.0
2 3.0
3 -6.0
4 30.0
# 19.4 Residual Line Plot
# line plot of residual errors
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals = DataFrame(residuals)
residuals # plot residuals
residuals.plot() pyplot.show()
#19.5 Residual Summary Statistics
# summary statistics of residual errors
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals = DataFrame(residuals)
residuals # summary statistics
print(residuals.describe())
0
count 125.000000
mean 0.064000
std 9.187776
min -28.000000
25% -6.000000
50% -1.000000
75% 5.000000
max 30.000000
#19.6 Residual Histogram and Density Plots
# density plots of residual errors
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals = DataFrame(residuals)
residuals # histogram plot
residuals.hist()
array([[<Axes: title={'center': '0'}>]], dtype=object)
pyplot.show()
# density plot
='kde')
residuals.plot(kind pyplot.show()
# 19.7 Residual Q-Q Plot
# qq plot of residual errors
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
import numpy
from statsmodels.graphics.gofplots import qqplot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals = numpy.array(residuals)
residuals ='r')
qqplot(residuals, line pyplot.show()
# 19.8 Residual Autocorrelation Plot
# autoregression plot of residual errors
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
= read_csv('daily-total-female-births.csv', header=0, index_col=0, parse_dates=True).squeeze("columns")
series # create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = int(len(X) * 0.66)
train_size = X[1:train_size], X[train_size:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
= [x for x in test_X]
predictions # calculate residuals
= [test_y[i]-predictions[i] for i in range(len(predictions))]
residuals = DataFrame(residuals)
residuals
autocorrelation_plot(residuals) pyplot.show()
### Chapter 20 Reframe Time Series Forecasting Problems
# reframe precision of regression forecast
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
# load data
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates# create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # round forecast to nearest 5
for i in range(len(dataframe['t+1'])):
't+1'] = int(dataframe.loc[i,'t+1'] / 5) * 5.0
dataframe.loc[i,print(dataframe.head(5))
t t+1
0 NaN 20.0
1 20.7 15.0
2 17.9 15.0
3 18.8 10.0
4 14.6 15.0
# 20.5 Classification Framings
# reframe regression as classification
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
# load data
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates# Create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # make discrete
for i in range(len(dataframe['t+1'])):
= dataframe['t+1'][i]
value if value < 10.0:
't+1'] = 0
dataframe.loc[i,elif value >= 25.0:
't+1'] = 2
dataframe.loc[i,else:
't+1'] = 1
dataframe.loc[i,print(dataframe.head(5))
t t+1
0 NaN 1.0
1 20.7 1.0
2 17.9 1.0
3 18.8 1.0
4 14.6 1.0
# 20.6 Time Horizon Framings
# reframe time horizon of forecast
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
# load data
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates# create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values, values.shift(-1),
dataframe -2), values.shift(-3), values.shift(-4), values.shift(-5),
values.shift(-6)], axis=1)
values.shift(= ['t', 't+1', 't+2', 't+3', 't+4', 't+5', 't+6', 't+7']
dataframe.columns print(dataframe.head(14))
t t+1 t+2 t+3 t+4 t+5 t+6 t+7
0 NaN 20.7 17.9 18.8 14.6 15.8 15.8 15.8
1 20.7 17.9 18.8 14.6 15.8 15.8 15.8 17.4
2 17.9 18.8 14.6 15.8 15.8 15.8 17.4 21.8
3 18.8 14.6 15.8 15.8 15.8 17.4 21.8 20.0
4 14.6 15.8 15.8 15.8 17.4 21.8 20.0 16.2
5 15.8 15.8 15.8 17.4 21.8 20.0 16.2 13.3
6 15.8 15.8 17.4 21.8 20.0 16.2 13.3 16.7
7 15.8 17.4 21.8 20.0 16.2 13.3 16.7 21.5
8 17.4 21.8 20.0 16.2 13.3 16.7 21.5 25.0
9 21.8 20.0 16.2 13.3 16.7 21.5 25.0 20.7
10 20.0 16.2 13.3 16.7 21.5 25.0 20.7 20.6
11 16.2 13.3 16.7 21.5 25.0 20.7 20.6 24.8
12 13.3 16.7 21.5 25.0 20.7 20.6 24.8 17.7
13 16.7 21.5 25.0 20.7 20.6 24.8 17.7 15.5
### Chapter 22 Autoregression Models for Forecasting
# lag plot of time series
from pandas import read_csv
from matplotlib import pyplot
from pandas.plotting import lag_plot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates
lag_plot(series) pyplot.show()
# correlation of lag=1
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns = dataframe.corr()
result print(result)
t t+1
t 1.00000 0.77487
t+1 0.77487 1.00000
#22.5 Autocorrelation Plots
# autocorrelation plot of time series
from pandas import read_csv
from matplotlib import pyplot
from pandas.plotting import autocorrelation_plot
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates
autocorrelation_plot(series) pyplot.show()
# autocorrelation plot of time series
from pandas import read_csv
from matplotlib import pyplot
from statsmodels.graphics.tsaplots import plot_acf
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates=31)
plot_acf(series, lags pyplot.show()
# 22.6 Persistence Model
# evaluate a persistence model
from pandas import read_csv
from pandas import DataFrame
from pandas import concat
from matplotlib import pyplot
from sklearn.metrics import mean_squared_error
from math import sqrt
# load dataset
= read_csv('daily-min-temperatures (1).csv', header=0, index_col=0,
series =True).squeeze("columns")
parse_dates# create lagged dataset
= DataFrame(series.values)
values = concat([values.shift(1), values], axis=1)
dataframe = ['t', 't+1']
dataframe.columns # split into train and test sets
= dataframe.values
X = X[1:len(X)-7], X[len(X)-7:]
train, test = train[:,0], train[:,1]
train_X, train_y = test[:,0], test[:,1]
test_X, test_y # persistence model
def model_persistence(x):
return x
# walk-forward validation
= list()
predictions for x in test_X:
= model_persistence(x)
yhat
predictions.append(yhat)= sqrt(mean_squared_error(test_y, predictions))
rmse print('Test RMSE: %.3f' % rmse)
Test RMSE: 1.850
# plot predictions vs expected
pyplot.plot(test_y)='red')
pyplot.plot(predictions, color pyplot.show()
Time Series Forecasting Using Generative AI: Leveraging AI for Precision Forecasting
Generative AI is a subset of artificial intelligence because it utilizes AI techniques, such as machine learning and pattern recognition, to generate new content, like images and text; just as how a painter uses brushes to create art, GenAI uses algorithms to create new content, making it a specialized tool within the broader scope of AI. For example, ChatGPT, a GenAI tool, uses AI algorithms to generate human-like text responses, making it a subset of AI.
GenAI involves leveraging AI to generate novel content, such as text, images, music, audio, and videos, by employing machine learning algorithms to identify patterns and relationships within human-created content. These learned patterns are then used to create new content, effectively mimicking human creativity. The emergence of GenAI has significant implications for language teaching and learning, which plays a vital role in today’s globalized world. Language proficiency enables individuals to communicate effectively, express ideas clearly, and navigate diverse cultural contexts
Multilayer Perceptron (MLP)
An MLP is a neural network that has at least three layers: an input layer, a hidden layer, and an output layer. Each layer performs operations on the outputs of its preceding layer
#!pip install IPython
#!pip install pandas
# 2.2.1 Multilayer Perceptron in Action
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.losses.pytorch import MQLoss,DistributionLoss
from neuralforecast.models import MLP
def calculate_error_metrics(actual, predicted, num_predictors=1):
# convert inputs are numpy arrays
= np.array(actual)
actual = np.array(predicted)
predicted # Number of observations
= len(actual)
n # Calculate MSE
= mean_squared_error(actual, predicted)
mse # Calculate RMSE
= np.sqrt(mse)
rmse # Calculate MAPE
= mean_absolute_percentage_error(actual, predicted)
mape # Calculate R-squared
= r2_score(actual, predicted)
r2 # Calculate Adjusted R-squared
= 1 - ((1 - r2) * (n - 1) / (n - num_predictors - 1))
adjusted_r2 print(f'MSE : {mse}')
print(f'RMSE : {rmse}')
print(f'MAPE : {mape}')
print(f'r2 : {r2}')
print(f'adjusted_r2 : {adjusted_r2}')
from neuralforecast.utils import AirPassengersDF
= AirPassengersDF
Y_df = Y_df.reset_index(drop=True)
Y_df Y_df.head()
unique_id ds y
0 1.0 1949-01-31 112.0
1 1.0 1949-02-28 118.0
2 1.0 1949-03-31 132.0
3 1.0 1949-04-30 129.0
4 1.0 1949-05-31 121.0
= Y_df.head(132)
train_data = Y_df.tail(12)
test_data
= 12
horizon = MLP(h=horizon, input_size=12,
model =DistributionLoss(distribution='Normal',
loss=[80, 90]),
level='robust',
scaler_type=1e-3,
learning_rate=200,
max_steps=10,
val_check_steps=2)
early_stop_patience_steps
#fcst = NeuralForecast(models=[model],freq='M')
#fcst.fit(df=train_data, val_size=12)
#Y_hat_df = fcst.predict()
#Y_hat_df.head()
'y']],Y_hat_df['MLP']) calculate_error_metrics(test_data[[
MSE : 547.1504516601562
RMSE : 23.39124733014801
MAPE : 0.03406834229826927
r2 : 0.9012269377708435
adjusted_r2 : 0.8913496315479279
'ds',inplace =True)
train_data.set_index('ds',inplace =True)
Y_hat_df.set_index('ds',inplace =True)
test_data.set_index(=(25, 15))
plt.figure(figsize= train_data["y"]
y_past = Y_hat_df['MLP']
y_pred = test_data["y"]
y_test ="Past time series values")
plt.plot(y_past, label="Forecast")
plt.plot(y_pred, label="Actual time series values")
plt.plot(y_test, label'AirPassengers Forecast', fontsize=10)
plt.title('Monthly Passengers', fontsize=10)
plt.ylabel('Timestamp [t]', fontsize=10)
plt.xlabel(; plt.legend()
Temporal Convolutional Networks (TCN)
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.losses.pytorch import GMM, MQLoss, DistributionLoss
from neuralforecast.auto import TCN
from neuralforecast.tsdataset import TimeSeriesDataset
from ray import tune
from neuralforecast.utils import AirPassengersDF as Y_df
def calculate_error_metrics(actual, predicted, num_predictors=1):
# convert inputs are numpy arrays
= np.array(actual)
actual = np.array(predicted)
predicted # Number of observations
= len(actual)
n # Calculate MSE
= mean_squared_error(actual, predicted)
mse # Calculate RMSE
= np.sqrt(mse)
rmse # Calculate MAPE
= mean_absolute_percentage_error(actual, predicted)
mape # Calculate R-squared
= r2_score(actual, predicted)
r2 # Calculate Adjusted R-squared
= 1 - ((1 - r2) * (n - 1) / (n - num_predictors - 1))
adjusted_r2 print(f'MSE : {mse}')
print(f'RMSE : {rmse}')
print(f'MAPE : {mape}')
print(f'r2 : {r2}')
print(f'adjusted_r2 : {adjusted_r2}')
= Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31']
Y_test_df *_ = TimeSeriesDataset.from_df(Y_train_df) dataset,
'y']],y_hat[['TCN']]) calculate_error_metrics(Y_test_df[[
MSE : 396.6375732421875
RMSE : 19.915761929742672
MAPE : 0.03342359513044357
r2 : 0.9283979535102844
adjusted_r2 : 0.9212377488613128
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
Y_test_df.set_index(
=(25, 15)) plt.figure(figsize
<Figure size 2500x1500 with 0 Axes>
= Y_train_df["y"]
y_past = y_hat[['TCN']]
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F948CB1F0>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F948DE1D0>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F948DF250>]
'AirPassengers Forecast') plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers') plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]') plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Bidirectional Temporal Convolutional Network (BiTCN)
Bidirectional temporal convolutional network (BiTCN) architecture is developed by using two temporal convolutional networks for forecasting. The first network, called the forward network, encodes future covariates of the time series. The second network, called the backward network, encodes past observations and covariates. This technique helps in preserving temporal information of sequence data. The parameters of the output distribution are jointly estimated using these two networks. It is computationally more efficient than RNN methods like LSTM.
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import BiTCN
from ray import tune
from neuralforecast.losses.pytorch import GMM, DistributionLoss
from neuralforecast.tsdataset import TimeSeriesDataset
from neuralforecast.utils import AirPassengersDF as Y_df
def calculate_error_metrics(actual, predicted, num_predictors=1):
# convert inputs are numpy arrays
= np.array(actual)
actual = np.array(predicted)
predicted # Number of observations
= len(actual)
n # Calculate MSE
= mean_squared_error(actual, predicted)
mse # Calculate RMSE
= np.sqrt(mse)
rmse # Calculate MAPE
= mean_absolute_percentage_error(actual, predicted)
mape # Calculate R-squared
= r2_score(actual, predicted)
r2 # Calculate Adjusted R-squared
= 1 - ((1 - r2) * (n - 1) / (n - num_predictors - 1))
adjusted_r2 print(f'MSE : {mse}')
print(f'RMSE : {rmse}')
print(f'MAPE : {mape}')
print(f'r2 : {r2}')
print(f'adjusted_r2 : {adjusted_r2}')
= Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31']
Y_test_df *_ = TimeSeriesDataset.from_df(Y_train_df) dataset,
'ds',inplace =True)
y_hat.set_index( y_hat.head()
unique_id BiTCN ... BiTCN-mu-7 BiTCN-std-7
ds ...
1960-01-31 1.0 439.786194 ... 481.688324 57.548355
1960-02-29 1.0 458.564697 ... 485.977234 61.890015
1960-03-31 1.0 476.137177 ... 542.925232 53.607937
1960-04-30 1.0 485.645538 ... 522.366516 61.040913
1960-05-31 1.0 487.014954 ... 533.534668 54.934593
[5 rows x 21 columns]
'y']],y_hat[['BiTCN']]) calculate_error_metrics(Y_test_df[[
MSE : 3626.825439453125
RMSE : 60.2231304355156
MAPE : 0.10271913558244705
r2 : 0.3452759385108948
adjusted_r2 : 0.2798035323619843
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 15)) plt.figure(figsize
<Figure size 2500x1500 with 0 Axes>
= Y_train_df["y"]
y_past = y_hat[['BiTCN']]
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F9490A290>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F9492CFA0>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F9492E020>]
'AirPassengers Forecast', fontsize=30) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=30) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=30) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Recurrent Neural Network (RNN)
In the RNN architecture, the output from the previous step becomes input for the current step. So, no points for guessing why sequence is important for RNN architecture. This is in contrast to the traditional neural networks where the inputs and outputs from each layer are independent of each other. The emergence of RNN architecture was majorly due to NLP (natural language processing) use cases that required prediction of the next word. RNN provided a solution to this problem by making use of a hidden layer. This layer works as memory, as it is used to remember some information about the sequence.
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.losses.pytorch import GMM, MQLoss,DistributionLoss
from neuralforecast.models import RNN
from neuralforecast.tsdataset import TimeSeriesDataset
from ray import tune
from neuralforecast.utils import AirPassengersDF as Y_df
def calculate_error_metrics(actual, predicted, num_predictors=1):
# convert inputs are numpy arrays
= np.array(actual)
actual = np.array(predicted)
predicted # Number of observations
= len(actual)
n # Calculate MSE
= mean_squared_error(actual, predicted)
mse # Calculate RMSE
= np.sqrt(mse)
rmse # Calculate MAPE
= mean_absolute_percentage_error(actual, predicted)
mape # Calculate R-squared
= r2_score(actual, predicted)
r2 # Calculate Adjusted R-squared
= 1 - ((1 - r2) * (n - 1) / (n - num_predictors - 1))
adjusted_r2 print(f'MSE : {mse}')
print(f'RMSE : {rmse}')
print(f'MAPE : {mape}')
print(f'r2 : {r2}')
print(f'adjusted_r2 : {adjusted_r2}')
= Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31']
Y_test_df *_ = TimeSeriesDataset.from_df(Y_train_df) dataset,
'ds',inplace =True)
y_hat.set_index( y_hat.head()
unique_id RNN-median ... RNN-hi-80 RNN-hi-90
ds ...
1960-01-31 1.0 424.830475 ... 454.812195 465.117096
1960-02-29 1.0 404.263458 ... 430.056854 443.181305
1960-03-31 1.0 461.973358 ... 494.343323 505.895691
1960-04-30 1.0 460.056946 ... 489.093109 502.045746
1960-05-31 1.0 477.102234 ... 507.555481 520.431641
[5 rows x 6 columns]
'y']],y_hat[['RNN-median']]) calculate_error_metrics(Y_test_df[[
MSE : 229.1974334716797
RMSE : 15.139267930507065
MAPE : 0.02436511404812336
r2 : 0.9586246609687805
adjusted_r2 : 0.9544871270656585
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
Y_test_df.set_index(
=(25, 15)) plt.figure(figsize
<Figure size 2500x1500 with 0 Axes>
= Y_train_df["y"]
y_past = y_hat[['RNN-median']]
y_pred = Y_test_df["y"]
y_test plt.plot(y_past)
[<matplotlib.lines.Line2D object at 0x0000022F94A536A0>]
plt.plot(y_pred)
[<matplotlib.lines.Line2D object at 0x0000022F94A940A0>]
plt.plot(y_test)
[<matplotlib.lines.Line2D object at 0x0000022F94A95630>]
Long Short-Term Memory (LSTM)
The long short-term memory (LSTM) architecture is a modification to the RNN architecture to allow additional signal paths. These additional paths help in bypassing many processing steps encountered at each stage of the network. This modification helps in remembering information over a large number of time steps. While this modification improves the performance compared to the RNN, it also introduces additional complexity. This complexity has an impact on training speed compared to RNNs. Popular tools like Apple’s Siri and Google’s AlphaGo were based on LSTM.
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import LSTM
from neuralforecast.tsdataset import TimeSeriesDataset
from neuralforecast.losses.pytorch import GMM, MQLoss,DistributionLoss
from neuralforecast.utils import AirPassengersDF as Y_df
from ray import tune
from neuralforecast.utils import AirPassengersDF as Y_df
= Y_df[Y_df.ds<='1959-12-31'] # 132 train data
Y_train_df = Y_df[Y_df.ds>'1959-12-31'] # 12 test data
Y_test_df *_ = TimeSeriesDataset.from_df(Y_train_df) dataset,
#model.fit(dataset=dataset)
= fcst.predict() y_hat
Predicting: | | 0/? [00:00<?, ?it/s]
Predicting: 0%| | 0/1 [00:00<?, ?it/s]
Predicting DataLoader 0: 0%| | 0/1 [00:00<?, ?it/s]
Predicting DataLoader 0: 100%|##########| 1/1 [00:00<00:00, 101.07it/s]
Predicting DataLoader 0: 100%|##########| 1/1 [00:00<00:00, 101.07it/s]
'ds',inplace =True)
y_hat.set_index( y_hat.head()
unique_id LSTM ... LSTM-hi-80 LSTM-hi-90
ds ...
1960-01-31 1.0 383.367157 ... 415.843842 425.110443
1960-02-29 1.0 384.142822 ... 423.718140 436.733459
1960-03-31 1.0 411.430298 ... 454.735565 468.883850
1960-04-30 1.0 432.984985 ... 476.166199 487.669250
1960-05-31 1.0 467.594727 ... 507.642029 516.355347
[5 rows x 7 columns]
'y']],y_hat[['LSTM']]) calculate_error_metrics(Y_test_df[[
MSE : 282.4617919921875
RMSE : 16.806599655855063
MAPE : 0.028130965307354927
r2 : 0.9490092396736145
adjusted_r2 : 0.9439101636409759
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 15)) plt.figure(figsize
<Figure size 2500x1500 with 0 Axes>
= Y_train_df["y"]
y_past = y_hat[['LSTM']]
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94909BD0>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F94AA6500>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94AA6C20>]
'AirPassengers Forecast', fontsize=30) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=30) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=30) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Neural Networks Based on Autoregression (DeepAR)
The DeepAR model has some key benefits compared to traditional approaches. The major advantages that set DeepAR apart are as follows: (a) Relatively much less effort and time need to be spent on feature engineering to capture complex and group-dependent behavior. This is because the model learns seasonality and dependencies on given covariates across the time series. (b) It has an ability to provide forecasts for products with little to no historical data. This is because of learning from historical data of similar events. The DeepAR model has properties that help produce better forecasts by learning from historical behavior of all the time series taken together. (a) It incorporates a wide range of likelihood functions. This allows the time series modeling team to choose suitable functions based on statistical properties of the data. (b) The probabilistic forecasts are generated in the form of Monte Carlo Samples. These can be used to compute quantile estimates belonging to subranges in the prediction horizon. This is important as discussed earlier in this section, where we pointed out advantages of forecasts with probabilities compared to a point forecast value.
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.losses.pytorch import MQLoss,DistributionLoss, GMM, PMM
from neuralforecast.tsdataset import TimeSeriesDataset
import pandas as pd
import pytorch_lightning as pl
import matplotlib.pyplot as plt
from neuralforecast.models import DeepAR
from neuralforecast.losses.pytorch import DistributionLoss, HuberMQLoss
from neuralforecast.utils import AirPassengers, AirPassengersPanel, AirPassengersStatic
from neuralforecast.utils import AirPassengers, AirPassengersPanel, AirPassengersStatic, AirPassengersPanel, AirPassengersStatic
AirPassengersPanel.head()
unique_id ds y trend y_[lag12]
0 Airline1 1949-01-31 112.0 0 112.0
1 Airline1 1949-02-28 118.0 1 118.0
2 Airline1 1949-03-31 132.0 2 132.0
3 Airline1 1949-04-30 129.0 3 129.0
4 Airline1 1949-05-31 121.0 4 121.0
print(AirPassengersStatic)
unique_id airline1 airline2
0 Airline1 0 1
1 Airline2 1 0
= AirPassengersPanel[AirPassengersPanel.ds<AirPassengersPanel['ds'].values[-12]]
Y_train_df = AirPassengersPanel[AirPassengersPanel.ds>=AirPassengersPanel['ds'].values[-12]].reset_index(drop=True) Y_test_df
'y']],Y_hat_df[['DeepAR']]) calculate_error_metrics(Y_test_df[[
MSE : 601.0615844726562
RMSE : 24.51655735360608
MAPE : 0.03668348118662834
r2 : 0.9785637259483337
adjusted_r2 : 0.9775893498550762
=Y_hat_df.reset_index(drop=False).drop(columns=['unique_id','ds'])
Y_hat_df = pd.concat([Y_test_df, Y_hat_df], axis=1)
plot_df = pd.concat([Y_train_df, plot_df])
plot_df =(20, 15)) plt.figure(figsize
<Figure size 2000x1500 with 0 Axes>
= plot_df[plot_df.unique_id=='Airline1'].drop('unique_id', axis=1)
plot_df 'ds'], plot_df['y'], c='black', label='True') plt.plot(plot_df[
[<matplotlib.lines.Line2D object at 0x0000022F94A5E890>]
'ds'], plot_df['DeepAR-median'], c='blue',label='median') plt.plot(plot_df[
[<matplotlib.lines.Line2D object at 0x0000022F94ADB400>]
=plot_df['ds'][-12:],
plt.fill_between(x=plot_df['DeepAR-lo-90'][-12:].values,
y1=plot_df['DeepAR-hi-90'][-12:].values,
y2=0.4, label='level 90') alpha
<matplotlib.collections.FillBetweenPolyCollection object at 0x0000022F94AD8D30>
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
plt.legend()
<matplotlib.legend.Legend object at 0x0000022F94A97160>
plt.grid() plt.plot()
[]
Neural Basis Expansion Analysis (NBEATS)
NBEATS architecture was developed in the process of exploring the use of deep learning to solve univariate time series forecasting use cases. This architecture is designed using a deep learning network with multiple fully connected layers and relies on a network of backward and forward residual links. The intention of including this model in our journey to understand time series forecasting with GenAI is that this model was the first pure deep learning approach that performed better than existing statistical approaches in the Makridakis M-competition. The NBEATS model surpassed the winning solution of the M4 competition.
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from IPython.display import display, Markdown
import matplotlib.pyplot as plt
from ray import tune
from neuralforecast.core import NeuralForecast
from neuralforecast.models import NBEATS, NHITS
from neuralforecast.utils import AirPassengersDF
= AirPassengersDF
Y_df = Y_df.reset_index(drop=True)
Y_df Y_df.head()
unique_id ds y
0 1.0 1949-01-31 112.0
1 1.0 1949-02-28 118.0
2 1.0 1949-03-31 132.0
3 1.0 1949-04-30 129.0
4 1.0 1949-05-31 121.0
= Y_df.head(132)
train_data = Y_df.tail(12) test_data
Y_hat_df.head()
index unique_id ds NBEATS
0 0 1.0 1960-01-31 421.764130
1 1 1.0 1960-02-29 437.824432
2 2 1.0 1960-03-31 454.093109
3 3 1.0 1960-04-30 454.956543
4 4 1.0 1960-05-31 502.554260
'y']],Y_hat_df['NBEATS']) calculate_error_metrics(test_data[[
MSE : 984.4974975585938
RMSE : 31.37670310212011
MAPE : 0.06071820482611656
r2 : 0.8222759366035461
adjusted_r2 : 0.8045035302639008
'ds',inplace =True)
train_data.set_index('ds',inplace =True)
Y_hat_df.set_index('ds',inplace =True)
test_data.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= "airline_1"
item_id = train_data["y"]
y_past = Y_hat_df['NBEATS']
y_pred = test_data["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94A945B0>]
="Mean forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F94C1F3A0>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94C0C6D0>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Transformers for Time Series
Transformers initially revolutionized natural language processing and have increasingly found their application in other realms such as computer vision, audio processing, bioinformatics, finance, robotics, and time series analysis.
Transformers are designed using stacked self-attention and pointwise, fully connected layers for both the encoder and decoder. Transformers are built on encoder-decoder architecture. The encoder applies the mathematical function to the data and transforms input to a certain representation, while the decoder applies the inverse function to recover back the original data.
Vanilla Transformer
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import MLP,VanillaTransformer
from neuralforecast.losses.pytorch import MQLoss, DistributionLoss,MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengers, AirPassengersPanel, AirPassengersStatic, augment_calendar_df
from neuralforecast.utils import AirPassengersDF as Y_df
print(Y_df)
unique_id ds y
0 1.0 1949-01-31 112.0
1 1.0 1949-02-28 118.0
2 1.0 1949-03-31 132.0
3 1.0 1949-04-30 129.0
4 1.0 1949-05-31 121.0
.. ... ... ...
139 1.0 1960-08-31 606.0
140 1.0 1960-09-30 508.0
141 1.0 1960-10-31 461.0
142 1.0 1960-11-30 390.0
143 1.0 1960-12-31 432.0
[144 rows x 3 columns]
= Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31'] Y_test_df
forecasts.head()
unique_id ds VanillaTransformer
0 1.0 1960-01-31 390.566284
1 1.0 1960-02-29 410.820770
2 1.0 1960-03-31 431.629608
3 1.0 1960-04-30 442.306793
4 1.0 1960-05-31 468.161926
'y']],forecasts['VanillaTransformer']) calculate_error_metrics(Y_test_df[[
MSE : 4713.275390625
RMSE : 68.65329846864607
MAPE : 0.10067308694124222
r2 : 0.1491471529006958
adjusted_r2 : 0.06406186819076543
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
forecasts.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= Y_train_df["y"]
y_past = forecasts['VanillaTransformer']
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94D88820>]
="Forecast") plt.plot(forecasts, label
[<matplotlib.lines.Line2D object at 0x0000022F94D8AE90>, <matplotlib.lines.Line2D object at 0x0000022F94D8AE60>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94D78D30>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Inverted Transformers
iTransformers take the transformer architecture but apply the attention and feedforward network on the inverted dimensions. This means that the time points of each individual series are embedded into variate tokens which can be used by the attention mechanisms to capture multivariate correlation, and the feedforward network learns nonlinear relationships.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import iTransformer
from neuralforecast.losses.pytorch import MQLoss, DistributionLoss,MSE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengersDF as Y_df
= Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31']
Y_test_df *_ = TimeSeriesDataset.from_df(Y_train_df) dataset,
Y_test_df.head()
unique_id ds y iTransformers
132 1.0 1960-01-31 417.0 431.639618
133 1.0 1960-02-29 391.0 395.834778
134 1.0 1960-03-31 419.0 450.014862
135 1.0 1960-04-30 461.0 444.223022
136 1.0 1960-05-31 472.0 475.579132
'y']],Y_test_df['iTransformers']) calculate_error_metrics(Y_test_df[[
MSE : 494.6007995605469
RMSE : 22.23962228907107
MAPE : 0.035653989762067795
r2 : 0.9107133746147156
adjusted_r2 : 0.9017847120761872
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= Y_train_df["y"]
y_past = Y_test_df['iTransformers']
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94E21750>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F94E9E740>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94E9E470>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
DLinear
DLinear is a combination of a decomposition scheme used in Autoformer and FEDformer with linear layers. It decomposes raw data input into a trend component by a moving average kernel and a remainder or seasonal component. Then, two one-layer linear layers are applied to each component, and we sum up the two features to get the final prediction. By explicitly handling trends, DLinear enhances the performance of a vanilla linear when there is a clear trend in the data.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import MLP,DLinear
from neuralforecast.losses.pytorch import MQLoss, DistributionLoss,MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengers, AirPassengersPanel, AirPassengersStatic, augment_calendar_df
from neuralforecast.utils import AirPassengersDF
= AirPassengersDF
Y_df = Y_df.reset_index(drop=True)
Y_df = Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31'] Y_test_df
'y']],forecasts['DLinear']) calculate_error_metrics(Y_test_df[[
MSE : 1411.2696533203125
RMSE : 37.56686909126594
MAPE : 0.07227641344070435
r2 : 0.7452338933944702
adjusted_r2 : 0.7197572827339173
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
forecasts.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= Y_train_df["y"]
y_past = forecasts['DLinear']
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94B65E40>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F94A8C460>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94A8FAC0>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
NLinear
NLinear is part of the LTSF-Linear family of models specifically designed to boost the performance of Linear when there is a distribution shift in the dataset. NLinear first subtracts the input by the last value of the sequence, then the input goes through a linear layer, and the subtracted part is added back before making the final prediction. The subtraction and addition in NLinear are a simple normalization for the input sequence.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import MLP,NLinear
from neuralforecast.losses.pytorch import MQLoss, DistributionLoss,MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengers, AirPassengersPanel, AirPassengersStatic, augment_calendar_df
from neuralforecast.utils import AirPassengersDF
def calculate_error_metrics(actual, predicted, num_predictors=1):
# convert inputs are numpy arrays
= np.array(actual)
actual = np.array(predicted)
predicted # Number of observations
= len(actual)
n # Calculate MSE
= mean_squared_error(actual, predicted)
mse # Calculate RMSE
= np.sqrt(mse)
rmse # Calculate MAPE
= mean_absolute_percentage_error(actual, predicted)
mape # Calculate R-squared
= r2_score(actual, predicted)
r2 # Calculate Adjusted R-squared
= 1 - ((1 - r2) * (n - 1) / (n - num_predictors - 1))
adjusted_r2 print(f'MSE : {mse}')
print(f'RMSE : {rmse}')
print(f'MAPE : {mape}')
print(f'r2 : {r2}')
print(f'adjusted_r2 : {adjusted_r2}')
= AirPassengersDF
Y_df = Y_df.reset_index(drop=True)
Y_df Y_df.head()
unique_id ds y
0 1.0 1949-01-31 112.0
1 1.0 1949-02-28 118.0
2 1.0 1949-03-31 132.0
3 1.0 1949-04-30 129.0
4 1.0 1949-05-31 121.0
= Y_df[Y_df.ds<='1959-12-31']
Y_train_df = Y_df[Y_df.ds>'1959-12-31'] Y_test_df
'y']],forecasts['NLinear']) calculate_error_metrics(Y_test_df[[
MSE : 1214.2550048828125
RMSE : 34.846161982100874
MAPE : 0.06048479303717613
r2 : 0.7807995080947876
adjusted_r2 : 0.7588794589042663
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
forecasts.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= Y_train_df["y"]
y_past = forecasts['NLinear']
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94ADB820>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F949D9300>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94A8FB20>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Patch Time Series Transformer (PatchTST)
PatchTST supports multivariate time series forecasting and self-supervised representation learning. It is based on the segmentation of time series into subseries-level patches, which serve as input tokens to the transformer. Channel independence is a property of PatchTST where each channel contains a single univariate time series. Channel independence helps share the same embedding and transformer weights across all the series. This helps the PatchTST model to apply attention weights separately to each channel, which helps in better capturing the unique features and patterns in each channel.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from neuralforecast import NeuralForecast
from neuralforecast.models import PatchTST
from neuralforecast.losses.pytorch import MQLoss, DistributionLoss,MAE
from neuralforecast.tsdataset import TimeSeriesDataset
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast.utils import AirPassengers, AirPassengersPanel, AirPassengersStatic, augment_calendar_df
from neuralforecast.utils import AirPassengersDF as Y_df
= Y_df[Y_df.ds<='1959-12-31'] # 132 train
Y_train_df = Y_df[Y_df.ds>'1959-12-31'] # 12 test
Y_test_df *_ = TimeSeriesDataset.from_df(Y_train_df) dataset,
'y']],forecasts['PatchTST']) calculate_error_metrics(Y_test_df[[
MSE : 1530.150390625
RMSE : 39.11713678971149
MAPE : 0.07313370704650879
r2 : 0.7237732410430908
adjusted_r2 : 0.6961505651473999
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
forecasts.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= Y_train_df["y"]
y_past = forecasts['PatchTST']
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F948A5CF0>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F94882800>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F94883880>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
Reprogramming Large Language Model (Time-LLM)
A Large Language Model is a type of artificial intelligence model that uses machine learning techniques to process and generate human language at a scale much larger than traditional models.
These models are trained on vast amounts of text data, often encompassing entire libraries of books, website articles, social media posts, and other publicly available information. The primary function of an LLM is to predict and generate coherent and contextually relevant sequences of words, allowing it to perform tasks such as answering questions, translating languages, summarizing texts, and even generating creative writing or code.
A TIME-LLM, is a reprogramming framework to adapt large language models for time series forecasting while keeping the backbone model intact. The core idea is to reprogram the input time series into text prototype representations that are more naturally suited to language models’ capabilities.
#!pip install transformers
#!pip install psutil
#!pip install huggingface_hub
#!pip install hf_xet
#!pip install torch torchaudio torchvision --index-url https://download.pytorch.org/whl/nightly/cu128 --force-reinstall --no-cache-dir
import torch
import psutil
import platform
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error, r2_score
from neuralforecast import NeuralForecast
from neuralforecast.models import TimeLLM
from neuralforecast.utils import AirPassengersPanel, augment_calendar_df
from transformers import GPT2Config, GPT2Model, GPT2Tokenizer
= torch.cuda.is_available()
use_cuda
if use_cuda:
print('__CUDNN VERSION:', torch.backends.cudnn.version())
print('__Number CUDA Devices:', torch.cuda.device_count())
print('__CUDA Device Name:',torch.cuda.get_device_name(0))
print('__CUDA Device Total Memory [GB]:',torch.cuda.get_device_properties(0).total_memory/1e9)
= psutil.virtual_memory()
mem print("Available Memory:")
Available Memory:
print(" Total:", mem.total / (1024 ** 2), "MB")
Total: 65384.01953125 MB
= psutil.cpu_count()
cpu_count = psutil.cpu_count(logical=True)
cpu_count_logical print("\nCPU Details:")
CPU Details:
print(" Physical Cores:", cpu_count)
Physical Cores: 32
print(" Logical Cores:", cpu_count_logical)
Logical Cores: 32
= platform.platform()
platform_info print("\nPlatform:", platform_info)
Platform: Windows-10-10.0.26100-SP0
from neuralforecast.utils import AirPassengersDF
= AirPassengersDF
Y_df = Y_df.reset_index(drop=True)
Y_df Y_df.head()
unique_id ds y
0 1.0 1949-01-31 112.0
1 1.0 1949-02-28 118.0
2 1.0 1949-03-31 132.0
3 1.0 1949-04-30 129.0
4 1.0 1949-05-31 121.0
= Y_df[Y_df.ds<='1959-12-31'] # 132 train
Y_train_df = Y_df[Y_df.ds>'1959-12-31'] # 12 test
Y_test_df
= GPT2Config.from_pretrained('gpt2')
gpt2_config = GPT2Model.from_pretrained('gpt2', config=gpt2_config)
gpt2 = GPT2Tokenizer.from_pretrained('gpt2')
gpt2_tokenizer
= "The dataset contains data on monthly air passengers. There is a yearly seasonality" prompt_prefix
forecasts1.head()
unique_id ds TimeLLM
0 1.0 1960-01-31 411.856049
1 1.0 1960-02-29 435.284607
2 1.0 1960-03-31 442.377167
3 1.0 1960-04-30 433.812866
4 1.0 1960-05-31 442.045441
'y']],forecasts1['TimeLLM']) calculate_error_metrics(Y_test_df[[
MSE : 5853.29833984375
RMSE : 76.50685158757841
MAPE : 0.10379436612129211
r2 : -0.05665266513824463
adjusted_r2 : -0.1623179316520691
'ds',inplace =True)
Y_train_df.set_index('ds',inplace =True)
forecasts1.set_index('ds',inplace =True)
Y_test_df.set_index(=(25, 20)) plt.figure(figsize
<Figure size 2500x2000 with 0 Axes>
= Y_train_df["y"]
y_past = forecasts1['TimeLLM']
y_pred = Y_test_df["y"]
y_test ="Past time series values") plt.plot(y_past, label
[<matplotlib.lines.Line2D object at 0x0000022F94984D90>]
="Forecast") plt.plot(y_pred, label
[<matplotlib.lines.Line2D object at 0x0000022F949BD930>]
="Actual time series values") plt.plot(y_test, label
[<matplotlib.lines.Line2D object at 0x0000022F949BCA00>]
'AirPassengers Forecast', fontsize=10) plt.title(
Text(0.5, 1.0, 'AirPassengers Forecast')
'Monthly Passengers', fontsize=10) plt.ylabel(
Text(0, 0.5, 'Monthly Passengers')
'Timestamp [t]', fontsize=10) plt.xlabel(
Text(0.5, 0, 'Timestamp [t]')
; plt.legend()
A Time Series LLM for Universal Forecasting (MOIRAI)
The Masked EncOder-based UnIveRsAl Time Series Forecasting Transformer, or in short MOIRAI, is a result of novel enhancements made to the traditional time series forecasting transformer. The current version of the model was developed by training on a dataset containing observations taken across nine domains and has around 27B observations. In our experience, we found MOIRAI useful in scenarios involving zeroshot forecasting. In some use cases, it was providing results on par with multi-shot forecasting models. MOIRAI is trained and made available in three sizes, MOIRAISmall, MOIRAIBase, and MOIRAILarge, with 14m, 91m, and 311m parameters, respectively.
#!pip install gluonts
#!pip install torch
#!pip install matplotlib
#!pip install einops
#!pip install gluonts
#!pip install uni2ts
#!pip install scikit-learn