From bf51476cb0574fbc098ded92277d192e0bb05c97 Mon Sep 17 00:00:00 2001 From: madtoinou <32447896+madtoinou@users.noreply.github.com> Date: Sat, 24 Feb 2024 13:36:12 +0100 Subject: [PATCH] Fix/ts prepend (#2237) * fix: append/prepend correctul retain components names and hierarchy * updated changelog * fix: revert unecessary change * update changelog --------- Co-authored-by: dennisbader --- CHANGELOG.md | 3 +- darts/tests/test_timeseries.py | 55 ++++++++++++++++++++-------------- darts/timeseries.py | 4 ++- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39747ba136..eb210770a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,8 @@ but cannot always guarantee backwards compatibility. Changes that may **break co **Fixed** - Fixed a bug in probabilistic `LinearRegressionModel.fit()`, where the `model` attribute was not pointing to all underlying estimators. [#2205](https://github.com/unit8co/darts/pull/2205) by [Antoine Madrona](https://github.com/madtoinou). - Raise an error in `RegressionEsembleModel` when the `regression_model` was created with `multi_models=False` (not supported). [#2205](https://github.com/unit8co/darts/pull/2205) by [Antoine Madrona](https://github.com/madtoinou). -- Fixed a bug in `coefficient_of_variaton()` with `intersect=True`, where the coefficient was not computed on the intersection. [#2202](https://github.com/unit8co/darts/pull/2202) by [Antoine Madrona](https://github.com/madtoinou). +- Fixed a bug in `coefficient_of_variation()` with `intersect=True`, where the coefficient was not computed on the intersection. [#2202](https://github.com/unit8co/darts/pull/2202) by [Antoine Madrona](https://github.com/madtoinou). +- Fixed a bug in `TimeSeries.append/prepend_values()`, where the components names and the hierarchy were dropped. [#2237](https://github.com/unit8co/darts/pull/2237) by [Antoine Madrona](https://github.com/madtoinou). ### For developers of the library: - Updated pre-commit hooks to the latest version using `pre-commit autoupdate`. diff --git a/darts/tests/test_timeseries.py b/darts/tests/test_timeseries.py index edefc2fe9d..ef892d4753 100644 --- a/darts/tests/test_timeseries.py +++ b/darts/tests/test_timeseries.py @@ -627,9 +627,11 @@ def helper_test_shift(test_case, test_series: TimeSeries): def helper_test_append(test_case, test_series: TimeSeries): # reconstruct series seriesA, seriesB = test_series.split_after(pd.Timestamp("20130106")) - assert seriesA.append(seriesB) == test_series - assert seriesA.append(seriesB).freq == test_series.freq - assert test_series.time_index.equals(seriesA.append(seriesB).time_index) + appended = seriesA.append(seriesB) + assert appended == test_series + assert appended.freq == test_series.freq + assert test_series.time_index.equals(appended.time_index) + assert appended.components.equals(seriesA.components) # Creating a gap is not allowed seriesC = test_series.drop_before(pd.Timestamp("20130108")) @@ -648,23 +650,26 @@ def helper_test_append_values(test_case, test_series: TimeSeries): # reconstruct series seriesA, seriesB = test_series.split_after(pd.Timestamp("20130106")) arrayB = seriesB.all_values() - assert seriesA.append_values(arrayB) == test_series - assert test_series.time_index.equals(seriesA.append_values(arrayB).time_index) + appended = seriesA.append_values(arrayB) + assert appended == test_series + assert test_series.time_index.equals(appended.time_index) # arrayB shape shouldn't affect append_values output: squeezed_arrayB = arrayB.squeeze() - assert seriesA.append_values(squeezed_arrayB) == test_series - assert test_series.time_index.equals( - seriesA.append_values(squeezed_arrayB).time_index - ) + appended_sq = seriesA.append_values(squeezed_arrayB) + assert appended_sq == test_series + assert test_series.time_index.equals(appended_sq.time_index) + assert appended_sq.components.equals(seriesA.components) @staticmethod def helper_test_prepend(test_case, test_series: TimeSeries): # reconstruct series seriesA, seriesB = test_series.split_after(pd.Timestamp("20130106")) - assert seriesB.prepend(seriesA) == test_series - assert seriesB.prepend(seriesA).freq == test_series.freq - assert test_series.time_index.equals(seriesB.prepend(seriesA).time_index) + prepended = seriesB.prepend(seriesA) + assert prepended == test_series + assert prepended.freq == test_series.freq + assert test_series.time_index.equals(prepended.time_index) + assert prepended.components.equals(seriesB.components) # Creating a gap is not allowed seriesC = test_series.drop_before(pd.Timestamp("20130108")) @@ -683,15 +688,17 @@ def helper_test_prepend_values(test_case, test_series: TimeSeries): # reconstruct series seriesA, seriesB = test_series.split_after(pd.Timestamp("20130106")) arrayA = seriesA.data_array().values - assert seriesB.prepend_values(arrayA) == test_series - assert test_series.time_index.equals(seriesB.prepend_values(arrayA).time_index) + prepended = seriesB.prepend_values(arrayA) + assert prepended == test_series + assert test_series.time_index.equals(prepended.time_index) + assert prepended.components.equals(test_series.components) # arrayB shape shouldn't affect append_values output: squeezed_arrayA = arrayA.squeeze() - assert seriesB.prepend_values(squeezed_arrayA) == test_series - assert test_series.time_index.equals( - seriesB.prepend_values(squeezed_arrayA).time_index - ) + prepended_sq = seriesB.prepend_values(squeezed_arrayA) + assert prepended_sq == test_series + assert test_series.time_index.equals(prepended_sq.time_index) + assert prepended_sq.components.equals(test_series.components) def test_slice(self): TestTimeSeries.helper_test_slice(self, self.series1) @@ -711,8 +718,8 @@ def test_shift(self): def test_append(self): TestTimeSeries.helper_test_append(self, self.series1) # Check `append` deals with `RangeIndex` series correctly: - series_1 = linear_timeseries(start=1, length=5, freq=2) - series_2 = linear_timeseries(start=11, length=2, freq=2) + series_1 = linear_timeseries(start=1, length=5, freq=2, column_name="A") + series_2 = linear_timeseries(start=11, length=2, freq=2, column_name="B") appended = series_1.append(series_2) expected_vals = np.concatenate( [series_1.all_values(), series_2.all_values()], axis=0 @@ -720,6 +727,7 @@ def test_append(self): expected_idx = pd.RangeIndex(start=1, stop=15, step=2) assert np.allclose(appended.all_values(), expected_vals) assert appended.time_index.equals(expected_idx) + assert appended.components.equals(series_1.components) def test_append_values(self): TestTimeSeries.helper_test_append_values(self, self.series1) @@ -732,12 +740,13 @@ def test_append_values(self): expected_idx = pd.RangeIndex(start=1, stop=15, step=2) assert np.allclose(appended.all_values(), expected_vals) assert appended.time_index.equals(expected_idx) + assert appended.components.equals(series.components) def test_prepend(self): TestTimeSeries.helper_test_prepend(self, self.series1) # Check `prepend` deals with `RangeIndex` series correctly: - series_1 = linear_timeseries(start=1, length=5, freq=2) - series_2 = linear_timeseries(start=11, length=2, freq=2) + series_1 = linear_timeseries(start=1, length=5, freq=2, column_name="A") + series_2 = linear_timeseries(start=11, length=2, freq=2, column_name="B") prepended = series_2.prepend(series_1) expected_vals = np.concatenate( [series_1.all_values(), series_2.all_values()], axis=0 @@ -745,6 +754,7 @@ def test_prepend(self): expected_idx = pd.RangeIndex(start=1, stop=15, step=2) assert np.allclose(prepended.all_values(), expected_vals) assert prepended.time_index.equals(expected_idx) + assert prepended.components.equals(series_1.components) def test_prepend_values(self): TestTimeSeries.helper_test_prepend_values(self, self.series1) @@ -757,6 +767,7 @@ def test_prepend_values(self): expected_idx = pd.RangeIndex(start=-3, stop=11, step=2) assert np.allclose(prepended.all_values(), expected_vals) assert prepended.time_index.equals(expected_idx) + assert prepended.components.equals(series.components) def test_with_values(self): vals = np.random.rand(5, 10, 3) diff --git a/darts/timeseries.py b/darts/timeseries.py index 7a9ad9dfba..6ac6aa269a 100644 --- a/darts/timeseries.py +++ b/darts/timeseries.py @@ -2744,7 +2744,7 @@ def append(self, other: Self) -> Self: ) raise_if_not( other.freq == self.freq, - "Appended TimeSeries must have the same frequency as the current one", + "Both series must have the same frequency.", logger, ) raise_if_not( @@ -2875,6 +2875,8 @@ def prepend_values(self, values: np.ndarray) -> Self: times=idx, fill_missing_dates=False, static_covariates=self.static_covariates, + columns=self.columns, + hierarchy=self.hierarchy, ) )