Skip to content

feat: add UCM (Unobserved Components Model) support#1081

Open
formeo wants to merge 11 commits intoNixtla:mainfrom
formeo:feat/ucm-model
Open

feat: add UCM (Unobserved Components Model) support#1081
formeo wants to merge 11 commits intoNixtla:mainfrom
formeo:feat/ucm-model

Conversation

@formeo
Copy link

@formeo formeo commented Jan 25, 2026

Feature: Add UCM (Unobserved Components Model) Support

Closes #1012

Summary

This PR adds support for Unobserved Components Models (UCM), also known as Structural Time Series Models. UCM is a well-known and proven forecasting approach that decomposes time series into interpretable components.

What is UCM?

UCM (Harvey, 1989) decomposes a time series into:

  • Level - intercept that can vary over time
  • Trend - slope that can vary over time
  • Seasonal - periodic patterns
  • Cycle - longer-term oscillations
  • Irregular - noise

This is similar to classical decomposition but uses state-space methods and the Kalman filter, allowing for:

  • Stochastic (time-varying) components
  • Proper uncertainty quantification
  • Missing data handling
  • Exogenous variables

Implementation

This PR adds a wrapper around statsmodels.tsa.statespace.structural.UnobservedComponents that follows the statsforecast API.

New Classes

  1. UCM - Full UCM model with all configuration options
  2. LocalLevel - Convenience class for random walk model
  3. LocalLinearTrend - Convenience class for level + trend model
  4. SmoothTrend - Convenience class for integrated random walk
  5. RandomWalkWithDrift - Convenience class for RW with drift

API

from statsforecast.models import UCM, LocalLevel, LocalLinearTrend

# Basic usage
model = UCM(level='local level', seasonal=12)
model.fit(y)
forecast = model.predict(h=12, level=[90, 95])

# Convenience classes
model = LocalLinearTrend(seasonal=12)

# With StatsForecast
sf = StatsForecast(
    models=[
        LocalLevel(seasonal=12),
        LocalLinearTrend(seasonal=12),
        UCM(level='smooth trend', seasonal=12),
    ],
    freq='MS',
)
sf.fit(df)
forecast = sf.predict(h=12, level=[90])

Features

  • ✅ Full statsforecast API compatibility (fit, predict, forecast, predict_in_sample)
  • ✅ Prediction intervals via statsmodels state-space methods
  • ✅ Exogenous variables support
  • ✅ Component extraction (get_components())
  • ✅ Multiple level/trend specifications (local level, local linear trend, smooth trend, etc.)
  • ✅ Seasonal component with configurable period
  • ✅ Cycle and autoregressive components
  • ✅ Works with StatsForecast parallelization

Testing

import numpy as np
from statsforecast import StatsForecast
from statsforecast.models import UCM, LocalLevel, LocalLinearTrend

# Create data with trend and seasonality
np.random.seed(42)
n = 120
t = np.arange(n)
y = 50 + 0.5 * t + 10 * np.sin(2 * np.pi * t / 12) + np.random.randn(n) * 2

# Test models
for Model in [LocalLevel, LocalLinearTrend]:
    model = Model(seasonal=12)
    model.fit(y)
    fc = model.predict(h=12, level=[95])
    print(f"{model}: {fc['mean'][:3]}")

Dependencies

  • statsmodels (already an optional dependency for some models)

Checklist

  • Implements requested feature (UCM model support #1012)
  • Follows statsforecast API conventions
  • Includes comprehensive docstrings
  • Works with StatsForecast parallelization
  • Handles both pandas and numpy returns from statsmodels
  • Convenience classes for common use cases

References

@CLAassistant
Copy link

CLAassistant commented Jan 25, 2026

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@MMenchero MMenchero self-assigned this Jan 28, 2026
@MMenchero MMenchero requested a review from Copilot January 28, 2026 02:25
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for Unobserved Components Models (UCM), also known as Structural Time Series Models, by wrapping statsmodels' UnobservedComponents class to conform to the statsforecast API. UCM decomposes time series into interpretable components (level, trend, seasonal, cycle, irregular) using state-space methods and the Kalman filter.

Changes:

  • Added new UCM implementation module with full model class and convenience subclasses
  • Integrated UCM classes into statsforecast's model registry
  • Added comprehensive test suite covering all UCM functionality

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 15 comments.

File Description
python/statsforecast/ucm.py New module implementing UCM wrapper with base class and convenience subclasses (LocalLevel, LocalLinearTrend, SmoothTrend)
python/statsforecast/models.py Updated exports to include new UCM model classes
tests/test_ucm.py Comprehensive test suite covering UCM functionality including fit/predict, seasonality, prediction intervals, components, exogenous variables, and StatsForecast integration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@MMenchero
Copy link
Contributor

Hi @formeo thank you for your contribution. Please double check the import paths, as shown above.

Copy link
Author

@formeo formeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 12, 2026

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing formeo:feat/ucm-model (1dd2b72) with main (65569e1)

Open in CodSpeed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UCM model support

3 participants

Comments