Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ETS model #369

Merged
merged 21 commits into from
Oct 25, 2024
Merged

Conversation

jessegrabowski
Copy link
Member

@jessegrabowski jessegrabowski commented Jul 27, 2024

Adds BayesianETS as an available statespace model.

According to this book, this is great baseline model for forecasting. I don't have a lot of experience with it, but statsmodels implements it, so I did too.

Todo:

  • Write an example notebook
  • Add a class method utility to decompose the time series into level, trend, and seasonal components
  • Test time series generation against statsmodels
  • Check whether the first state is correctly interpreted in the Kalman filter

The last point is a but subtle. From the statsmodel implementation:

One consequence is that the "initial state" corresponds to the "filtered" state at time t=0, but this is different from the usual state space initialization used in Statsmodels, which initializes the model with the "predicted" state at time t=1.

I have no idea whether this is important or not for the present implementation, I need to look at it more closely.

Some comments:
In general I just follow the statsmodel implementation, and I'm testing that all the statespace matrices match those of statsmodels. The one difference is in the selection matrix. Looking at the book equations, for example:

$$ \begin{align} y_t &= \ell_t + \epsilon_t \\ \ell_t &= \ell_{t-1} + \alpha \epsilon_t \end{align} $$

The general statespace equation is:

$$ \begin{align} x_t &= T x_{t-1} + c + R \epsilon_t \\ y_t &= Z x_t + d + H \end{align} $$

This implies states:

$$x_t = \begin{bmatrix} \epsilon_t \\ \ell_t \end{bmatrix}$$

So:

$$T = \begin{bmatrix} 0 & 0 \\ 0 & 1 \end{bmatrix}, R = \begin{bmatrix} 1 \\ \alpha \end{bmatrix} $$

This all seems straightforward, but statsmodels sets the (0, 0) element of $R$ to be $1 - \alpha$. That really doesn't seem right, so I didn't do it.

@jessegrabowski
Copy link
Member Author

jessegrabowski commented Jul 29, 2024

So statsmodels was right of course. My equations above were slightly wrong. We want to have:

$$ \begin{align} y_t &= \ell_{t-1} + \epsilon_t \\ \ell_t &= \ell_{t-1} + \alpha \epsilon_t \end{align} $$

This could be done by making $y_t$ a hidden state, then:

$$T = \begin{bmatrix} 0 & 1 \\ 0 & 1 \end{bmatrix}, Z_t = \begin{bmatrix} 1 & 0 \end{bmatrix}$$

But we can also get back to the timing that I had above, with $y_t = \ell_t + \epsilon_t$, if we do some algebra. Specifically, $\ell_{t-1} = \ell_t - \alpha \epsilon_t$, so $y_t = \ell_t + \epsilon_t - \alpha \epsilon_t = \ell_t + (1 - \alpha) \epsilon_t$

So that's where the $R$ adjustments in statsmodels were coming from. The same thing happens when you bring in a seasonal component; it becomes $y_t = \ell_t + s_{t-m}+ (1 - \alpha - \gamma) \epsilon_t$

I also added an alternative parameterization that I thing might be nicer for priors. Under the $\alpha, \beta, \gamma$ parameterization, you need $\alpha \in (0, 1)$, $\beta \in (0, \alpha)$, and $\gamma \in (0, 1 - \alpha)$. Which is pretty hairy to set priors for. If instead you go with:

$$ \begin{align} y_t &= \ell_{t-1} + s_{t-m-1} + \epsilon_t \\ \ell_t &= \ell_{t-1} + b_{t-1} + \alpha \epsilon_t \\ b_t &= b_{t-1} + \alpha \beta^\star \epsilon_t \\ s_{t-m} &= s_{t-m-1} + (1 - \alpha) \gamma^\star \epsilon_t \end{align} $$

Then all of $\alpha, \beta^\star, \gamma^\star$ are between 0 and 1, which is nice. So that's the default now, and you can ask for the other one with use_transformed_parameterization=True.

Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@jessegrabowski jessegrabowski force-pushed the exponential-smoothing branch 2 times, most recently from aeb76ee to 3a48e39 Compare September 23, 2024 11:44
@jessegrabowski jessegrabowski marked this pull request as ready for review October 13, 2024 09:38
pyproject.toml Outdated Show resolved Hide resolved
@ricardoV94
Copy link
Member

Typo: 3 instances of "forcasting" (e missing) in the notebook

@jessegrabowski jessegrabowski force-pushed the exponential-smoothing branch 2 times, most recently from 295a5cc to e2c7369 Compare October 20, 2024 06:51
@junpenglao
Copy link
Member

Oh wow, I have seen folks express ETS as a states pace model, but never in a way that so clear and straightforward - very nice!

@jessegrabowski jessegrabowski merged commit 5de65eb into pymc-devs:main Oct 25, 2024
7 checks passed
@jessegrabowski jessegrabowski deleted the exponential-smoothing branch October 25, 2024 16:17
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