{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Parameter Estimation\n",
    "\n",
    "Example created by Wilson Rocha Lacerda Junior"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "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."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sysidentpy.model_structure_selection import FROLS\n",
    "from sysidentpy.basis_function._basis_function import Polynomial\n",
    "from sysidentpy.metrics import root_relative_squared_error\n",
    "from sysidentpy.utils.generate_data import get_siso_data\n",
    "from sysidentpy.utils.display_results import results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generating 1 input 1 output sample data  \n",
    "\n",
    "The data is generated by simulating the following model:\n",
    "\n",
    "$y_k = 0.2y_{k-1} + 0.1y_{k-1}x_{k-1} + 0.9x_{k-1} + e_{k}$\n",
    "\n",
    "If *colored_noise* is set to True:\n",
    "\n",
    "$e_{k} = 0.8\\nu_{k-1} + \\nu_{k}$\n",
    "\n",
    "where $x$ is a uniformly distributed random variable and $\\nu$ is a gaussian distributed variable with $\\mu=0$ and $\\sigma=0.1$\n",
    "\n",
    "In the next example we will generate a data with 1000 samples with white noise and selecting 90% of the data to train the model. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train, x_valid, y_train, y_valid = get_siso_data(\n",
    "    n=1000,\n",
    "    colored_noise=False,\n",
    "    sigma=0.001,\n",
    "    train_percentage=90\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### There are several method to be used for parameter estimation.\n",
    "\n",
    "- least_squares; \n",
    "- total_least_squares;\n",
    "- recursive_least_squares; \n",
    "- least_mean_squares\n",
    "- affine_least_mean_squares\n",
    "- least_mean_squares_sign_error\n",
    "- normalized_least_mean_squares\n",
    "- least_mean_squares_normalized_sign_error\n",
    "- least_mean_squares_sign_regressor\n",
    "- least_mean_squares_normalized_sign_regressor\n",
    "- least_mean_squares_sign_sign\n",
    "- least_mean_squares_normalized_sign_sign\n",
    "- least_mean_squares_normalized_leaky\n",
    "- least_mean_squares_leaky\n",
    "- least_mean_squares_fourth\n",
    "- least_mean_squares_mixed_norm\n",
    "\n",
    "\n",
    "Polynomial NARMAX models are linear-in-the-parameter, so Least Squares based methods works well for most cases (using with extended least squares algorithm when dealing with colered noise). \n",
    "\n",
    "However, the user can choose some recursive and stochastic gradient descent methods (in this case, the least mean squares algorithm and its variants) to that task too.\n",
    "\n",
    "Choosing the method is straightforward: pass any of the methods mentioned above on estimator parameters.\n",
    "\n",
    "- **Note: The adaptative filters have specifc parameter that need to be tunned. In the following examples we will use the default ones. More examples regarding tunned parameter will be available soon. For now, the user can read the method documentation for more information.** "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Total Least Squares"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0017546043817803368\n",
      "      Regressors  Parameters             ERR\n",
      "0        x1(k-2)  8.9994E-01  9.55863828E-01\n",
      "1         y(k-1)  2.0002E-01  4.06706802E-02\n",
      "2  x1(k-1)y(k-1)  1.0004E-01  3.46188050E-03\n"
     ]
    }
   ],
   "source": [
    "basis_function = Polynomial(degree=2)\n",
    "\n",
    "model = FROLS(\n",
    "    order_selection=False,\n",
    "    n_terms=3,\n",
    "    extended_least_squares=False,\n",
    "    ylag=2, xlag=2,\n",
    "    estimator='total_least_squares',\n",
    "    basis_function=basis_function\n",
    ")\n",
    "model.fit(X=x_train, y=y_train)\n",
    "yhat = model.predict(X=x_valid, y=y_valid)\n",
    "rrse = root_relative_squared_error(y_valid, yhat)\n",
    "print(rrse)\n",
    "\n",
    "r = pd.DataFrame(\n",
    "    results(\n",
    "        model.final_model, model.theta, model.err,\n",
    "        model.n_terms, err_precision=8, dtype='sci'\n",
    "        ),\n",
    "    columns=['Regressors', 'Parameters', 'ERR'])\n",
    "print(r)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Recursive Least Squares"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0017428918921948222\n",
      "      Regressors  Parameters             ERR\n",
      "0        x1(k-2)  9.0005E-01  9.55863828E-01\n",
      "1         y(k-1)  1.9991E-01  4.06706802E-02\n",
      "2  x1(k-1)y(k-1)  1.0030E-01  3.46188050E-03\n"
     ]
    }
   ],
   "source": [
    "# recursive least squares\n",
    "basis_function = Polynomial(degree=2)\n",
    "\n",
    "model = FROLS(\n",
    "    order_selection=False,\n",
    "    n_terms=3,\n",
    "    extended_least_squares=False,\n",
    "    ylag=2, xlag=2,\n",
    "    estimator='recursive_least_squares',\n",
    "    basis_function=basis_function\n",
    ")\n",
    "model.fit(X=x_train, y=y_train)\n",
    "yhat = model.predict(X=x_valid, y=y_valid)\n",
    "rrse = root_relative_squared_error(y_valid, yhat)\n",
    "print(rrse)\n",
    "\n",
    "r = pd.DataFrame(\n",
    "    results(\n",
    "        model.final_model, model.theta, model.err,\n",
    "        model.n_terms, err_precision=8, dtype='sci'\n",
    "        ),\n",
    "    columns=['Regressors', 'Parameters', 'ERR'])\n",
    "print(r)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Least Mean Squares"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.011788905296672262\n",
      "      Regressors  Parameters             ERR\n",
      "0        x1(k-2)  8.9844E-01  9.55863828E-01\n",
      "1         y(k-1)  1.9880E-01  4.06706802E-02\n",
      "2  x1(k-1)y(k-1)  8.3552E-02  3.46188050E-03\n"
     ]
    }
   ],
   "source": [
    "# recursive least squares\n",
    "basis_function = Polynomial(degree=2)\n",
    "\n",
    "model = FROLS(\n",
    "    order_selection=False,\n",
    "    n_terms=3,\n",
    "    extended_least_squares=False,\n",
    "    ylag=2, xlag=2,\n",
    "    estimator='least_mean_squares',\n",
    "    basis_function=basis_function\n",
    ")\n",
    "model.fit(X=x_train, y=y_train)\n",
    "yhat = model.predict(X=x_valid, y=y_valid)\n",
    "rrse = root_relative_squared_error(y_valid, yhat)\n",
    "print(rrse)\n",
    "\n",
    "r = pd.DataFrame(\n",
    "    results(\n",
    "        model.final_model, model.theta, model.err,\n",
    "        model.n_terms, err_precision=8, dtype='sci'\n",
    "        ),\n",
    "    columns=['Regressors', 'Parameters', 'ERR'])\n",
    "print(r)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Affine Least Mean Squares"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0017565655363110896\n",
      "      Regressors  Parameters             ERR\n",
      "0        x1(k-2)  8.9983E-01  9.55863828E-01\n",
      "1         y(k-1)  2.0000E-01  4.06706802E-02\n",
      "2  x1(k-1)y(k-1)  1.0002E-01  3.46188050E-03\n"
     ]
    }
   ],
   "source": [
    "# recursive least squares\n",
    "basis_function = Polynomial(degree=2)\n",
    "\n",
    "model = FROLS(\n",
    "    order_selection=False,\n",
    "    n_terms=3,\n",
    "    extended_least_squares=False,\n",
    "    ylag=2, xlag=2,\n",
    "    estimator='affine_least_mean_squares',\n",
    "    basis_function=basis_function\n",
    ")\n",
    "model.fit(X=x_train, y=y_train)\n",
    "yhat = model.predict(X=x_valid, y=y_valid)\n",
    "rrse = root_relative_squared_error(y_valid, yhat)\n",
    "print(rrse)\n",
    "\n",
    "r = pd.DataFrame(\n",
    "    results(\n",
    "        model.final_model, model.theta, model.err,\n",
    "        model.n_terms, err_precision=8, dtype='sci'\n",
    "        ),\n",
    "    columns=['Regressors', 'Parameters', 'ERR'])\n",
    "print(r)\n"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "0e65fe37feb8ff9f7778552a28949e943d61f86c936833305e2c18cda5b438ac"
  },
  "kernelspec": {
   "display_name": "Python 3.8.11 64-bit ('rd': conda)",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
