Skip to main content

Conforme

CI License: MIT Python 3.12+

Conforme is a conformal forecasting library for panels of time series. It makes point forecasts at many origins, reconciles them over a hierarchy, and calibrates bands and bounds from out-of-sample residuals.

Install

Install conforme from PyPI:

pip install conforme
# or
uv add conforme

The vendor model adapters need an extra: stats (statsforecast), ml (mlforecast), or neural (neuralforecast).

pip install "conforme[stats]"

Quick start

import numpy as np
import pandas as pd

from conforme import Absolute, BottomUp, Hierarchy, LeadTime, Panel, SeasonalNaive, Signed
from conforme import SplitQuantile, Step, replay, rolling_forecasts
from conforme.metrics import coverage

rng = np.random.default_rng(0)
series = np.array(["a", "b", "c"])
periods = pd.date_range("2024-01-01", periods=120, freq="D")
panel = Panel(series, periods, rng.poisson(5.0, (3, 120)), "D")
hierarchy = Hierarchy.from_attributes(
    series, pd.DataFrame({"group": ["x", "x", "y"]}, index=series)
)

origins = np.arange(60, 113)  # each origin is the index of the last observed period
run = rolling_forecasts(panel, hierarchy, SeasonalNaive(7), BottomUp(hierarchy), origins, 7)
actuals = hierarchy.aggregate(panel.values)

calibrator = SplitQuantile(0.9, window=28)
bands = replay(run, actuals, target=Step(), score=Absolute(), calibrator=calibrator)
bound = replay(run, actuals, target=LeadTime(7), score=Signed(), calibrator=calibrator)
print(coverage(bands.target, bands.lower, bands.upper))

Concepts

Shapes use these axes: B bottom series, T periods, N nodes with bottoms first, S forecast series (B for BottomUp, N otherwise), O origins, H forecast steps, and C target columns (H for Step, 1 for LeadTime).

Panel and Hierarchy go to the Forecaster, base forecasts to the Reconciler, points to the Calibrator, bounds to order_up_to and settle

Stage Names
Data Panel, Hierarchy, Covariate
Forecast Forecaster, Reconciler (BottomUp, Identity, WlsStruct), rolling_forecasts
Calibrate Target (Step, LeadTime), Score (Absolute, Signed), Loss (Miss), Calibrator (SplitQuantile, ACI, QuantileTracker, RiskControl), step, replay
Decide critical_ratio, order_up_to, settle
Measure conforme.metrics: coverage, width, interval score, pinball, cost

Two rules hold everywhere. A model reads only its window, so a later value cannot change a point unless a covariate declares it known ahead. A calibrator sees a score only once its target is known, and before the origin that knows it issues.

Architecture has the shapes and the modules.

Write a calibrator

A calibrator owns its target, a level or a loss, and is three functions of an explicit state. conforme.online handles the origins, the delays, and the indexing. A new method is one file in conforme/conformal/calibrators/ that imports only calibrators.base, calibrators.ranks, and conformal.losses. This is the whole of a quantile tracker:

import numpy as np

from conforme.conformal.calibrators.base import Calibrator


class Tracker(Calibrator):
    def __init__(self, level, lr):
        self.level = level
        self.lr = lr

    def initial_state(self, n_nodes, n_columns):
        return {"q": np.zeros((n_nodes, n_columns))}

    def update(self, state, feedback):
        q = state["q"].copy()
        for row, column in enumerate(feedback.column):  # one row = one origin, one column
            miss = feedback.scores[row] > feedback.issued[row]
            q[:, column] += self.lr * (miss - (1 - self.level))
        return {"q": q}

    def threshold(self, state):
        return state["q"].astype(np.float32)

Keep the state in numpy arrays. Then a product can save it after each origin with conforme.online.state.flatten and continue from it.

Models

Model Kind Install
conforme.forecast.models.naive.SeasonalNaive local core
conforme.forecast.models.statsforecast.StatsForecastModel local, any statsforecast.models model conforme[stats]
conforme.forecast.models.mlforecast.MLForecast global regressor with lags and covariates conforme[ml]
conforme.forecast.models.neuralforecast.NeuralForecast global network from neuralforecast.models conforme[neural]
from lightgbm import LGBMRegressor
from conforme import BottomUp, Covariate, rolling_forecasts
from conforme.forecast.models.mlforecast import MLForecast

model = MLForecast(
    LGBMRegressor(), lags=[7, 14, 28], features=["price"], fit_periods=365, lookback=84
)
price = Covariate(prices, known_ahead=True, aggregate="mean")  # [B, T + H]
run = rolling_forecasts(
    panel,
    hierarchy,
    model,
    BottomUp(hierarchy),
    origins,
    28,
    refit_every=7,
    covariates={"price": price},
)

Benchmarks

bench/ is a folder of scripts. They load benchmark data from a directory, run benchmark protocols, and compare calibrators. They import the installed conforme. Raw data is not in Git.

Script Content
vn2.py load(path): weekly VN2 sales with the out-of-stock mask, hierarchy, and starting stock. play(data, bounds): six orders up to the bounds, eight settled weeks, holding 0.2 and shortage 1.0
m5.py load(path): daily M5 sales and the 12-level hierarchy (42,840 nodes). prices(horizon): the sell price covariate
compare.py compare(forecasts, actuals, calibrators, target, score, level): one row of metrics per method, on the cells where each method was ready

vn2_conformal.py runs the whole VN2 path in about one second:

uv run python bench/vn2_conformal.py data/vn2

Documents

Development

uv sync --group dev
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run ty check src/
uv build --no-sources

See Contributing.

License

MIT

Metadata

Release files for conforme 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for conforme 0.1.0
File Size Uploaded
conforme-0.1.0.tar.gz 27.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for conforme 0.1.0
File Interpreter ABI Platform
conforme-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 68.6 kB

Release files / conforme-0.1.0.tar.gz

Download URL conforme-0.1.0.tar.gz
Size 27.1 kB
Tags Source
SHA-256 checksum
How to use checksums
ee2be13833878ab2dfebaf27cc0dd419cabe9ed74e1f5c2418e473048e3b6824
BLAKE2b-256 checksum
How to use checksums
111931657cfbb790965b8672fbacc357338b4544b2298be4f342954c85fc5de1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / conforme-0.1.0-py3-none-any.whl

Download URL conforme-0.1.0-py3-none-any.whl
Size 41.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
357012af1819772a1c36265540e5c4bd84e93cd359d2ddadf135f7d566367fc5
BLAKE2b-256 checksum
How to use checksums
70c52cfadecd5f8795896f6a4e464e21a4860d1a3c3c81606a31679af15f95a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page