Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ but cannot always guarantee backwards compatibility. Changes that may **break co

**Improved**

- Added `TimeSeries.idxmin()` and `TimeSeries.idxmax()`, returning a `pandas.Series` (indexed by component) of the time index value at which each component attains its minimum / maximum. Closes [#3115](https://github.com/unit8co/darts/pull/3115) by [Jean-Baptiste Braun](https://github.com/jbbqqf).
- 🚀🚀 Added new forecasting model `PatchTSTFMModel` : IBM's pre-trained ~260M-parameter foundational model for zero-shot forecasting. It supports univariate, multivariate, and multiple time series forecasting without training and can output deterministic or probabilistic forecasts. [#3120](https://github.com/unit8co/darts/pull/3120) by [Dennis Bader](https://github.com/dennisbader).
- Added `use_longer_projection_head` to `TimesFM2p5Model` to enable longer non-autoregressive prediction horizons (up to 1024 steps for `output_chunk_length + output_chunk_shift`). [#3121](https://github.com/unit8co/darts/pull/3121) by [Zhihao Dai](https://github.com/daidahao).
- `TimeSeries.from_dataframe()` now supports time columns of type `pl.Date` for `polars.DataFrame`. [#3124](https://github.com/unit8co/darts/pull/3124) by [Dennis Bader](https://github.com/dennisbader)
Expand Down
43 changes: 43 additions & 0 deletions darts/tests/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3340,6 +3340,49 @@ def test_max(self):
new_ts._values, self.values.max(axis=axis, keepdims=True)
).all()

def test_idxmin_idxmax_univariate_datetime(self):
idx = pd.date_range("2020-01-01", periods=5, freq="D")
values = np.array([3.0, 1.0, 4.0, 0.0, 2.0])
ts = TimeSeries(times=idx, values=values, components=["a"])

idxmin = ts.idxmin()
idxmax = ts.idxmax()
assert list(idxmin.index) == ["a"]
assert list(idxmax.index) == ["a"]
# minimum at position 3 (2020-01-04), maximum at position 2 (2020-01-03)
assert idxmin["a"] == pd.Timestamp("2020-01-04")
assert idxmax["a"] == pd.Timestamp("2020-01-03")

def test_idxmin_idxmax_multivariate(self):
idx = pd.date_range("2020-01-01", periods=3, freq="D")
values = np.array([[1.0, 0.0], [0.0, 0.0], [0.0, 1.0]])
ts = TimeSeries(times=idx, values=values, components=["a", "b"])

idxmin = ts.idxmin()
idxmax = ts.idxmax()
# first occurrence of the minimum, mirroring numpy
assert idxmin["a"] == pd.Timestamp("2020-01-02")
assert idxmin["b"] == pd.Timestamp("2020-01-01")
assert idxmax["a"] == pd.Timestamp("2020-01-01")
assert idxmax["b"] == pd.Timestamp("2020-01-03")

def test_idxmin_idxmax_range_index(self):
values = np.array([5.0, 3.0, 8.0, 1.0])
ts = TimeSeries(
times=pd.RangeIndex(start=10, stop=14, step=1),
values=values,
components=["x"],
)
assert ts.idxmin()["x"] == 13
assert ts.idxmax()["x"] == 12

def test_idxmin_idxmax_stochastic(self):
idx = pd.date_range("2020-01-01", periods=3, freq="D")
# sample 0 min at t=1, sample 1 min at t=2 — medians [3.0, 2.0, 1.5], min at t=2
values = np.array([[[2.0, 4.0]], [[1.0, 3.0]], [[3.0, 0.0]]]) # (3, 1, 2)
ts = TimeSeries(times=idx, values=values, components=["a"])
assert ts.idxmin()["a"] == pd.Timestamp("2020-01-03")

Comment thread
dennisbader marked this conversation as resolved.
def test_sum(self):
for axis in range(3):
new_ts = self.ts.sum(axis=axis)
Expand Down
71 changes: 71 additions & 0 deletions darts/timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -4764,6 +4764,7 @@ def min(self, axis: int = 2) -> Self:

If ``axis=1``, the static covariates and the hierarchy are discarded from the series.


Parameters
----------
axis
Expand Down Expand Up @@ -4793,6 +4794,7 @@ def max(self, axis: int = 2) -> Self:

If ``axis=1``, the static covariates and the hierarchy are discarded from the series.


Parameters
----------
axis
Expand All @@ -4812,6 +4814,75 @@ def max(self, axis: int = 2) -> Self:
**(self._attrs if axis != 1 else dict()),
)

def idxmin(self) -> pd.Series:
"""Return the time index value of the minimum of each component.

For a stochastic series the median over samples is taken before
finding the minimum, so the returned index is well-defined regardless
of ``n_samples``.


Comment on lines +4823 to +4824

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i'd say this is unnecesssary

Returns
-------
pandas.Series
A series indexed by component name. Each value is the timestamp
(or integer index, if the series uses an ``RangeIndex``) at which
that component attains its minimum.

Examples
--------
>>> import pandas as pd
>>> from darts import TimeSeries
>>> df = pd.DataFrame({"a": [1, 0, 0], "b": [0, 0, 1]})
>>> series = TimeSeries.from_dataframe(df)
>>> series.idxmin()
a 1
b 0
dtype: int64
"""
deterministic = (
self._values
if self.is_deterministic
else np.median(self._values, axis=2, keepdims=True)
)
# argmin along time axis → shape (n_components,)
idxs = deterministic[:, :, 0].argmin(axis=0)
return pd.Series(self._time_index[idxs], index=self.components)

def idxmax(self) -> pd.Series:
"""Return the time index value of the maximum of each component.

For a stochastic series the median over samples is taken before
finding the maximum, so the returned index is well-defined regardless
of ``n_samples``.


Comment on lines +4858 to +4859

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

same as above

Returns
-------
pandas.Series
A series indexed by component name. Each value is the timestamp
(or integer index, if the series uses an ``RangeIndex``) at which
that component attains its maximum.

Examples
--------
>>> import pandas as pd
>>> from darts import TimeSeries
>>> df = pd.DataFrame({"a": [1, 0, 0], "b": [0, 0, 1]})
>>> series = TimeSeries.from_dataframe(df)
>>> series.idxmax()
a 0
b 2
dtype: int64
"""
deterministic = (
self._values
if self.is_deterministic
else np.median(self._values, axis=2, keepdims=True)
)
idxs = deterministic[:, :, 0].argmax(axis=0)
return pd.Series(self._time_index[idxs], index=self.components)

def quantile(self, q: float | Sequence[float] = 0.5, **kwargs) -> Self:
"""Return a deterministic series with the desired quantile(s) `q` of each component computed over the samples
of the stochastic series.
Expand Down
Loading