Skip to content

[FIX] UCM: remove dead _calculate_sigma helper and unused sigma storage#1136

Closed
shaun0927 wants to merge 1 commit into
Nixtla:mainfrom
shaun0927:fix/ucm-remove-dead-sigma
Closed

[FIX] UCM: remove dead _calculate_sigma helper and unused sigma storage#1136
shaun0927 wants to merge 1 commit into
Nixtla:mainfrom
shaun0927:fix/ucm-remove-dead-sigma

Conversation

@shaun0927

Copy link
Copy Markdown
Contributor

Summary

UCM defines a private _calculate_sigma helper at ucm.py:25 and stores its result in model_["sigma"] at ucm.py:292, but no method ever reads it. predict, predict_in_sample, and forecast all retrieve intervals from forecast.conf_int(alpha=…) (statsmodels) directly. UCM does not implement simulate() either, so the simulation pattern from #1072 (which consumes model_["sigma"]) is not in play.

The helper is therefore dead code with two further problems:

  1. It shadows the project's canonical statsforecast.utils._calculate_sigma, which is used by 30+ call sites in models.py.
  2. It uses a different denominator (max(n - 1, 1) instead of n) — and the convention everywhere else is _calculate_sigma(residuals, len(residuals) - n_params), i.e. the caller pre-subtracts the parameter count.

Reproducer

import inspect
import numpy as np
from statsforecast.models import UCM
import statsforecast.ucm as ucm_mod
import statsforecast.utils as utils_mod

y = np.cumsum(np.random.default_rng(0).standard_normal(100)) + 50
m = UCM(level="local level"); m.fit(y)
print("sigma stored:", m.model_["sigma"])
print("UCM.simulate exists:", hasattr(UCM, "simulate"))   # False

# Local helper duplicates utils with a different denominator:
print(inspect.getsource(ucm_mod._calculate_sigma))
print(inspect.getsource(utils_mod._calculate_sigma))

Changes

This PR removes the dead path. A follow-up can wire UCM into simulate() later (following the pattern from #1072), at which point the canonical from statsforecast.utils import _calculate_sigma should be imported and the correct n - n_params denominator used.

 # python/statsforecast/ucm.py
-def _calculate_sigma(residuals: np.ndarray, n: int) -> float:
-    """Calculate standard error of residuals."""
-    return np.sqrt(np.sum(residuals ** 2) / max(n - 1, 1))
-
 ...

     def fit(self, y, X=None):
         ...
-        # Calculate sigma from residuals
-        residuals = y - fitted_vals
-        self.model_["sigma"] = _calculate_sigma(residuals, y.size)
         return self

UCM stored model_["sigma"] but no method (predict, predict_in_sample,
forecast) read it; intervals come from statsmodels `forecast.conf_int`
directly, and UCM does not implement `simulate()`. The local
_calculate_sigma also shadowed statsforecast.utils._calculate_sigma
with a different denominator (max(n-1, 1) instead of the convention
n - n_params used by the 30+ call sites in models.py). A follow-up
can wire UCM into the simulate API from Nixtla#1072 if/when that's planned.
@CLAassistant

CLAassistant commented Apr 17, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@nasaul

nasaul commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

We are refactoring the UCM model in #1158

@nasaul nasaul closed this Jun 24, 2026
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.

3 participants