Skip to content

[BUG] Align TimeXer v2 endogenous/exogenous usage with tslib metadata#2009

Merged
phoeenniixx merged 7 commits intosktime:mainfrom
ahmedkansulum:bugfix/timexer-endogenous-exogenous-metadata-v2
Dec 20, 2025
Merged

[BUG] Align TimeXer v2 endogenous/exogenous usage with tslib metadata#2009
phoeenniixx merged 7 commits intosktime:mainfrom
ahmedkansulum:bugfix/timexer-endogenous-exogenous-metadata-v2

Conversation

@ahmedkansulum
Copy link
Contributor

@ahmedkansulum ahmedkansulum commented Dec 15, 2025

Summary

This PR makes the TimeXer v2 implementation consistent with the v2 / tslib design by removing the duplicated configuration of endogenous and exogenous variables inside TimeXer._forecast.

Instead of re-selecting series using self.endogenous_vars / self.exogenous_vars on top of the tslib metadata, the model now relies solely on the tensors provided by the data pipeline (history_target and history_cont).

This implements option 1 discussed in #2003 ("not overriding or passing twice").
Fixes #2003

Motivation / Context

In v2, feature configuration is intended to be described by the metadata produced by TslibDataModule and consumed by TslibBaseModel. TimeXer v2 currently has:

  • feature names and indices described in metadata
  • and additional endogenous_vars / exogenous_vars kwargs that are used in _forecast to re-select columns from history_cont

This leads to two different places where the endogenous / exogenous split can be defined, which is exactly the concern raised in #2003.

The maintainers confirmed that option 1 is preferred: relying on the metadata / data pipeline only, i.e. not overriding or passing the configuration twice.

What this PR changes

In pytorch_forecasting/models/timexer/_timexer_v2.py:

  • TimeXer._forecast no longer uses self.endogenous_vars or self.exogenous_vars to re-select columns from history_cont.

  • Instead, the method now follows the v2 convention:

    • endogenous information is taken from history_target
    • exogenous information is taken from all continuous covariates in history_cont

Concretely, the previous block:

# explicitly set endogenous and exogenous variables
endogenous_cont = history_target
if self.endogenous_vars:
    endogenous_indices = [
        self.feature_names["continuous"].index(var)
        for var in self.endogenous_vars
    ]
    endogenous_cont = history_cont[..., endogenous_indices]

exogenous_cont = history_cont
if self.exogenous_vars:
    exogenous_indices = [
        self.feature_names["continuous"].index(var)
        for var in self.exogenous_vars
    ]
    exogenous_cont = history_cont[..., exogenous_indices]

is replaced by:

# v2 convention:
# - endogenous information comes from the target history
# - exogenous information comes from all continuous covariates
endogenous_cont = history_target
exogenous_cont = history_cont

The rest of _forecast (embedding, encoder, head) remains unchanged.

API / behaviour notes

  • The endogenous_vars and exogenous_vars arguments are still present in TimeXer.__init__ and are stored on self, but they are no longer used in _forecast.
  • This keeps the public signature unchanged for now (no immediate breaking change), while removing the duplicated configuration path that conflicted with the v2 metadata design.
  • In practice, this means TimeXer v2 now always behaves as if the endogenous information is given by the target history and the exogenous information by the continuous covariates provided by TslibDataModule.
  • If desired, a follow-up PR can deprecate or remove these args entirely from the public API.

Tests

On Windows with Python 3.13, I ran:

python -m pytest -k "TimeXer" -q --basetemp="C:\Projects\pytorch-forecasting\.pytest_tmp"
  • 75 tests passed
  • 1 test skipped
  • 0 failures

The failures reported earlier were due to a local Windows permission issue with the default pytest temp directory; pointing --basetemp at a project-local directory resolved that, and the TimeXer tests now run cleanly with the change in place.

Notes

  • This PR is intentionally scoped to the functional change in _forecast only.
  • I am happy to follow up with a separate PR (or extend this one if preferred) to:
    • deprecate/remove the endogenous_vars / exogenous_vars kwargs from TimeXer.__init__, and
    • update the class docstring and docs accordingly.

