コード例 #1
0
        def test_static_covariates_support(self):
            target_multi = concatenate(
                [tg.sine_timeseries(length=10, freq="h")] * 2, axis=1)

            target_multi = target_multi.with_static_covariates(
                pd.DataFrame([[0.0, 1.0], [2.0, 3.0]], index=["st1", "st2"]))

            # should work with cyclic encoding for time index
            model = TFTModel(
                input_chunk_length=3,
                output_chunk_length=4,
                add_encoders={"cyclic": {
                    "future": "hour"
                }},
                pl_trainer_kwargs={"fast_dev_run": True},
            )
            model.fit(target_multi, verbose=False)
            assert len(model.model.static_variables) == len(
                target_multi.static_covariates.columns)

            model.predict(n=1, series=target_multi, verbose=False)

            # raise an error when trained with static covariates of wrong dimensionality
            target_multi = target_multi.with_static_covariates(
                pd.concat([target_multi.static_covariates] * 2, axis=1))
            with pytest.raises(ValueError):
                model.predict(n=1, series=target_multi, verbose=False)

            # raise an error when trained with static covariates and trying to predict without
            target_multi = target_multi.with_static_covariates(None)
            with pytest.raises(ValueError):
                model.predict(n=1, series=target_multi, verbose=False)
コード例 #2
0
    def test_concatenate_dim_samples(self):
        """
        Test concatenation with static covariates along sample dimension (axis=2)
        Along sample dimension, we only take the static covariates of the first series (as we components and
        time don't change).
        """
        static_covs_left = pd.DataFrame([[0, 1]], columns=["st1",
                                                           "st2"]).astype(int)
        static_covs_right = pd.DataFrame([[3, 4]], columns=["st3",
                                                            "st4"]).astype(int)

        ts_left = linear_timeseries(
            length=10).with_static_covariates(static_covs_left)
        ts_right = linear_timeseries(
            length=10).with_static_covariates(static_covs_right)

        ts_concat = concatenate([ts_left, ts_right], axis=2)
        assert ts_concat.static_covariates.equals(ts_left.static_covariates)
コード例 #3
0
    def test_concatenate_dim_time(self):
        """
        Test concatenation with static covariates along time dimension (axis=0)
        Along time dimension, we only take the static covariates of the first series (as static covariates are
        time-independant).
        """
        static_covs_left = pd.DataFrame([[0, 1]], columns=["st1",
                                                           "st2"]).astype(int)
        static_covs_right = pd.DataFrame([[3, 4]], columns=["st3",
                                                            "st4"]).astype(int)

        ts_left = linear_timeseries(
            length=10).with_static_covariates(static_covs_left)
        ts_right = linear_timeseries(
            length=10, start=ts_left.end_time() +
            ts_left.freq).with_static_covariates(static_covs_right)

        ts_concat = concatenate([ts_left, ts_right], axis=0)
        assert ts_concat.static_covariates.equals(ts_left.static_covariates)
コード例 #4
0
    def _encode_sequence(
        self,
        encoders: Sequence[SingleEncoder],
        transformer: Optional[SequentialEncoderTransformer],
        target: Sequence[TimeSeries],
        covariate: Optional[SupportedTimeSeries],
        n: Optional[int] = None,
    ) -> List[TimeSeries]:
        """Sequentially encodes the index of all input target/covariate TimeSeries

        If `n` is `None` it is a prediction and method `encoder.encode_inference()` is called.
        Otherwise, it is a training case and `encoder.encode_train()` is called.
        """

        encode_method = "encode_train" if n is None else "encode_inference"

        encoded_sequence = []
        if covariate is None:
            covariate = [None] * len(target)
        else:
            covariate = [covariate] if isinstance(covariate,
                                                  TimeSeries) else covariate

        for ts, pc in zip(target, covariate):
            encoded = concatenate(
                [
                    getattr(enc, encode_method)(
                        target=ts, covariate=pc, merge_covariate=False, n=n)
                    for enc in encoders
                ],
                axis=DIMS[1],
            )
            encoded_sequence.append(
                self._merge_covariate(encoded=encoded, covariate=pc))

        if transformer is not None:
            encoded_sequence = transformer.transform(encoded_sequence)

        return encoded_sequence
