{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "!pip install -Uqq nixtla utilsforecast"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide \n",
    "from nixtla.utils import in_colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide \n",
    "IN_COLAB = in_colab()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "if not IN_COLAB:\n",
    "    from nixtla.utils import colab_badge\n",
    "    from dotenv import load_dotenv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Forecasting web traffic\n",
    "\n",
    "Our task is to forecast the next 7 days of daily visits to the website [cienciadedatos.net](cienciadedatos.net).\n",
    "\n",
    "In this tutorial we will show:\n",
    "\n",
    "* How to load time series data to be used for forecasting with TimeGPT\n",
    "\n",
    "* How to create cross-validated forecasts with TimeGPT\n",
    "\n",
    "This tutorial is an adaptation from [Joaquín Amat Rodrigo, Javier Escobar Ortiz, \"Forecasting web traffic with machine learning and Python\"](https://cienciadedatos.net/documentos/py37-forecasting-web-traffic-machine-learning.html). We will show you:\n",
    "\n",
    "* how you can achieve almost 10% better forecasting results;\n",
    "\n",
    "* using significantly less lines of code;\n",
    "\n",
    "* in a fraction of the time needed to run the original tutorial."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "[![](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Nixtla/nixtla/blob/main/nbs/docs/use-cases/1_forecasting_web_traffic.ipynb)"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#| echo: false\n",
    "if not IN_COLAB:\n",
    "    load_dotenv()    \n",
    "    colab_badge('docs/use-cases/1_forecasting_web_traffic')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Import packages\n",
    "First, we import the required packages and initialize the Nixtla client."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from nixtla import NixtlaClient"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nixtla_client = NixtlaClient(\n",
    "    # defaults to os.environ.get(\"NIXTLA_API_KEY\")\n",
    "    api_key = 'my_api_key_provided_by_nixtla'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 👍 Use an Azure AI endpoint\n",
    "> \n",
    "> To use an Azure AI endpoint, remember to set also the `base_url` argument:\n",
    "> \n",
    "> `nixtla_client = NixtlaClient(base_url=\"you azure ai endpoint\", api_key=\"your api_key\")`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "if not IN_COLAB:\n",
    "    nixtla_client = NixtlaClient()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Load data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We load the website visit data, and set it to the right format to use with TimeGPT. In this case, we only need to add an identifier column for the timeseries, which we will call `daily_visits`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>users</th>\n",
       "      <th>unique_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2020-07-01</td>\n",
       "      <td>2324</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2020-07-02</td>\n",
       "      <td>2201</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2020-07-03</td>\n",
       "      <td>2146</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2020-07-04</td>\n",
       "      <td>1666</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2020-07-05</td>\n",
       "      <td>1433</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2020-07-06</td>\n",
       "      <td>2195</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>2020-07-07</td>\n",
       "      <td>2240</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>2020-07-08</td>\n",
       "      <td>2295</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>2020-07-09</td>\n",
       "      <td>2279</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>2020-07-10</td>\n",
       "      <td>2155</td>\n",
       "      <td>daily_visits</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        date  users     unique_id\n",
       "0 2020-07-01   2324  daily_visits\n",
       "1 2020-07-02   2201  daily_visits\n",
       "2 2020-07-03   2146  daily_visits\n",
       "3 2020-07-04   1666  daily_visits\n",
       "4 2020-07-05   1433  daily_visits\n",
       "5 2020-07-06   2195  daily_visits\n",
       "6 2020-07-07   2240  daily_visits\n",
       "7 2020-07-08   2295  daily_visits\n",
       "8 2020-07-09   2279  daily_visits\n",
       "9 2020-07-10   2155  daily_visits"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "url = ('https://raw.githubusercontent.com/JoaquinAmatRodrigo/Estadistica-machine-learning-python/' +\n",
    "       'master/data/visitas_por_dia_web_cienciadedatos.csv')\n",
    "df = pd.read_csv(url, sep=',', parse_dates=[0], date_format='%d/%m/%y')\n",
    "df['unique_id'] = 'daily_visits'\n",
    "\n",
    "df.head(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "That's it! No more preprocessing is necessary."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Cross-validation with TimeGPT"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can perform cross-validation on our data as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>unique_id</th>\n",
       "      <th>date</th>\n",
       "      <th>cutoff</th>\n",
       "      <th>users</th>\n",
       "      <th>TimeGPT</th>\n",
       "      <th>TimeGPT-lo-99.5</th>\n",
       "      <th>TimeGPT-lo-90</th>\n",
       "      <th>TimeGPT-lo-80</th>\n",
       "      <th>TimeGPT-hi-80</th>\n",
       "      <th>TimeGPT-hi-90</th>\n",
       "      <th>TimeGPT-hi-99.5</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-01</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>3123</td>\n",
       "      <td>3310.908447</td>\n",
       "      <td>3041.925497</td>\n",
       "      <td>3048.363220</td>\n",
       "      <td>3082.721924</td>\n",
       "      <td>3539.094971</td>\n",
       "      <td>3573.453674</td>\n",
       "      <td>3579.891397</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-02</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>2870</td>\n",
       "      <td>3090.971680</td>\n",
       "      <td>2793.535905</td>\n",
       "      <td>2838.480298</td>\n",
       "      <td>2853.750488</td>\n",
       "      <td>3328.192871</td>\n",
       "      <td>3343.463062</td>\n",
       "      <td>3388.407455</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-03</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>2020</td>\n",
       "      <td>2346.991455</td>\n",
       "      <td>2043.731296</td>\n",
       "      <td>2150.005078</td>\n",
       "      <td>2171.187012</td>\n",
       "      <td>2522.795898</td>\n",
       "      <td>2543.977832</td>\n",
       "      <td>2650.251614</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-04</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>1828</td>\n",
       "      <td>2182.191895</td>\n",
       "      <td>1836.848173</td>\n",
       "      <td>1897.684900</td>\n",
       "      <td>1929.914575</td>\n",
       "      <td>2434.469214</td>\n",
       "      <td>2466.698889</td>\n",
       "      <td>2527.535616</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-05</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>2722</td>\n",
       "      <td>3082.715088</td>\n",
       "      <td>2736.008055</td>\n",
       "      <td>2746.997034</td>\n",
       "      <td>2791.375342</td>\n",
       "      <td>3374.054834</td>\n",
       "      <td>3418.433142</td>\n",
       "      <td>3429.422121</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      unique_id        date     cutoff  users      TimeGPT  TimeGPT-lo-99.5  \\\n",
       "0  daily_visits  2021-07-01 2021-06-30   3123  3310.908447      3041.925497   \n",
       "1  daily_visits  2021-07-02 2021-06-30   2870  3090.971680      2793.535905   \n",
       "2  daily_visits  2021-07-03 2021-06-30   2020  2346.991455      2043.731296   \n",
       "3  daily_visits  2021-07-04 2021-06-30   1828  2182.191895      1836.848173   \n",
       "4  daily_visits  2021-07-05 2021-06-30   2722  3082.715088      2736.008055   \n",
       "\n",
       "   TimeGPT-lo-90  TimeGPT-lo-80  TimeGPT-hi-80  TimeGPT-hi-90  TimeGPT-hi-99.5  \n",
       "0    3048.363220    3082.721924    3539.094971    3573.453674      3579.891397  \n",
       "1    2838.480298    2853.750488    3328.192871    3343.463062      3388.407455  \n",
       "2    2150.005078    2171.187012    2522.795898    2543.977832      2650.251614  \n",
       "3    1897.684900    1929.914575    2434.469214    2466.698889      2527.535616  \n",
       "4    2746.997034    2791.375342    3374.054834    3418.433142      3429.422121  "
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timegpt_cv_df = nixtla_client.cross_validation(\n",
    "    df, \n",
    "    h=7, \n",
    "    n_windows=8, \n",
    "    time_col='date', \n",
    "    target_col='users', \n",
    "    freq='D',\n",
    "    level=[80, 90, 99.5]\n",
    ")\n",
    "timegpt_cv_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 📘 Available models in Azure AI\n",
    ">\n",
    "> If you are using an Azure AI endpoint, please be sure to set `model=\"azureai\"`:\n",
    ">\n",
    "> `nixtla_client.cross_validation(..., model=\"azureai\")`\n",
    "> \n",
    "> For the public API, we support two models: `timegpt-1` and `timegpt-1-long-horizon`. \n",
    "> \n",
    "> By default, `timegpt-1` is used. Please see [this tutorial](https://docs.nixtla.io/docs/tutorials-long_horizon_forecasting) on how and when to use `timegpt-1-long-horizon`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here, we have performed a rolling cross-validation of 8 folds. Let's plot the cross-validated forecasts including the prediction intervals:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 159204 characters]",
      "text/plain": [
       "<Figure size 2400x350 with 1 Axes>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nixtla_client.plot(\n",
    "    df, \n",
    "    timegpt_cv_df.drop(columns=['cutoff', 'users']), \n",
    "    time_col='date',\n",
    "    target_col='users',\n",
    "    max_insample_length=90, \n",
    "    level=[80, 90, 99.5]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This looks reasonable, and very comparable to the results obtained [here](https://cienciadedatos.net/documentos/py37-forecasting-web-traffic-machine-learning.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check the Mean Absolute Error of our cross-validation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from utilsforecast.losses import mae"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>unique_id</th>\n",
       "      <th>TimeGPT</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>167.691711</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      unique_id     TimeGPT\n",
       "0  daily_visits  167.691711"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mae_timegpt = mae(df = timegpt_cv_df.drop(columns=['cutoff']),\n",
    "    models=['TimeGPT'],\n",
    "    target_col='users')\n",
    "\n",
    "mae_timegpt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The MAE of our backtest is `167.69`. Hence, not only did TimeGPT achieve a lower MAE compared to the fully customized pipeline [here](https://cienciadedatos.net/documentos/py37-forecasting-web-traffic-machine-learning.html), the error of the forecast is also lower."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Exogenous variables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's add some exogenous variables to see if we can improve the forecasting performance further.\n",
    "\n",
    "We will add weekday indicators, which we will extract from the `date` column."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>date</th>\n",
       "      <th>users</th>\n",
       "      <th>unique_id</th>\n",
       "      <th>week_day_1</th>\n",
       "      <th>week_day_2</th>\n",
       "      <th>week_day_3</th>\n",
       "      <th>week_day_4</th>\n",
       "      <th>week_day_5</th>\n",
       "      <th>week_day_6</th>\n",
       "      <th>week_day_7</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2020-07-01</td>\n",
       "      <td>2324</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2020-07-02</td>\n",
       "      <td>2201</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2020-07-03</td>\n",
       "      <td>2146</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2020-07-04</td>\n",
       "      <td>1666</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2020-07-05</td>\n",
       "      <td>1433</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2020-07-06</td>\n",
       "      <td>2195</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>2020-07-07</td>\n",
       "      <td>2240</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>2020-07-08</td>\n",
       "      <td>2295</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>2020-07-09</td>\n",
       "      <td>2279</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>2020-07-10</td>\n",
       "      <td>2155</td>\n",
       "      <td>daily_visits</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "        date  users     unique_id  week_day_1  week_day_2  week_day_3  \\\n",
       "0 2020-07-01   2324  daily_visits           0           0           1   \n",
       "1 2020-07-02   2201  daily_visits           0           0           0   \n",
       "2 2020-07-03   2146  daily_visits           0           0           0   \n",
       "3 2020-07-04   1666  daily_visits           0           0           0   \n",
       "4 2020-07-05   1433  daily_visits           0           0           0   \n",
       "5 2020-07-06   2195  daily_visits           1           0           0   \n",
       "6 2020-07-07   2240  daily_visits           0           1           0   \n",
       "7 2020-07-08   2295  daily_visits           0           0           1   \n",
       "8 2020-07-09   2279  daily_visits           0           0           0   \n",
       "9 2020-07-10   2155  daily_visits           0           0           0   \n",
       "\n",
       "   week_day_4  week_day_5  week_day_6  week_day_7  \n",
       "0           0           0           0           0  \n",
       "1           1           0           0           0  \n",
       "2           0           1           0           0  \n",
       "3           0           0           1           0  \n",
       "4           0           0           0           1  \n",
       "5           0           0           0           0  \n",
       "6           0           0           0           0  \n",
       "7           0           0           0           0  \n",
       "8           1           0           0           0  \n",
       "9           0           1           0           0  "
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# We have 7 days, for each day a separate column denoting 1/0\n",
    "for i in range(7):\n",
    "    df[f'week_day_{i + 1}'] = 1 * (df['date'].dt.weekday == i)\n",
    "\n",
    "df.head(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's rerun the cross-validation procedure with the added exogenous variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Using the following exogenous variables: week_day_1, week_day_2, week_day_3, week_day_4, week_day_5, week_day_6, week_day_7\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Validating inputs...\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>unique_id</th>\n",
       "      <th>date</th>\n",
       "      <th>cutoff</th>\n",
       "      <th>users</th>\n",
       "      <th>TimeGPT</th>\n",
       "      <th>TimeGPT-lo-99.5</th>\n",
       "      <th>TimeGPT-lo-90</th>\n",
       "      <th>TimeGPT-lo-80</th>\n",
       "      <th>TimeGPT-hi-80</th>\n",
       "      <th>TimeGPT-hi-90</th>\n",
       "      <th>TimeGPT-hi-99.5</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-01</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>3123</td>\n",
       "      <td>3314.773743</td>\n",
       "      <td>2793.566942</td>\n",
       "      <td>3043.304261</td>\n",
       "      <td>3085.668122</td>\n",
       "      <td>3543.879364</td>\n",
       "      <td>3586.243226</td>\n",
       "      <td>3835.980544</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-02</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>2870</td>\n",
       "      <td>3093.066529</td>\n",
       "      <td>2139.727892</td>\n",
       "      <td>2725.964112</td>\n",
       "      <td>2779.082154</td>\n",
       "      <td>3407.050904</td>\n",
       "      <td>3460.168946</td>\n",
       "      <td>4046.405166</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-03</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>2020</td>\n",
       "      <td>2347.973573</td>\n",
       "      <td>1386.090529</td>\n",
       "      <td>1915.487550</td>\n",
       "      <td>1973.679628</td>\n",
       "      <td>2722.267519</td>\n",
       "      <td>2780.459596</td>\n",
       "      <td>3309.856618</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-04</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>1828</td>\n",
       "      <td>2182.467408</td>\n",
       "      <td>1003.677454</td>\n",
       "      <td>1681.246491</td>\n",
       "      <td>1874.572327</td>\n",
       "      <td>2490.362488</td>\n",
       "      <td>2683.688324</td>\n",
       "      <td>3361.257361</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>2021-07-05</td>\n",
       "      <td>2021-06-30</td>\n",
       "      <td>2722</td>\n",
       "      <td>3083.629453</td>\n",
       "      <td>1257.248435</td>\n",
       "      <td>2220.430357</td>\n",
       "      <td>2556.408628</td>\n",
       "      <td>3610.850279</td>\n",
       "      <td>3946.828550</td>\n",
       "      <td>4910.010472</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      unique_id        date     cutoff  users      TimeGPT  TimeGPT-lo-99.5  \\\n",
       "0  daily_visits  2021-07-01 2021-06-30   3123  3314.773743      2793.566942   \n",
       "1  daily_visits  2021-07-02 2021-06-30   2870  3093.066529      2139.727892   \n",
       "2  daily_visits  2021-07-03 2021-06-30   2020  2347.973573      1386.090529   \n",
       "3  daily_visits  2021-07-04 2021-06-30   1828  2182.467408      1003.677454   \n",
       "4  daily_visits  2021-07-05 2021-06-30   2722  3083.629453      1257.248435   \n",
       "\n",
       "   TimeGPT-lo-90  TimeGPT-lo-80  TimeGPT-hi-80  TimeGPT-hi-90  TimeGPT-hi-99.5  \n",
       "0    3043.304261    3085.668122    3543.879364    3586.243226      3835.980544  \n",
       "1    2725.964112    2779.082154    3407.050904    3460.168946      4046.405166  \n",
       "2    1915.487550    1973.679628    2722.267519    2780.459596      3309.856618  \n",
       "3    1681.246491    1874.572327    2490.362488    2683.688324      3361.257361  \n",
       "4    2220.430357    2556.408628    3610.850279    3946.828550      4910.010472  "
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timegpt_cv_df_with_ex = nixtla_client.cross_validation(\n",
    "    df, \n",
    "    h=7, \n",
    "    n_windows=8, \n",
    "    time_col='date', \n",
    "    target_col='users', \n",
    "    freq='D',\n",
    "    level=[80, 90, 99.5]\n",
    ")\n",
    "timegpt_cv_df_with_ex.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's plot our forecasts again and calculate our error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 162584 characters]",
      "text/plain": [
       "<Figure size 2400x350 with 1 Axes>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nixtla_client.plot(\n",
    "    df, \n",
    "    timegpt_cv_df_with_ex.drop(columns=['cutoff', 'users']), \n",
    "    time_col='date',\n",
    "    target_col='users',\n",
    "    max_insample_length=90, \n",
    "    level=[80, 90, 99.5]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>unique_id</th>\n",
       "      <th>TimeGPT</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>daily_visits</td>\n",
       "      <td>167.22857</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      unique_id    TimeGPT\n",
       "0  daily_visits  167.22857"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mae_timegpt_with_exogenous = mae(df = timegpt_cv_df_with_ex.drop(columns=['cutoff']),\n",
    "    models=['TimeGPT'],\n",
    "    target_col='users')\n",
    "\n",
    "mae_timegpt_with_exogenous"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To conclude, we obtain the following forecast results in this notebook:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>model</th>\n",
       "      <th>Exogenous features</th>\n",
       "      <th>MAE backtest</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>TimeGPT</td>\n",
       "      <td>False</td>\n",
       "      <td>167.691711</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>TimeGPT</td>\n",
       "      <td>True</td>\n",
       "      <td>167.228570</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     model  Exogenous features  MAE backtest\n",
       "0  TimeGPT               False    167.691711\n",
       "0  TimeGPT                True    167.228570"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mae_timegpt['Exogenous features'] = False\n",
    "mae_timegpt_with_exogenous['Exogenous features'] = True\n",
    "\n",
    "df_results = pd.concat([mae_timegpt, mae_timegpt_with_exogenous])\n",
    "df_results = df_results.rename(columns={'TimeGPT':'MAE backtest'})\n",
    "df_results = df_results.drop(columns={'unique_id'})\n",
    "df_results['model'] = 'TimeGPT'\n",
    "\n",
    "df_results[['model', 'Exogenous features', 'MAE backtest']]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We've shown how to forecast daily visits of a website. We achieved almost 10% better forecasting results as compared to the [original tutorial](https://cienciadedatos.net/documentos/py37-forecasting-web-traffic-machine-learning.html), using significantly less lines of code, in a fraction of the time required to run everything.\n",
    "\n",
    "Did you notice how little effort that took? What you did not have to do, is:\n",
    "\n",
    "- Elaborate data preprocessing - just a table with timeseries is sufficient\n",
    "- Creating a validation- and test set - TimeGPT handles the cross-validation in a single function\n",
    "- Choosing and testing different models - It's just a single call to TimeGPT\n",
    "- Hyperparameter tuning - Not necessary.\n",
    "\n",
    "Happy forecasting!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
