# V0.1.6 - Information Criteria - Examples¶

Example created by Wilson Rocha Lacerda Junior

## Comparing different information criteria methods¶

Here we import the NARMAX model, the metric for model evaluation and the methods to generate sample data for tests. Also, we import pandas for specific usage.

pip install sysidentpy

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sysidentpy.polynomial_basis import PolynomialNarmax
from sysidentpy.metrics import root_relative_squared_error
from sysidentpy.utils.generate_data import get_miso_data, get_siso_data


## Generating sample data¶

The data is generated by simulating the following model: $$y_k = 0.2y_{k-1} + 0.1y_{k-1}x_{k-1} + 0.9x_{k-1} + e_{k}$$

If colored_noise is set to True:

$$e_{k} = 0.8\nu_{k-1} + \nu_{k}$$

where $$x$$ is a uniformly distributed random variable and $$\nu$$ is a gaussian distributed variable with $$\mu=0$$ and $$\sigma=0.1$$

In the next example we will generate a data with 3000 samples with white noise and selecting 90% of the data to train the model.

x_train, x_valid, y_train, y_valid = get_siso_data(n=1000,
colored_noise=False,
sigma=0.2,
train_percentage=90)


The idea is to show the impact of the information criteria to select the number of terms to compose the final model. You will se why it is an auxiliary tool and let the algorithm select the number of terms based on the minimum value is not a good idea when dealing with data highly corrupted by noise (even white noise)

Note: You may find different results when running the examples. This is due the fact we are not setting a fixed random generator for the sample data. However, the main analysis remain.

## AIC¶

model = PolynomialNarmax(non_degree=2,
order_selection=True,
n_info_values=15,
extended_least_squares=False,
ylag=2, xlag=2,
info_criteria='aic',
estimator='least_squares',
)

model.fit(x_train, y_train)
yhat = model.predict(x_valid, y_valid)
rrse = root_relative_squared_error(y_valid, yhat)
print(rrse)

results = pd.DataFrame(model.results(err_precision=8,
dtype='dec'),
columns=['Regressors', 'Parameters', 'ERR'])

print(results)

xaxis = np.arange(1, model.n_info_values + 1)
plt.plot(xaxis, model.info_values)
plt.xlabel('n_terms')
plt.ylabel('Information Criteria')

0.38202463734760717
Regressors Parameters         ERR
0        x1(k-2)     0.9210  0.84287328
1         y(k-1)     0.1867  0.03532986
2  x1(k-1)y(k-1)     0.1215  0.00403228
3       y(k-1)^2     0.0478  0.00073353
4      x1(k-1)^2    -0.0342  0.00052802

Text(0, 0.5, 'Information Criteria') model.info_values

array([-2694.09936284, -2920.43235501, -2948.99729043, -2951.5656718 ,
-2953.60017972, -2952.10447799, -2950.4899516 , -2948.64474158,
-2946.7871786 , -2944.89120846, -2942.95165921, -2940.98557817,
-2939.02706707, -2937.03646143, -2935.03708992])


As can be seen above, the minimum value make the algorithm choose a model with 5 terms. However, if you check the plot, 3 terms is the best choice. Incresase the number of terms from 3 upwards do not lead to a better model since the difference is very small.

In this case, you should run the model again with the parameters n_terms=3! The ERR algorithm ordered the terms in a correct way, so you will get the exact model structure again!

## BIC¶

model = PolynomialNarmax(non_degree=2,
order_selection=True,
n_info_values=15,
extended_least_squares=False,
ylag=2, xlag=2,
info_criteria='bic',
estimator='least_squares',
)

model.fit(x_train, y_train)
yhat = model.predict(x_valid, y_valid)
rrse = root_relative_squared_error(y_valid, yhat)
print(rrse)

results = pd.DataFrame(model.results(err_precision=8,
dtype='dec'),
columns=['Regressors', 'Parameters', 'ERR'])

print(results)

xaxis = np.arange(1, model.n_info_values + 1)
plt.plot(xaxis, model.info_values)
plt.xlabel('n_terms')
plt.ylabel('Information Criteria')

