321 lines
168 KiB
Plaintext
321 lines
168 KiB
Plaintext
|
|
{
|
||
|
|
"cells": [
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "7d729fc0",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# Explorations and Analyses of the ENTSO-E data"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 2,
|
||
|
|
"id": "db058e46",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# Fix the path \n",
|
||
|
|
"import sys\n",
|
||
|
|
"import os\n",
|
||
|
|
"\n",
|
||
|
|
"sys.path.append(os.path.abspath(\"..\")) # since you're in src/data_analysis\n",
|
||
|
|
"os.environ[\"ENTSOE_API_KEY\"] = \"ec10538b-eae1-4d71-ada6-45feff2e51c2\"\n",
|
||
|
|
"os.environ[\"QUANT_DB_HOST\"] = \"localhost\"\n",
|
||
|
|
"os.environ[\"QUANT_DB_PORT\"] = \"5432\"\n",
|
||
|
|
"os.environ[\"QUANT_DB_NAME\"] = \"options_db\"\n",
|
||
|
|
"os.environ[\"QUANT_DB_USER\"] = \"quant_user\"\n",
|
||
|
|
"os.environ[\"QUANT_DB_PASSWORD\"] = \"strong_password\"\n"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 3,
|
||
|
|
"id": "a302f12a",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# import necessary libraries\n",
|
||
|
|
"import importlib\n",
|
||
|
|
"import numpy as np\n",
|
||
|
|
"import matplotlib.pyplot as plt\n",
|
||
|
|
"import pandas as pd\n",
|
||
|
|
"import os\n",
|
||
|
|
"\n",
|
||
|
|
"# Ensure notebook picks up local code edits without kernel restarts\n",
|
||
|
|
"%load_ext autoreload\n",
|
||
|
|
"%autoreload 2\n",
|
||
|
|
"\n",
|
||
|
|
"# custom imports\n",
|
||
|
|
"import electricity_price_predictor.entsoe_api as api\n",
|
||
|
|
"import electricity_price_predictor.pipeline as pipeline\n",
|
||
|
|
"\n",
|
||
|
|
"importlib.reload(api)\n",
|
||
|
|
"importlib.reload(pipeline)\n",
|
||
|
|
"\n",
|
||
|
|
"from electricity_price_predictor.db import get_engine\n",
|
||
|
|
"from electricity_price_predictor.pipeline import run_feature_pipeline\n"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 4,
|
||
|
|
"id": "51ddca35",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"def access_data(\n",
|
||
|
|
" start: pd.Timestamp,\n",
|
||
|
|
" end: pd.Timestamp,\n",
|
||
|
|
" country_code: str,\n",
|
||
|
|
" history_hours: int = 48,\n",
|
||
|
|
") -> pd.DataFrame:\n",
|
||
|
|
" \"\"\"\n",
|
||
|
|
" Fetch features for [start, end) while pulling extra lookback history.\n",
|
||
|
|
"\n",
|
||
|
|
" We need lookback because feature generation creates lagged columns (t-1..t-24)\n",
|
||
|
|
" and drops rows with NaNs.\n",
|
||
|
|
" \"\"\"\n",
|
||
|
|
" api_key = os.getenv(\"ENTSOE_API_KEY\")\n",
|
||
|
|
" if not api_key:\n",
|
||
|
|
" raise RuntimeError(\"ENTSOE_API_KEY environment variable is required.\")\n",
|
||
|
|
"\n",
|
||
|
|
" start_ts = pd.Timestamp(start)\n",
|
||
|
|
" end_ts = pd.Timestamp(end)\n",
|
||
|
|
" if start_ts.tz is None:\n",
|
||
|
|
" start_ts = start_ts.tz_localize(\"UTC\")\n",
|
||
|
|
" else:\n",
|
||
|
|
" start_ts = start_ts.tz_convert(\"UTC\")\n",
|
||
|
|
"\n",
|
||
|
|
" if end_ts.tz is None:\n",
|
||
|
|
" end_ts = end_ts.tz_localize(\"UTC\")\n",
|
||
|
|
" else:\n",
|
||
|
|
" end_ts = end_ts.tz_convert(\"UTC\")\n",
|
||
|
|
"\n",
|
||
|
|
" engine = get_engine()\n",
|
||
|
|
" pipeline_start = start_ts - pd.Timedelta(hours=history_hours)\n",
|
||
|
|
"\n",
|
||
|
|
" features = run_feature_pipeline(\n",
|
||
|
|
" engine=engine,\n",
|
||
|
|
" entsoe_api_key=api_key,\n",
|
||
|
|
" country_code=country_code,\n",
|
||
|
|
" start=pipeline_start,\n",
|
||
|
|
" end=end_ts,\n",
|
||
|
|
" cache_ttl_hours=24,\n",
|
||
|
|
" )\n",
|
||
|
|
"\n",
|
||
|
|
" # Return only the user-requested interval.\n",
|
||
|
|
" return features[(features.index >= start_ts) & (features.index < end_ts)]\n",
|
||
|
|
"\n"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 5,
|
||
|
|
"id": "215dfccc",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# Pull the latest 48h window ending at the most recent complete hour.\n",
|
||
|
|
"end = pd.Timestamp.now(tz=\"UTC\").floor(\"h\")\n",
|
||
|
|
"start = end - pd.Timedelta(hours=48)\n",
|
||
|
|
"\n",
|
||
|
|
"df_CH = access_data(start, end, \"CH\", history_hours=72)\n",
|
||
|
|
"\n",
|
||
|
|
"\n",
|
||
|
|
"# pull German data for comparison \n",
|
||
|
|
"df_DE = access_data(start, end, \"DE_LU\", history_hours=72)\n",
|
||
|
|
"# pull French data for comparison \n",
|
||
|
|
"df_FR = access_data(start, end, \"FR\", history_hours=72)\n",
|
||
|
|
"# pull Italian data for comparison \n",
|
||
|
|
"df_IT = access_data(start, end, \"IT\", history_hours=72)\n",
|
||
|
|
"# pull Austrian data for comparison \n",
|
||
|
|
"df_AT = access_data(start, end, \"AT\", history_hours=72)\n",
|
||
|
|
"# pull Spanish data for comparison \n",
|
||
|
|
"df_ES = access_data(start, end, \"ES\", history_hours=72)\n",
|
||
|
|
"\n",
|
||
|
|
"\n"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 6,
|
||
|
|
"id": "ecb030fa",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAH3CAYAAABdFJ4JAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd4VFX6wPHvnT6T3hshhdB7B5Hei72sa0FEXV2xl0X82VbXtXddXVcFCypiRUCa9F6kdwghgfQ2KZPp9/fHTYaEhDTSSM7neeYhmblz7zkJmXnnnPe8R5JlWUYQBEEQBKGVUjV3AwRBEARBEBqTCHYEQRAEQWjVRLAjCIIgCEKrJoIdQRAEQRBaNRHsCIIgCILQqolgRxAEQRCEVk0EO4IgCIIgtGoi2BEEQRAEoVUTwY4gCIIgCK2aCHYEQWiRYmNjmTZtWnM3owJJknj++eeb5FqjRo1i1KhRTXItQWjtRLAjCK3QvHnzkCTJczMYDERGRjJx4kTee+89CgsLm7uJgiAITUbT3A0QBKHxvPDCC8TFxeFwOEhPT2ft2rU8/PDDvPXWWyxatIhevXo1dxOFC1ixYkVzN0EQWg0R7AhCKzZ58mQGDBjg+X7OnDmsXr2aadOmceWVV3L48GGMRmMztlA4n8ViwWQyodPpmrspgtBqiGksQWhjxowZwzPPPMPp06f5+uuvPffv27ePGTNmEB8fj8FgIDw8nJkzZ5KTk+M5Zs2aNUiSxM8//1zpvN988w2SJLFly5Zqrz937lzGjBlDaGgoer2ebt268dFHH13w+I0bNzJo0CAMBgPx8fF8+eWXlY7Jz8/n4YcfJjo6Gr1eT0JCAq+++iput7vCcW+88QaXXXYZQUFBGI1G+vfvzw8//FDpfDabjUceeYSQkBB8fHy48sorOXPmTLX9KrN27VokSWLBggU89dRThIeH4+XlxZVXXklKSkqFY0eNGkWPHj3YtWsXI0aMwGQy8dRTT3keOz9nx2q18vzzz9OpUycMBgMRERFce+21nDx50nOM2+3mnXfeoXv37hgMBsLCwrjnnnvIy8urVfsFoTUSwY4gtEG33XYbUHGqZOXKlSQmJnLHHXfw/vvvc9NNN/Hdd98xZcoUZFkGlDfg6Oho5s+fX+mc8+fPp0OHDgwdOrTaa3/00UfExMTw1FNP8eabbxIdHc19993Hhx9+WOnYEydOcP311zN+/HjefPNNAgICmDFjBgcPHvQcY7FYGDlyJF9//TXTp0/nvffeY9iwYcyZM4dHH320wvneffdd+vbtywsvvMC///1vNBoNN9xwA0uWLKlw3F133cU777zDhAkTeOWVV9BqtUydOrWGn2pFL730EkuWLGH27Nk8+OCDrFy5knHjxlFSUlLhuJycHCZPnkyfPn145513GD16dJXnc7lcTJs2jX/+85/079+fN998k4ceegiz2cyBAwc8x91zzz088cQTDBs2jHfffZc77riD+fPnM3HiRBwOR536IAithiwIQqszd+5cGZB37NhxwWP8/Pzkvn37er63WCyVjvn2229lQF6/fr3nvjlz5sh6vV7Oz8/33JeZmSlrNBr5ueeeq7FtVV1n4sSJcnx8fIX7YmJiKl07MzNT1uv18mOPPea578UXX5S9vLzkY8eOVXj+k08+KavVajk5OfmC17bb7XKPHj3kMWPGeO7bs2ePDMj33XdfhWNvvvlmGaixj2vWrJEBOSoqSi4oKPDc//3338uA/O6773ruGzlypAzIH3/8caXzjBw5Uh45cqTn+88//1wG5LfeeqvSsW63W5ZlWd6wYYMMyPPnz6/w+LJly6q8XxDaCjGyIwhtlLe3d4VVWeVzd6xWK9nZ2QwZMgSAP//80/PY9OnTsdlsFaZ/FixYgNPp5NZbb63xuuWvYzabyc7OZuTIkSQmJmI2mysc261bN4YPH+75PiQkhM6dO5OYmOi5b+HChQwfPpyAgACys7M9t3HjxuFyuVi/fn2V187Ly8NsNjN8+PAK/Vu6dCkADz74YIW2PPzwwzX2rbzp06fj4+Pj+f76668nIiLCc/4yer2eO+64o8bz/fjjjwQHB/PAAw9UekySJED5Wfj5+TF+/PgKP4v+/fvj7e3NmjVr6tQHQWgtRIKyILRRRUVFhIaGer7Pzc3ln//8J9999x2ZmZkVji0fhHTp0oWBAwcyf/587rzzTkCZwhoyZAgJCQme48tP1+h0OgIDAwHYtGkTzz33HFu2bMFisVS6jp+fn+f79u3bV2p3QEBAhfyT48ePs2/fPkJCQqrsZ/m+LF68mH/961/s2bMHm83mub8sWAA4ffo0KpWKDh06VDhP586dqzz/hXTs2LHC95IkkZCQQFJSUoX7o6KiapWMfPLkSTp37oxGc+GX7ePHj2M2myv8Xss7//cqCG2FCHYEoQ06c+YMZrPZE5wA3HjjjWzevJknnniCPn364O3tjdvtZtKkSZUSfadPn85DDz3EmTNnsNlsbN26lQ8++MDz+EMPPcQXX3zh+X7kyJGsXbuWkydPMnbsWLp06cJbb71FdHQ0Op2OpUuX8vbbb1e6jlqtrrL9cmkOESgJuePHj+cf//hHlcd26tQJgA0bNnDllVcyYsQI/vOf/xAREYFWq2Xu3Ll88803tfzJNbyGXA3ndrsJDQ2tMqcKuGBAKAitnQh2BKEN+uqrrwCYOHEioEzp/PHHH/zzn//k2Wef9Rx3/PjxKp9/00038eijj/Ltt99SUlKCVqvlL3/5i+fxf/zjHxWmtAICAgD47bffsNlsLFq0qMKozcVMr3To0IGioiLGjRtX7XE//vgjBoOB5cuXo9frPffPnTu3wnExMTG43W7PSEqZo0eP1qld5//sZFnmxIkT9a5t1KFDB7Zt24bD4UCr1V7wmFWrVjFs2DBRUkAQyhE5O4LQxqxevZoXX3yRuLg4brnlFuDcCEr5EROAd955p8pzBAcHM3nyZL7++mvmz5/PpEmTCA4O9jzerVs3xo0b57n179//gtcxm82VAo66uPHGG9myZQvLly+v9Fh+fj5Op9NzbUmScLlcnseTkpL45ZdfKjxn8uTJALz33nsV7r/Qz+JCvvzyywo5UT/88ANpaWme89fVddddR3Z2doURtDJlP88bb7wRl8vFiy++WOkYp9NJfn5+va4tCJc6MbIjCK3Y77//zpEjR3A6nWRkZLB69WpWrlxJTEwMixYtwmAwAODr68uIESN47bXXcDgcREVFsWLFCk6dOnXBc0+fPp3rr78eoMo316pMmDABnU7HFVdcwT333ENRURH/+9//CA0NJS0trV59fOKJJ1i0aBHTpk1jxowZ9O/fn+LiYvbv388PP/xAUlISwcHBTJ06lbfeeotJkyZx8803k5mZyYcffkhCQgL79u3znK9Pnz789a9/5T//+Q9ms5nLLruMP/74gxMnTtSpXYGBgVx++eXccccdZGRk8M4775CQkMDdd99dr35Onz6dL7/8kkcffZTt27czfPhwiouLWbVqFffddx9XXXUVI0eO5J577uHll19mz549TJgwAa1Wy/Hjx1m4cCHvvvuu53cmCG1Ks64FEwShUZQtPS+76XQ6OTw8XB4/frz87rvvVlgSXebMmTPyNddcI/v7+8t+fn7yDTfcIKempl5wubXNZpMDAgJkPz8/uaSkpNZtW7RokdyrVy/ZYDDIsbGx8quvvupZVn3q1CnPcTExMfLUqVMrPf/8JdmyLMuFhYXynDlz5ISEBFmn08nBwcHyZZddJr/xxhuy3W73HPfZZ5/JHTt2lPV6vdylSxd57ty58nPPPSef/1JYUlIiP/jgg3JQUJDs5eUlX3HFFXJKSkqdlp5/++238pw5c+TQ0FDZaDTKU6dOlU+fPl2pL927d6/yPFX102KxyP/3f/8nx8XFyVqtVg4PD5evv/56+eTJkxWO++STT+T+/fvLRqNR9vHxkXv27Cn/4x//kFNTU6ttuyC0VpIsnzduLQiCUAtOp5PIyEiuuOIKPvvss+ZuTouxdu1aRo8ezcKFC8UoiiC0ECJnRxCEevnll
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 640x480 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"plt.plot(df_CH.index, df_CH[\"day_ahead_price\"], label=\"CH\")\n",
|
||
|
|
"plt.plot(df_DE.index, df_DE[\"day_ahead_price\"], label=\"DE_LU\")\n",
|
||
|
|
"plt.plot(df_FR.index, df_FR[\"day_ahead_price\"], label=\"FR\")\n",
|
||
|
|
"plt.plot(df_IT.index, df_IT[\"day_ahead_price\"], label=\"IT\")\n",
|
||
|
|
"plt.plot(df_AT.index, df_AT[\"day_ahead_price\"], label=\"AT\")\n",
|
||
|
|
"plt.plot(df_ES.index, df_ES[\"day_ahead_price\"], label=\"ES\")\n",
|
||
|
|
"\n",
|
||
|
|
"plt.xticks(rotation=90)\n",
|
||
|
|
"plt.grid()\n",
|
||
|
|
"plt.title(\"Day-ahead price\")\n",
|
||
|
|
"plt.xlabel(\"Date\")\n",
|
||
|
|
"plt.ylabel(\"Price (EUR/MWh)\")\n",
|
||
|
|
"plt.legend()\n",
|
||
|
|
"\n",
|
||
|
|
"plt.show()\n",
|
||
|
|
"\n",
|
||
|
|
"\n"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "2c907274",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Feature engineering \n",
|
||
|
|
"In the next section we are going to explore which features are justifiable with the given data. "
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 7,
|
||
|
|
"id": "7a97f063",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"Index(['day_ahead_price', 'load_forecast', 'wind_forecast', 'solar_forecast',\n",
|
||
|
|
" 'residual_load', 'lagged_price_1', 'lagged_residual_load_1',\n",
|
||
|
|
" 'lagged_price_2', 'lagged_residual_load_2', 'lagged_price_3',\n",
|
||
|
|
" 'lagged_residual_load_3', 'lagged_price_4', 'lagged_residual_load_4',\n",
|
||
|
|
" 'lagged_price_5', 'lagged_residual_load_5', 'lagged_price_6',\n",
|
||
|
|
" 'lagged_residual_load_6', 'lagged_price_7', 'lagged_residual_load_7',\n",
|
||
|
|
" 'lagged_price_8', 'lagged_residual_load_8', 'lagged_price_9',\n",
|
||
|
|
" 'lagged_residual_load_9', 'lagged_price_10', 'lagged_residual_load_10',\n",
|
||
|
|
" 'lagged_price_11', 'lagged_residual_load_11', 'lagged_price_12',\n",
|
||
|
|
" 'lagged_residual_load_12', 'lagged_price_13', 'lagged_residual_load_13',\n",
|
||
|
|
" 'lagged_price_14', 'lagged_residual_load_14', 'lagged_price_15',\n",
|
||
|
|
" 'lagged_residual_load_15', 'lagged_price_16', 'lagged_residual_load_16',\n",
|
||
|
|
" 'lagged_price_17', 'lagged_residual_load_17', 'lagged_price_18',\n",
|
||
|
|
" 'lagged_residual_load_18', 'lagged_price_19', 'lagged_residual_load_19',\n",
|
||
|
|
" 'lagged_price_20', 'lagged_residual_load_20', 'lagged_price_21',\n",
|
||
|
|
" 'lagged_residual_load_21', 'lagged_price_22', 'lagged_residual_load_22',\n",
|
||
|
|
" 'lagged_price_23', 'lagged_residual_load_23', 'lagged_price_24',\n",
|
||
|
|
" 'lagged_residual_load_24', 'hour_of_day_sin', 'hour_of_day_cos',\n",
|
||
|
|
" 'weekday_sin', 'weekday_cos', 'month_sin', 'month_cos'],\n",
|
||
|
|
" dtype='str')"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 7,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"df_CH.columns"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 10,
|
||
|
|
"id": "28f7adf4",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"text/plain": [
|
||
|
|
"<Axes: >"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"execution_count": 10,
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "execute_result"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 1200x400 with 2 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"fig, axes = plt.subplots(2,1,figsize=(12,4))\n",
|
||
|
|
"end = pd.Timestamp.now(tz=\"UTC\").floor(\"h\")\n",
|
||
|
|
"start = end - pd.Timedelta(hours=14*24)\n",
|
||
|
|
"df = access_data(start, end, \"CH\", history_hours=72)\n",
|
||
|
|
"df[\"day_ahead_price\"].plot(ax = axes[0], title = \"Price Time Series CH\")\n",
|
||
|
|
"df[\"day_ahead_price\"].hist(bins=50, ax = axes[1])"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"id": "cfd6a4e4",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"Observations: \n",
|
||
|
|
"\n",
|
||
|
|
"* Intraday seasonality \n",
|
||
|
|
"* $\\mu \\approx 125$\n",
|
||
|
|
"* Noise \n",
|
||
|
|
"\n",
|
||
|
|
"An approach could be to model it as \n",
|
||
|
|
"\n",
|
||
|
|
"Price(t) = µ + seasonal(t) + noise"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": null,
|
||
|
|
"id": "443b5dc4",
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"# Let's explore this further with an STL decomposition \n",
|
||
|
|
"from statsmodels.tsa.seasonal import STL \n",
|
||
|
|
"\n",
|
||
|
|
"ts = df[\"day_ahead_price\"]\n",
|
||
|
|
"\n",
|
||
|
|
"stl = STL(ts, period=24)\n",
|
||
|
|
"res = stl.fit()\n",
|
||
|
|
"\n",
|
||
|
|
"res.plot()\n",
|
||
|
|
"\n",
|
||
|
|
"\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"metadata": {
|
||
|
|
"kernelspec": {
|
||
|
|
"display_name": ".venv",
|
||
|
|
"language": "python",
|
||
|
|
"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.12.3"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nbformat": 4,
|
||
|
|
"nbformat_minor": 5
|
||
|
|
}
|