"""
Time series forecasting with TabICL on electricity load
=======================================================
"""
'\nTime series forecasting with TabICL on electricity load\n=======================================================\n'
%pip install -q https://pypi.anaconda.org/ogrisel/simple/polars/1.24.0/polars-1.24.0-cp39-abi3-emscripten_3_1_58_wasm32.whl
%pip install -q skrub altair holidays plotly nbformat
%pip install "tabicl[forecast]"
ERROR: polars-1.24.0-cp39-abi3-emscripten_3_1_58_wasm32.whl is not a supported wheel on this platform.
Note: you may need to restart the kernel to use updated packages.
Note: you may need to restart the kernel to use updated packages.
Requirement already satisfied: tabicl[forecast] in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (2.2.0)
Requirement already satisfied: einops>=0.7 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (0.8.2)
Requirement already satisfied: huggingface-hub in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (1.32.0)
Requirement already satisfied: numpy in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (2.4.6)
Requirement already satisfied: psutil in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (7.2.2)
Requirement already satisfied: scikit-learn>=1.3.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (1.9.1)
Requirement already satisfied: scipy in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (1.15.2)
Requirement already satisfied: torch>=2.2 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (2.12.0)
Requirement already satisfied: tqdm>=4.64.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (4.70.1)
Requirement already satisfied: matplotlib>=3.10.3 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (3.11.2)
Requirement already satisfied: pandas>=2.1.2 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (2.3.3)
Requirement already satisfied: statsmodels>=0.14.5 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from tabicl[forecast]) (0.15.0)
Requirement already satisfied: contourpy>=1.0.1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (1.4.0)
Requirement already satisfied: cycler>=0.10 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (0.12.1)
Requirement already satisfied: fonttools>=4.28.2 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (4.66.1)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (1.5.1)
Requirement already satisfied: packaging>=20.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (26.3)
Requirement already satisfied: pillow>=9 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (12.3.0)
Requirement already satisfied: pyparsing>=3 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (3.3.3)
Requirement already satisfied: python-dateutil>=2.7 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from matplotlib>=3.10.3->tabicl[forecast]) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from pandas>=2.1.2->tabicl[forecast]) (2026.5)
Requirement already satisfied: tzdata>=2022.7 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from pandas>=2.1.2->tabicl[forecast]) (2026.5)
Requirement already satisfied: six>=1.5 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from python-dateutil>=2.7->matplotlib>=3.10.3->tabicl[forecast]) (1.17.0)
Requirement already satisfied: joblib>=1.4.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from scikit-learn>=1.3.0->tabicl[forecast]) (1.6.0)
Requirement already satisfied: narwhals>=2.0.1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from scikit-learn>=1.3.0->tabicl[forecast]) (2.27.0)
Requirement already satisfied: threadpoolctl>=3.5.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from scikit-learn>=1.3.0->tabicl[forecast]) (3.7.0)
Requirement already satisfied: cloudpickle>=3.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from joblib>=1.4.0->scikit-learn>=1.3.0->tabicl[forecast]) (3.0.0)
Requirement already satisfied: patsy>=0.5.6 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from statsmodels>=0.14.5->tabicl[forecast]) (1.0.3)
Requirement already satisfied: formulaic>=1.1.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from statsmodels>=0.14.5->tabicl[forecast]) (1.2.2)
Requirement already satisfied: interface-meta>=1.2.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from formulaic>=1.1.0->statsmodels>=0.14.5->tabicl[forecast]) (1.3.0)
Requirement already satisfied: typing-extensions>=4.2.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from formulaic>=1.1.0->statsmodels>=0.14.5->tabicl[forecast]) (4.16.0)
Requirement already satisfied: wrapt>=1.17.0rc1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from formulaic>=1.1.0->statsmodels>=0.14.5->tabicl[forecast]) (2.5.0)
Requirement already satisfied: filelock in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from torch>=2.2->tabicl[forecast]) (4.0.12)
Requirement already satisfied: sympy>=1.13.3 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from torch>=2.2->tabicl[forecast]) (1.14.0)
Requirement already satisfied: networkx>=2.5.1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from torch>=2.2->tabicl[forecast]) (3.7)
Requirement already satisfied: jinja2 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from torch>=2.2->tabicl[forecast]) (3.1.6)
Requirement already satisfied: fsspec>=0.8.5 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from torch>=2.2->tabicl[forecast]) (2026.9.0)
Requirement already satisfied: mpmath<1.5,>=1.1.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from sympy>=1.13.3->torch>=2.2->tabicl[forecast]) (1.4.1)
Requirement already satisfied: click<9.0.0,>=8.4.2 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from huggingface-hub->tabicl[forecast]) (8.5.0)
Requirement already satisfied: hf-xet<2.0.0,>=1.5.2 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from huggingface-hub->tabicl[forecast]) (1.5.2)
Requirement already satisfied: httpx<1,>=0.23.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from huggingface-hub->tabicl[forecast]) (0.28.1)
Requirement already satisfied: pyyaml>=5.1 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from huggingface-hub->tabicl[forecast]) (6.0.3)
Requirement already satisfied: anyio in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from httpx<1,>=0.23.0->huggingface-hub->tabicl[forecast]) (4.15.1)
Requirement already satisfied: certifi in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from httpx<1,>=0.23.0->huggingface-hub->tabicl[forecast]) (2026.7.22)
Requirement already satisfied: httpcore==1.* in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from httpx<1,>=0.23.0->huggingface-hub->tabicl[forecast]) (1.0.9)
Requirement already satisfied: idna in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from httpx<1,>=0.23.0->huggingface-hub->tabicl[forecast]) (3.20)
Requirement already satisfied: h11>=0.16 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->huggingface-hub->tabicl[forecast]) (0.16.0)
Requirement already satisfied: MarkupSafe>=2.0 in /home/runner/work/forecasting/forecasting/.pixi/envs/default/lib/python3.13/site-packages (from jinja2->torch>=2.2->tabicl[forecast]) (3.0.4)
Note: you may need to restart the kernel to use updated packages.
import functools
import importlib
import re
import warnings
from datetime import UTC, datetime, timedelta
import numpy as np
import plotly.graph_objects as go
import polars as pl
import skrub
from tabicl import TabICLRegressor
import tutorial_helpers
importlib.reload(tutorial_helpers)
from feature_engineering_lib import feature_engineering_outputs
from prediction_intervals_lib import (
concat_horizons,
cross_val_predict,
neg_mape,
neg_mape_scorer,
pinball,
pinball_scorer,
plot_predictions,
)
from single_horizon_prediction_lib import TimeSeriesSplitter
from tutorial_helpers import plot_lorenz_curve, plot_reliability_diagram
warnings.filterwarnings("ignore", category=UserWarning, module="pkg_resources")
def tabicl_quantiles_to_df(prediction, quantiles, mode=skrub.eval_mode()):
if mode == "fit":
return prediction
return pl.DataFrame(prediction, schema=[f"q_{q}" for q in quantiles])
def limit_train_size(
df,
size=tutorial_helpers.TABICL_TRAIN_SIZE, # 9000 by default, 1500 in CI
mode=skrub.eval_mode(),
):
if mode in ("fit", "fit_transform", "preview"):
return df.tail(size)
return df
def sanitize_tabicl_matrix(X):
X = np.asarray(X, dtype=float)
if X.ndim == 1:
X = X.reshape(-1, 1)
X = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0)
if not np.isfinite(X).all():
X = np.where(np.isfinite(X), X, 0.0)
return X
def make_multi_horizon_pred_tabicl(features, y, quantiles):
quantiles_to_predict = skrub.as_data_op(quantiles).skb.set_name("quantiles")
predictor = TabICLRegressor(n_estimators=1)
predict_kwargs = {"output_type": "quantiles", "alphas": quantiles_to_predict}
predictions = {
h: feat.skb.drop(["prediction_time", "target_time"])
.skb.apply(skrub.ToFloat())
.to_numpy()
.skb.apply_func(sanitize_tabicl_matrix)
.skb.apply(predictor, y=y[f"{h}h"], predict_kwargs=predict_kwargs)
.skb.apply_func(tabicl_quantiles_to_df, quantiles_to_predict)
.skb.set_name(f"pred_{h}h")
for h, feat in features.items()
}
return skrub.deferred(concat_horizons)(predictions)
def concat_X_y_predictions(X_test, y_test, prediction):
return pl.concat(
[
X_test,
y_test,
prediction.rename("pred_{}".format),
],
how="horizontal",
)
TIME_HORIZONS = (1, 12, 24)
QUANTILES = (0.05, 0.5, 0.95)
features, y = feature_engineering_outputs(TIME_HORIZONS, TimeSeriesSplitter())
features = {h: features[h].skb.apply_func(limit_train_size) for h in TIME_HORIZONS}
y = y.skb.apply_func(limit_train_size)
pred = (
make_multi_horizon_pred_tabicl(
features,
y,
quantiles=QUANTILES,
)
.skb.with_scoring(functools.partial(neg_mape_scorer, quantile_regression=True))
.skb.with_scoring(pinball_scorer)
)
cv_predictions_tabicl = cross_val_predict(
pred,
environment={"start": "2023-01-01", "end": "2025-05-31"},
)
2025-02-01T00:00:00+00:00
{'neg_mape__average__q_0.05': -0.06916509808064368, 'neg_mape__1h__q_0.05': -0.05586851483330389, 'neg_mape__12h__q_0.05': -0.07099659301685442, 'neg_mape__24h__q_0.05': -0.08063018639177273, 'neg_mape__average__q_0.5': -0.07995331261149095, 'neg_mape__1h__q_0.5': -0.041166832118307246, 'neg_mape__12h__q_0.5': -0.08901421964050539, 'neg_mape__24h__q_0.5': -0.10967888607566023, 'neg_mape__average': -0.07995331261149095, 'neg_mape__1h': -0.041166832118307246, 'neg_mape__12h': -0.08901421964050539, 'neg_mape__24h': -0.10967888607566023, 'neg_mape__average__q_0.95': -0.2187418494209595, 'neg_mape__1h__q_0.95': -0.14495105565391037, 'neg_mape__12h__q_0.95': -0.22147277087785752, 'neg_mape__24h__q_0.95': -0.2898017217311107, 'd2_pinball_score__average__q_0.05': 0.6037598983598957, 'd2_pinball_score__1h__q_0.05': 0.6362510577947884, 'd2_pinball_score__12h__q_0.05': 0.4903481849929787, 'd2_pinball_score__24h__q_0.05': 0.426672003562944, 'd2_pinball_score__average__q_0.5': 0.5215958274067369, 'd2_pinball_score__1h__q_0.5': 0.7520014799074068, 'd2_pinball_score__12h__q_0.5': 0.46487240858188994, 'd2_pinball_score__24h__q_0.5': 0.3479135937309139, 'd2_pinball_score__average__q_0.95': 0.45553721085074445, 'd2_pinball_score__1h__q_0.95': 0.10793103534472748, 'd2_pinball_score__12h__q_0.95': -0.3737828068945248, 'd2_pinball_score__24h__q_0.95': -0.809701036815186}
2025-05-01T00:00:00+00:00
{'neg_mape__average__q_0.05': -0.08552548370691616, 'neg_mape__1h__q_0.05': -0.04813589246142939, 'neg_mape__12h__q_0.05': -0.0959788924399876, 'neg_mape__24h__q_0.05': -0.11246166621933151, 'neg_mape__average__q_0.5': -0.04582253975428424, 'neg_mape__1h__q_0.5': -0.027849276379172616, 'neg_mape__12h__q_0.5': -0.049297158694908576, 'neg_mape__24h__q_0.5': -0.06032118418877153, 'neg_mape__average': -0.04582253975428424, 'neg_mape__1h': -0.027849276379172616, 'neg_mape__12h': -0.049297158694908576, 'neg_mape__24h': -0.06032118418877153, 'neg_mape__average__q_0.95': -0.1625111325130444, 'neg_mape__1h__q_0.95': -0.10995786779347295, 'neg_mape__12h__q_0.95': -0.15997138585731227, 'neg_mape__24h__q_0.95': -0.21760414388834795, 'd2_pinball_score__average__q_0.05': 0.5796819547864691, 'd2_pinball_score__1h__q_0.05': 0.5095011838707564, 'd2_pinball_score__12h__q_0.05': -0.01920764077559345, 'd2_pinball_score__24h__q_0.05': -0.2027122832002788, 'd2_pinball_score__average__q_0.5': 0.5553156768692457, 'd2_pinball_score__1h__q_0.5': 0.7331006530319139, 'd2_pinball_score__12h__q_0.5': 0.5194426981306723, 'd2_pinball_score__24h__q_0.5': 0.41340367944515044, 'd2_pinball_score__average__q_0.95': 0.17417960902083185, 'd2_pinball_score__1h__q_0.95': -0.07004253674201033, 'd2_pinball_score__12h__q_0.95': -0.6028332108458012, 'd2_pinball_score__24h__q_0.95': -1.187983312818036}
plot_predictions(cv_predictions_tabicl[0], horizons=(12,), start="2023-01-01").show()
plot_reliability_diagram(
cv_predictions_tabicl[0],
1,
forecast_quantile=0.50,
).interactive().properties(title="TabICL reliability diagram for quantile 0.50")
plot_reliability_diagram(
cv_predictions_tabicl[0],
1,
forecast_quantile=0.05,
).interactive().properties(title="TabICL reliability diagram for quantile 0.05")
plot_reliability_diagram(
cv_predictions_tabicl[0],
1,
forecast_quantile=0.95,
).interactive().properties(title="TabICL reliability diagram for quantile 0.95")
plot_lorenz_curve(
cv_predictions_tabicl[0],
1,
quantile=0.50,
).interactive().properties(title="TabICL Lorenz curve for quantile 0.50")
plot_lorenz_curve(
cv_predictions_tabicl[0],
1,
quantile=0.05,
).interactive().properties(title="TabICL Lorenz curve for quantile 0.05")
plot_lorenz_curve(
cv_predictions_tabicl[0],
1,
quantile=0.95,
).interactive().properties(title="TabICL Lorenz curve for quantile 0.95")