@codecov
Copy link

codecov bot commented Dec 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@725e0c3). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2009   +/-   ##
=======================================
  Coverage        ?   86.59%           
=======================================
  Files           ?      164           
  Lines           ?     9690           
  Branches        ?        0           
=======================================
  Hits            ?     8391           
  Misses          ?     1299           
  Partials        ?        0           
Flag Coverage Δ
cpu 86.59% <ø> (?)
pytest 86.59% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@phoeenniixx phoeenniixx left a comment

Choose a reason for hiding this comment

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

Hello @ahmedkansulum!
Welcome to pytorch-forecasting!
I think there has been some issue while committing, I can't see the changes made by you. Can you please have a look at it?

@ahmedkansulum
Copy link
Contributor Author

Hello @ahmedkansulum! Welcome to pytorch-forecasting! I think there has been some issue while committing, I can't see the changes made by you. Can you please have a look at it?

@phoeenniixx Thank you.
I am looking into this now and will revert shortly.

@ahmedkansulum
Copy link
Contributor Author

Hi @phoeenniixx,
Thanks for the heads up and the warm welcome! You were right, my earlier commits didn’t actually contain the intended _forecast change, which is why there was no diff versus main.

I have now re-applied the change in pytorch_forecasting/models/timexer/_timexer_v2.py so that _forecast uses history_target for the endogenous input and history_cont for the exogenous covariates, consistent with the v2 metadata / TslibDataModule design. I also re-ran pytest -k "TimeXer" and pre-commit locally and they pass.

Please let me know if anything else needs adjusting.

Copy link
Member

@phoeenniixx phoeenniixx left a comment

Choose a reason for hiding this comment

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

Thanks @ahmedkansulum !
Although I have a doubt: I thought we needed to remove the duplicate usage of exogeneous_var etc from param set of __init__ and use metadata instead to initialise these vars? Or am I missing something here?

Also FYI @PranavBhatP

Copy link
Contributor

@PranavBhatP PranavBhatP left a comment

Choose a reason for hiding this comment

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

@ahmedkansulum along with the changes already in this PR, you are also supposed to remove these params from the __init__. Otherwise everything seems fine.

endogenous_vars: Optional[list[str]] = None,
exogenous_vars: Optional[list[str]] = None,

@ahmedkansulum
Copy link
Contributor Author

@phoeenniixx
@PranavBhatP

Thanks for the clarification, that helps.

I have now:

  • removed endogenous_vars and exogenous_vars from the TimeXer v2 __init__ signature and the corresponding self.* assignments,
  • updated _forecast to rely on history_target (endogenous) and history_cont (exogenous) in line with the v2 metadata / TslibDataModule design,
  • removed the endogenous_vars / exogenous_vars entries from the class docstring, and
  • updated tests/test_models/test_timexer_v2.py so the tests no longer pass these kwargs and instead exercise the metadata-based behaviour.

I re-ran pytest -k "TimeXer" on Windows (with a local --basetemp) and pre-commit on the modified files, and they pass.

Please let me know if you would like any further adjustments (e.g. additional docs or changelog updates).

Copy link
Collaborator

@fkiraly fkiraly left a comment

Choose a reason for hiding this comment

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

Looks good to me now

Copy link
Member

@phoeenniixx phoeenniixx left a comment

Choose a reason for hiding this comment

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

Thanks!

@phoeenniixx phoeenniixx changed the title [BUG] Align TimeXer v2 endogenous/exogenous usage with tslib metadata (fixes #2003) [BUG] Align TimeXer v2 endogenous/exogenous usage with tslib metadata Dec 20, 2025
@phoeenniixx phoeenniixx merged commit dbfd38b into sktime:main Dec 20, 2025
29 checks passed
@ahmedkansulum
Copy link
Contributor Author

Thank you all for your support.

@phoeenniixx phoeenniixx added bug Something isn't working module:models labels Jan 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working module:models

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] why does TimeXer have endogenous_vars and exogenous_vars in __init__?

4 participants