{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d45121a",
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "!pip install -Uqq nixtla"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2680fe00",
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "from nixtla.utils import in_colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ca7f087",
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "IN_COLAB = in_colab()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be850b37",
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "if not IN_COLAB:\n",
    "    from nixtla.utils import colab_badge\n",
    "    from itertools import product\n",
    "    from dotenv import load_dotenv"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0241d5c1-8d11-4cb9-9259-cda5fffa7ea8",
   "metadata": {},
   "source": [
    "# Prediction intervals"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f73b521-05f2-4c53-b44c-d988bf8fe7b9",
   "metadata": {},
   "source": [
    "In forecasting, we are often interested in a distribution of predictions rather than only a point prediction, because we want to have a notion of the uncertainty around the forecast.\n",
    "\n",
    "To this end, we can create _prediction intervals_.\n",
    "\n",
    "Prediction intervals have an intuitive interpretation, as they present a specific range of the forecast distribution. For instance, a 95% prediction interval means that 95 out of 100 times, we expect the future value to fall within the estimated range. Therefore, a wider interval indicates greater uncertainty about the forecast, while a narrower interval suggests higher confidence.\n",
    "\n",
    "With TimeGPT, we can create a distribution of forecasts, and extract the prediction intervals for a required level.\n",
    "\n",
    "TimeGPT uses [conformal prediction](https://en.wikipedia.org/wiki/Conformal_prediction) to produce the prediction intervals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cdf86af8-08c0-4118-bd6b-0b88a6eac3f7",
   "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/tutorials/11_uncertainty_quantification_with_prediction_intervals.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/tutorials/11_uncertainty_quantification_with_prediction_intervals')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e49342d",
   "metadata": {},
   "source": [
    "## 1. Import packages\n",
    "First, we import the required packages and initialize the Nixtla client"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a5181e9-634c-4002-9c22-d65f0701fa14",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from nixtla import NixtlaClient"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9872d00d-ecb1-4a14-9813-bf0c56e70392",
   "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",
   "id": "4ec82f80",
   "metadata": {},
   "source": [
    "> 👍 Use an Azure AI endpoint\n",
    ">\n",
    "> To use an Azure AI endpoint, set 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,
   "id": "50eac17f-3c72-4f68-988a-1d5d877dff2b",
   "metadata": {},
   "outputs": [],
   "source": [
    "#| hide\n",
    "if not IN_COLAB:\n",
    "    nixtla_client = NixtlaClient()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b73a23a8",
   "metadata": {},
   "source": [
    "## 2. Load data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31b1e602-f8ee-49c4-8819-fcc093d64ab1",
   "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>timestamp</th>\n",
       "      <th>value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1949-01-01</td>\n",
       "      <td>112</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1949-02-01</td>\n",
       "      <td>118</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1949-03-01</td>\n",
       "      <td>132</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1949-04-01</td>\n",
       "      <td>129</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1949-05-01</td>\n",
       "      <td>121</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    timestamp  value\n",
       "0  1949-01-01    112\n",
       "1  1949-02-01    118\n",
       "2  1949-03-01    132\n",
       "3  1949-04-01    129\n",
       "4  1949-05-01    121"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/air_passengers.csv')\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3de9945d",
   "metadata": {},
   "source": [
    "## 3. Forecast with prediction intervals\n",
    "When using TimeGPT for time series forecasting, you can set the level (or levels) of prediction intervals according to your requirements. Here's how you could do it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "174db3ef-71ff-4bdf-92f3-e3277bb76c43",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Inferred freq: MS\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\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>timestamp</th>\n",
       "      <th>TimeGPT</th>\n",
       "      <th>TimeGPT-lo-99.7</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.7</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1961-01-01</td>\n",
       "      <td>437.837952</td>\n",
       "      <td>415.826484</td>\n",
       "      <td>423.783737</td>\n",
       "      <td>431.987091</td>\n",
       "      <td>443.688812</td>\n",
       "      <td>451.892166</td>\n",
       "      <td>459.849419</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1961-02-01</td>\n",
       "      <td>426.062744</td>\n",
       "      <td>402.833553</td>\n",
       "      <td>407.694092</td>\n",
       "      <td>412.704956</td>\n",
       "      <td>439.420532</td>\n",
       "      <td>444.431396</td>\n",
       "      <td>449.291935</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1961-03-01</td>\n",
       "      <td>463.116577</td>\n",
       "      <td>423.434092</td>\n",
       "      <td>430.316893</td>\n",
       "      <td>437.412564</td>\n",
       "      <td>488.820590</td>\n",
       "      <td>495.916261</td>\n",
       "      <td>502.799062</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1961-04-01</td>\n",
       "      <td>478.244507</td>\n",
       "      <td>444.885193</td>\n",
       "      <td>446.776764</td>\n",
       "      <td>448.726837</td>\n",
       "      <td>507.762177</td>\n",
       "      <td>509.712250</td>\n",
       "      <td>511.603821</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1961-05-01</td>\n",
       "      <td>505.646484</td>\n",
       "      <td>465.736694</td>\n",
       "      <td>471.976787</td>\n",
       "      <td>478.409872</td>\n",
       "      <td>532.883096</td>\n",
       "      <td>539.316182</td>\n",
       "      <td>545.556275</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    timestamp     TimeGPT  TimeGPT-lo-99.7  TimeGPT-lo-90  TimeGPT-lo-80  \\\n",
       "0  1961-01-01  437.837952       415.826484     423.783737     431.987091   \n",
       "1  1961-02-01  426.062744       402.833553     407.694092     412.704956   \n",
       "2  1961-03-01  463.116577       423.434092     430.316893     437.412564   \n",
       "3  1961-04-01  478.244507       444.885193     446.776764     448.726837   \n",
       "4  1961-05-01  505.646484       465.736694     471.976787     478.409872   \n",
       "\n",
       "   TimeGPT-hi-80  TimeGPT-hi-90  TimeGPT-hi-99.7  \n",
       "0     443.688812     451.892166       459.849419  \n",
       "1     439.420532     444.431396       449.291935  \n",
       "2     488.820590     495.916261       502.799062  \n",
       "3     507.762177     509.712250       511.603821  \n",
       "4     532.883096     539.316182       545.556275  "
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timegpt_fcst_pred_int_df = nixtla_client.forecast(\n",
    "    df=df, h=12, level=[80, 90, 99.7],\n",
    "    time_col='timestamp', target_col='value',\n",
    ")\n",
    "timegpt_fcst_pred_int_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7cefb13",
   "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.forecast(..., 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": "code",
   "execution_count": null,
   "id": "10fe6283-e01d-4afb-acbd-344726a0518f",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Inferred freq: MS\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n"
     ]
    }
   ],
   "source": [
    "#| hide\n",
    "# test shorter horizon\n",
    "if not IN_COLAB:\n",
    "    level_short_horizon_df = nixtla_client.forecast(\n",
    "        df=df, h=6, level=[80, 90, 99.7],\n",
    "        time_col='timestamp', target_col='value',\n",
    "    )\n",
    "    assert level_short_horizon_df.shape == (6, 8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65c9add4-da01-4767-abb2-4addd9b3bbd4",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Inferred freq: MS\n",
      "INFO:nixtla.nixtla_client:Restricting input...\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n"
     ]
    }
   ],
   "source": [
    "#| hide\n",
    "if not IN_COLAB:\n",
    "    test_level = [80, 90.5]\n",
    "    cols_fcst_df = nixtla_client.forecast(\n",
    "        df=df, h=12, level=test_level,\n",
    "        time_col='timestamp', target_col='value',\n",
    "    ).columns\n",
    "    assert all(f'TimeGPT-{pos}-{lv}' in cols_fcst_df for pos, lv in product(['lo', 'hi'], test_level) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a2e1bab-2352-4c8d-addd-3b74fdcbdb93",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 94192 characters]",
      "text/plain": [
       "<Figure size 2400x350 with 1 Axes>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nixtla_client.plot(\n",
    "    df, timegpt_fcst_pred_int_df,\n",
    "    time_col='timestamp', target_col='value',\n",
    "    level=[80, 90],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f3917c3-b5d3-4950-9ff4-32627849d3e7",
   "metadata": {},
   "source": [
    "It's essential to note that the choice of prediction interval level depends on your specific use case. For high-stakes predictions, you might want a wider interval to account for more uncertainty. For less critical forecasts, a narrower interval might be acceptable."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea3023d2-0c86-417c-ad19-a1a584910534",
   "metadata": {},
   "source": [
    "#### Historical Forecast"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c75269d-7cda-4bff-b18a-3a1193d8391e",
   "metadata": {},
   "source": [
    "You can also compute prediction intervals for historical forecasts adding the `add_history=True` parameter as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e539081f-d5c5-4d82-b223-5b11cbd75503",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:nixtla.nixtla_client:Validating inputs...\n",
      "INFO:nixtla.nixtla_client:Preprocessing dataframes...\n",
      "INFO:nixtla.nixtla_client:Inferred freq: MS\n",
      "INFO:nixtla.nixtla_client:Calling Forecast Endpoint...\n",
      "INFO:nixtla.nixtla_client:Calling Historical Forecast Endpoint...\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>timestamp</th>\n",
       "      <th>TimeGPT</th>\n",
       "      <th>TimeGPT-lo-80</th>\n",
       "      <th>TimeGPT-lo-90</th>\n",
       "      <th>TimeGPT-hi-80</th>\n",
       "      <th>TimeGPT-hi-90</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1951-01-01</td>\n",
       "      <td>135.483673</td>\n",
       "      <td>111.937767</td>\n",
       "      <td>105.262830</td>\n",
       "      <td>159.029579</td>\n",
       "      <td>165.704516</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1951-02-01</td>\n",
       "      <td>144.442413</td>\n",
       "      <td>120.896508</td>\n",
       "      <td>114.221571</td>\n",
       "      <td>167.988319</td>\n",
       "      <td>174.663256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1951-03-01</td>\n",
       "      <td>157.191910</td>\n",
       "      <td>133.646004</td>\n",
       "      <td>126.971067</td>\n",
       "      <td>180.737815</td>\n",
       "      <td>187.412752</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1951-04-01</td>\n",
       "      <td>148.769379</td>\n",
       "      <td>125.223473</td>\n",
       "      <td>118.548536</td>\n",
       "      <td>172.315284</td>\n",
       "      <td>178.990221</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1951-05-01</td>\n",
       "      <td>140.472946</td>\n",
       "      <td>116.927041</td>\n",
       "      <td>110.252104</td>\n",
       "      <td>164.018852</td>\n",
       "      <td>170.693789</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    timestamp     TimeGPT  TimeGPT-lo-80  TimeGPT-lo-90  TimeGPT-hi-80  \\\n",
       "0  1951-01-01  135.483673     111.937767     105.262830     159.029579   \n",
       "1  1951-02-01  144.442413     120.896508     114.221571     167.988319   \n",
       "2  1951-03-01  157.191910     133.646004     126.971067     180.737815   \n",
       "3  1951-04-01  148.769379     125.223473     118.548536     172.315284   \n",
       "4  1951-05-01  140.472946     116.927041     110.252104     164.018852   \n",
       "\n",
       "   TimeGPT-hi-90  \n",
       "0     165.704516  \n",
       "1     174.663256  \n",
       "2     187.412752  \n",
       "3     178.990221  \n",
       "4     170.693789  "
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "timegpt_fcst_pred_int_historical_df = nixtla_client.forecast(\n",
    "    df=df, h=12, level=[80, 90],\n",
    "    time_col='timestamp', target_col='value',\n",
    "    add_history=True,\n",
    ")\n",
    "timegpt_fcst_pred_int_historical_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b9dddbe-0c5a-4d21-abcf-f664e176c7a7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 157992 characters]",
      "text/plain": [
       "<Figure size 2400x350 with 1 Axes>"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nixtla_client.plot(\n",
    "    df, timegpt_fcst_pred_int_historical_df,\n",
    "    time_col='timestamp', target_col='value',\n",
    "    level=[80, 90],\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