0.38121187399853695
Regressors Parameters         ERR
0        x1(k-2)     0.9235  0.84287328
1         y(k-1)     0.1864  0.03532986
2  x1(k-1)y(k-1)     0.1188  0.00403228

Text(0, 0.5, 'Information Criteria') model.info_values

array([-2689.29919277, -2910.83201488, -2934.59678022, -2932.36499152,
-2929.59932938, -2923.30345758, -2916.88876112, -2910.24338103,
-2903.58564799, -2896.88950777, -2890.14978846, -2883.38353735,
-2876.62485618, -2869.83408047, -2863.03453889])


BIC did a better job in this case! The way it penalizes the model regarding the number of terms ensure that the minimum value here was exact the number of expected terms to compose the model. Good, but not aways the best method!

## LILC¶

model = PolynomialNarmax(non_degree=2,
order_selection=True,
n_info_values=15,
extended_least_squares=False,
ylag=2, xlag=2,
info_criteria='lilc',
estimator='least_squares',
)

model.fit(x_train, y_train)
yhat = model.predict(x_valid, y_valid)
rrse = root_relative_squared_error(y_valid, yhat)
print(rrse)

results = pd.DataFrame(model.results(err_precision=8,
dtype='dec'),
columns=['Regressors', 'Parameters', 'ERR'])

print(results)

xaxis = np.arange(1, model.n_info_values + 1)
plt.plot(xaxis, model.info_values)
plt.xlabel('n_terms')
plt.ylabel('Information Criteria')

0.38202463734760717
Regressors Parameters         ERR
0        x1(k-2)     0.9210  0.84287328
1         y(k-1)     0.1867  0.03532986
2  x1(k-1)y(k-1)     0.1215  0.00403228
3       y(k-1)^2     0.0478  0.00073353
4      x1(k-1)^2    -0.0342  0.00052802

Text(0, 0.5, 'Information Criteria') model.info_values


LILC also includes spurious terms. Like AIC, it fails to automatically select the correct terms but you could select the right number based on the plot above!

## FPE¶

model = PolynomialNarmax(non_degree=2,
order_selection=True,
n_info_values=15,
extended_least_squares=False,
ylag=2, xlag=2,
info_criteria='fpe',
estimator='least_squares',
)

model.fit(x_train, y_train)
yhat = model.predict(x_valid, y_valid)
rrse = root_relative_squared_error(y_valid, yhat)
print(rrse)

results = pd.DataFrame(model.results(err_precision=8,
dtype='dec'),
columns=['Regressors', 'Parameters', 'ERR'])

print(results)

xaxis = np.arange(1, model.n_info_values + 1)
plt.plot(xaxis, model.info_values)
plt.xlabel('n_terms')
plt.ylabel('Information Criteria')

0.38202463734760717
Regressors Parameters         ERR
0        x1(k-2)     0.9210  0.84287328
1         y(k-1)     0.1867  0.03532986
2  x1(k-1)y(k-1)     0.1215  0.00403228
3       y(k-1)^2     0.0478  0.00073353
4      x1(k-1)^2    -0.0342  0.00052802

Text(0, 0.5, 'Information Criteria') model.info_values

array([-2694.09936201, -2920.4323484 , -2948.99726811, -2951.56561889,
-2953.60007638, -2952.10429942, -2950.48966802, -2948.64431828,
-2946.78657589, -2944.89038168, -2942.95055875, -2940.98414946,
-2939.02525054, -2937.03419259, -2935.03429929])


FPE also failed to automatically select the right number of terms! But, as we pointed out before, Information Criteria is an auxiliary tool! If you look at the plots, all the methods allows you to choose the right numbers of terms!

## Important Note¶

Here we are dealing with a known model structure! Concerning real data, we do not know the right number of terms so the methods above stands as excellent tools to help you out!

If you check the metrics above, even with the models with more terms, you will see excellent metrics! But System Identification always search for the best model structure! Model Structure Selection is the core of NARMAX methods! In this respect, the examples are to show basic concepts and how the algorithms work!