コード例 #5
0
class ReconciliationTestCase(unittest.TestCase):
    __test__ = True

    @classmethod
    def setUpClass(cls):
        logging.disable(logging.CRITICAL)

    np.random.seed(42)
    """ test case with a more intricate hierarchy """
    LENGTH = 200
    total_series = (tg.sine_timeseries(value_frequency=0.03, length=LENGTH) +
                    1 + tg.gaussian_timeseries(length=LENGTH) * 0.2)
    bottom_1 = total_series / 3 + tg.gaussian_timeseries(length=LENGTH) * 0.01
    bottom_2 = 2 * total_series / 3 + tg.gaussian_timeseries(
        length=LENGTH) * 0.01
    series = concatenate([total_series, bottom_1, bottom_2], axis=1)
    hierarchy = {"sine_1": ["sine"], "sine_2": ["sine"]}
    series = series.with_hierarchy(hierarchy)

    # get a single forecast
    model = LinearRegressionModel(lags=30, output_chunk_length=10)
    model.fit(series)
    pred = model.predict(n=20)

    # get a backtest forecast to get residuals
    pred_back = model.historical_forecasts(series,
                                           start=0.75,
                                           forecast_horizon=10)
    intersection = series.slice_intersect(pred_back)
    residuals = intersection - pred_back
    """ test case with a more intricate hierarchy """
    components_complex = ["total", "a", "b", "x", "y", "ax", "ay", "bx", "by"]

    hierarchy_complex = {
        "ax": ["a", "x"],
        "ay": ["a", "y"],
        "bx": ["b", "x"],
        "by": ["b", "y"],
        "a": ["total"],
        "b": ["total"],
        "x": ["total"],
        "y": ["total"],
    }

    series_complex = TimeSeries.from_values(
        values=np.random.rand(50, len(components_complex), 5),
        columns=components_complex,
        hierarchy=hierarchy_complex,
    )

    def _assert_reconciliation(self, fitted_recon):
        pred_r = fitted_recon.transform(self.pred)
        np.testing.assert_almost_equal(
            pred_r["sine"].values(copy=False),
            (pred_r["sine_1"] + pred_r["sine_2"]).values(copy=False),
        )

    def _assert_reconciliation_complex(self, fitted_recon):
        reconciled = fitted_recon.transform(self.series_complex)

        def _assert_comps(comp, comps):
            np.testing.assert_almost_equal(
                reconciled[comp].values(copy=False),
                sum(reconciled[c] for c in comps).values(copy=False),
            )

        _assert_comps("a", ["ax", "ay"])
        _assert_comps("b", ["bx", "by"])
        _assert_comps("x", ["ax", "bx"])
        _assert_comps("y", ["ay", "by"])
        _assert_comps("total", ["ax", "ay", "bx", "by"])
        _assert_comps("total", ["a", "b"])
        _assert_comps("total", ["x", "y"])

    def test_bottom_up(self):
        recon = BottomUpReconciliator()
        self._assert_reconciliation(recon)

    def test_top_down(self):
        # should work when fitting on training series
        recon = TopDownReconciliator()
        recon.fit(self.series)
        self._assert_reconciliation(recon)

        # or when fitting on forecasts
        recon = TopDownReconciliator()
        recon.fit(self.pred)
        self._assert_reconciliation(recon)

    def test_mint(self):
        # ols
        recon = MinTReconciliator("ols")
        recon.fit(self.series)
        self._assert_reconciliation(recon)

        # wls_struct
        recon = MinTReconciliator("wls_struct")
        recon.fit(self.series)
        self._assert_reconciliation(recon)

        # wls_var
        recon = MinTReconciliator("wls_var")
        recon.fit(self.residuals)
        self._assert_reconciliation(recon)

        # mint_cov
        recon = MinTReconciliator("mint_cov")
        recon.fit(self.residuals)
        self._assert_reconciliation(recon)

        # wls_val
        recon = MinTReconciliator("wls_val")
        recon.fit(self.series)
        self._assert_reconciliation(recon)

    def test_summation_matrix(self):
        np.testing.assert_equal(
            _get_summation_matrix(self.series_complex),
            np.array([
                [1, 1, 1, 1],
                [1, 1, 0, 0],
                [0, 0, 1, 1],
                [1, 0, 1, 0],
                [0, 1, 0, 1],
                [1, 0, 0, 0],
                [0, 1, 0, 0],
                [0, 0, 1, 0],
                [0, 0, 0, 1],
            ]),
        )

    def test_hierarchy_preserved_after_predict(self):
        self.assertEqual(self.pred.hierarchy, self.series.hierarchy)

    def test_more_intricate_hierarchy(self):
        recon = BottomUpReconciliator()
        self._assert_reconciliation_complex(recon)

        recon = TopDownReconciliator()
        recon.fit(self.series_complex)
        self._assert_reconciliation_complex(recon)

        recon = MinTReconciliator("ols")
        recon.fit(self.series_complex)
        self._assert_reconciliation_complex(recon)

        recon = MinTReconciliator("wls_struct")
        recon.fit(self.series_complex)
        self._assert_reconciliation_complex(recon)

        recon = MinTReconciliator("wls_val")
        recon.fit(self.series_complex)
        self._assert_reconciliation_complex(recon)
