Source code for models

from fireTS.core import GeneralAutoRegressor
from sklearn.utils.validation import check_X_y
from sklearn.metrics.regression import r2_score, mean_squared_error
import numpy as np


[docs]class NARX(GeneralAutoRegressor): r""" NARX stands for `Nonlinear AutoRegressive eXogenous model <https://en.wikipedia.org/wiki/Nonlinear_autoregressive_exogenous_model>`_. The model equation is written as follows. .. math:: y(t + 1) &=& f(y(t), ..., y(t-p+1), \\ & & x_1(t - d_1), ..., x_1(t-d_1-q_1+1), \\ & & ..., x_m(t - d_1), ..., x_m(t - d_m - q_m + 1)) + e(t) :label: narx :param object base_estimator: an estimator object that implements the scikit-learn API (fit, and predict). The estimator will be used to fit the function :math:`f` in equation :eq:`narx`. :param int auto_order: the autoregression order :math:`p` in equation :eq:`narx`. :param list exog_order: the exogenous input order, a list of integers representing the order for each exogenous input, i.e. :math:`[q_1, q_2, ..., q_m]` in equation :eq:`narx`. :param list exog_delay: the delays of the exogenous inputs, a list of integers representing the delay of each exogenous input, i.e. :math:`[d_1, d_2, ..., d_m]` in equation :eq:`narx`. By default, all the delays are set to 0. :param dict base_params: other keyword arguments for base_estimator. """ def __init__(self, base_estimator, auto_order, exog_order, exog_delay=None, **base_params): super(NARX, self).__init__( base_estimator, auto_order, exog_order, exog_delay=exog_delay, pred_step=1, **base_params)
[docs] def score(self, X, y, step=1, method="r2"): """ Produce multi-step prediction of y, and compute the metrics against y. Nan is ignored when computing the metrics. :param array-like X: exogenous input time series, shape = (n_samples, n_exog_inputs) :param array-like y: target time series to predict, shape = (n_samples) :param int step: prediction step. :param string method: could be "r2" (R Square) or "mse" (Mean Square Error). :return: prediction metric. Nan is ignored when computing the metrics. """ ypred = self.predict(X, y, step=step) mask = np.isnan(y) | np.isnan(ypred) if method == "r2": return r2_score(y[~mask], ypred[~mask]) elif method == "mse": return mean_squared_error(y[~mask], ypred[~mask])
# TODO: add forecast method
[docs] def predict(self, X, y, step=1): r""" Produce multi-step prediction of y. The multi-step prediction is done recursively by using the future inputs in X. The prediction equation is as follows: .. math:: \hat{y}(t + k) &=& f(\hat{y}(t + k - 1), ..., \hat{y}(t + k - p), \\ & &x_1(t + k - 1 - d_1), ..., x_1(t + k - d_1 - q_1) \\ & &..., x_m(t + k - 1 - d_m), ..., x_m(t + k - d_m - q_m)) :param array-like X: exogenous input time series, shape = (n_samples, n_exog_inputs) :param array-like y: target time series to predict, shape = (n_samples) :param int step: prediction step. :return: k-step prediction time series, shape = (n_samples). The :math:`i` th value of the output is the k-step prediction of the :math:`i` th value of the input ``y``. The first ``step + max(auto_order, max(exog_order + exog_delay))`` values of the output is ``np.nan``. """ X, y = check_X_y(X, y, y_numeric=True) if len(self.exog_order) != X.shape[1]: raise ValueError( 'The number of columns of X must be the same as the length of exog_order.' ) p = self._get_lag_feature_processor(X, y) features = p.generate_lag_features() for k in range(step): yhat = self._predictNA(features) if k == step - 1: break data_new = [yhat] data_new.extend([None] * len(self.exog_order)) features = p.update(data_new) ypred = np.concatenate([np.empty(step) * np.nan, yhat])[0:len(y)] return ypred
[docs]class DirectAutoRegressor(GeneralAutoRegressor): r""" This model performs autoregression with exogenous inputs on the k-step ahead output directly. The model equation is written as follows. .. math:: y(t + k) &=& f(y(t), ..., y(t-p+1), \\ & & x_1(t - d_1), ..., x_1(t-d_1-q_1+1), \\ & & ..., x_m(t - d_1), ..., x_m(t - d_m - q_m + 1)) + e(t) :label: narx :param object base_estimator: an estimator object that implements the scikit-learn API (fit, and predict). The estimator will be used to fit the function :math:`f` in equation :eq:`narx`. :param int auto_order: the autoregression order :math:`p` in equation :eq:`narx`. :param list exog_order: the exogenous input order, a list of integers representing the order for each exogenous input, i.e. :math:`[q_1, q_2, ..., q_m]` in equation :eq:`narx`. :param int pred_step: the prediction step :math:`k` in equation :eq:`gar`. By default, it is set to 1. :param list exog_delay: the delays of the exogenous inputs, a list of integers representing the delay of each exogenous input, i.e. :math:`[d_1, d_2, ..., d_m]` in equation :eq:`narx`. By default, all the delays are set to 0. :param dict base_params: other keyword arguments for base_estimator. """ def __init__(self, base_estimator, auto_order, exog_order, pred_step, exog_delay=None, **base_params): super(NARX, self).__init__( base_estimator, auto_order, exog_order, exog_delay=exog_delay, pred_step=pred_step, **base_params)
[docs] def predict(self, X, y): r""" Produce multi-step prediction of y. The multi-step prediction is done directly. No future X inputs are used in the prediction. The prediction equation is as follows: .. math:: \hat{y}(t + k) &=& f(y(t - 1), ..., y(t - p + 1), \\ & & x_1(t - d_1), ..., x_1(t - d_1 - q_1 + 1) \\ & & ..., x_m(t - d_m), ..., x_m(t - d_m - q_m + 1)) :param array-like X: exogenous input time series, shape = (n_samples, n_exog_inputs) :param array-like y: target time series to predict, shape = (n_samples) :param int step: prediction step. :return: k-step prediction time series, shape = (n_samples). The :math:`i` th value of the output is the k-step prediction of the :math:`i` th value of the input ``y``. The first ``step + max(auto_order, max(exog_order + exog_delay))`` values of the output is ``np.nan``. """ X, y = check_X_y(X, y, y_numeric=True) if len(self.exog_order) != X.shape[1]: raise ValueError( 'The number of columns of X must be the same as the length of exog_order.' ) p = self._get_lag_feature_processor(X, y) features = p.generate_lag_features() yhat = self._predictNA(features) ypred = np.concatenate([np.empty(self.pred_step) * np.nan, yhat])[0:len(y)] return ypred
[docs] def score(self, X, y, method="r2"): """ Produce multi-step prediction of y, and compute the metrics against y. Nan is ignored when computing the metrics. :param array-like X: exogenous input time series, shape = (n_samples, n_exog_inputs) :param array-like y: target time series to predict, shape = (n_samples) :param string method: could be "r2" (R Square) or "mse" (Mean Square Error). :return: prediction metric. Nan is ignored when computing the metrics. """ ypred = self.predict(X, y) mask = np.isnan(y) | np.isnan(ypred) if method == "r2": return r2_score(y[~mask], ypred[~mask]) elif method == "mse": return mean_squared_error(y[~mask], ypred[~mask])