コード例 #6
0
    def test_concatenate_dim_component(self):
        """
        test concatenation with static covariates along component dimension (axis=1)
        Along component dimension, we concatenate/transfer the static covariates of the series only if one of
        below cases applies:
        1)  concatenate when for each series the number of static cov components is equal to the number of
            components in the series. The static variable names (columns in series.static_covariates) must be
            identical across all series
        2)  if only the first series contains static covariates transfer only those
        3)  if `ignore_static_covarites=True`, case 1) is ignored and only the static covariates of the first
            series are transferred
        """
        ts_uni = linear_timeseries(length=10)
        ts_multi = ts_uni.stack(ts_uni)

        static_covs_uni1 = pd.DataFrame([[0, 1]], columns=["st1",
                                                           "st2"]).astype(int)
        static_covs_uni2 = pd.DataFrame([[3, 4]], columns=["st3",
                                                           "st4"]).astype(int)
        static_covs_uni3 = pd.DataFrame([[2, 3, 4]],
                                        columns=["st1", "st2",
                                                 "st3"]).astype(int)

        static_covs_multi = pd.DataFrame([[0, 0], [1, 1]],
                                         columns=["st1", "st2"]).astype(int)

        ts_uni_static_uni1 = ts_uni.with_static_covariates(static_covs_uni1)
        ts_uni_static_uni2 = ts_uni.with_static_covariates(static_covs_uni2)
        ts_uni_static_uni3 = ts_uni.with_static_covariates(static_covs_uni3)

        ts_multi_static_uni1 = ts_multi.with_static_covariates(
            static_covs_uni1)
        ts_multi_static_multi = ts_multi.with_static_covariates(
            static_covs_multi)

        # concatenation without covariates
        ts_concat = concatenate([ts_uni, ts_uni], axis=1)
        assert ts_concat.static_covariates is None

        # concatenation along component dimension results in multi component static covariates
        ts_concat = concatenate([ts_uni_static_uni1, ts_uni_static_uni1],
                                axis=1)
        assert ts_concat.static_covariates.shape == (2, 2)
        assert ts_concat.components.equals(ts_concat.static_covariates.index)
        np.testing.assert_almost_equal(
            ts_concat.static_covariates_values(copy=False),
            pd.concat([static_covs_uni1] * 2, axis=0).values,
        )

        # concatenation with inconsistent static variable names should fail ...
        with pytest.raises(ValueError):
            _ = concatenate([ts_uni_static_uni1, ts_uni_static_uni2], axis=1)

        # ... by ignoring the static covariates, it should work and take only the covariates of the first series
        ts_concat = concatenate(
            [ts_uni_static_uni1, ts_uni_static_uni2],
            axis=1,
            ignore_static_covariates=True,
        )
        assert ts_concat.static_covariates.shape == (1, 2)
        assert ts_concat.static_covariates.index.equals(
            pd.Index([DEFAULT_GLOBAL_STATIC_COV_NAME]))
        np.testing.assert_almost_equal(
            ts_concat.static_covariates_values(copy=False),
            ts_uni_static_uni1.static_covariates_values(copy=False),
        )

        # concatenation with inconsistent number of static covariates should fail ...
        with pytest.raises(ValueError):
            _ = concatenate([ts_uni_static_uni1, ts_uni_static_uni3], axis=1)

        # concatenation will only work if for each series the number of static cov components is equal to the
        # number of components in the series
        with pytest.raises(ValueError):
            _ = concatenate([ts_uni_static_uni1, ts_multi_static_uni1], axis=1)

        ts_concat = concatenate([ts_uni_static_uni1, ts_multi_static_multi],
                                axis=1)
        assert ts_concat.static_covariates.shape == (ts_concat.n_components, 2)
        assert ts_concat.components.equals(ts_concat.static_covariates.index)
        np.testing.assert_almost_equal(
            ts_concat.static_covariates_values(copy=False),
            pd.concat([static_covs_uni1, static_covs_multi], axis=0),
        )