Esempio n. 1
0
def _reconcile_from_S_and_G(
    series: TimeSeries, S: np.ndarray, G: np.ndarray
) -> TimeSeries:
    """
    Returns the TimeSeries linearly reconciled from the projection matrix G and the summation matrix S.
    """
    y_hat = series.all_values(copy=False)
    reconciled_values = S @ G @ y_hat  # (n, m) * (m, n) * (time, n, samples)
    return series.with_values(reconciled_values)
Esempio n. 2
0
    def ts_inverse_transform(series: TimeSeries, transformer, *args,
                             **kwargs) -> TimeSeries:
        component_mask = kwargs.get("component_mask", None)

        tr_out = transformer.inverse_transform(
            Scaler._reshape_in(series, component_mask=component_mask))
        inv_transformed_vals = Scaler._reshape_out(
            series, tr_out, component_mask=component_mask)

        return series.with_values(inv_transformed_vals)
Esempio n. 3
0
    def ts_inverse_transform(series: TimeSeries,
                             lmbda: Union[Sequence[float],
                                          pd.core.series.Series],
                             **kwargs) -> TimeSeries:
        component_mask = kwargs.get("component_mask", None)

        vals = BoxCox._reshape_in(series, component_mask=component_mask)
        inv_transformed_vals = np.stack(
            [inv_boxcox(vals[:, i], lmbda[i]) for i in range(series.width)],
            axis=1)
        return series.with_values(
            BoxCox._reshape_out(series,
                                inv_transformed_vals,
                                component_mask=component_mask))
Esempio n. 4
0
    def filter(self, series: TimeSeries, num_samples: int = 1) -> TimeSeries:
        """
        Fits the Gaussian Process on the observations and returns samples from the Gaussian Process,
        or its mean values if `num_samples` is set to 1.

        Parameters
        ----------
        series
            The series of observations used to infer the values according to the specified Gaussian Process.
            This must be a deterministic series (containing one sample).
        num_samples: int, default: 1
            Number of times a prediction is sampled from the Gaussian Process. If set to 1,
            the mean values will be returned instead.

        Returns
        -------
        TimeSeries
            A stochastic ``TimeSeries`` sampled from the Gaussian Process, or its mean
            if `num_samples` is set to 1.
        """
        super().filter(series)

        values = series.values(copy=False)
        if series.has_datetime_index:
            times = np.arange(series.n_timesteps).reshape(-1, 1)
        else:
            times = series.time_index.values.reshape(-1, 1)

        not_nan_mask = np.all(~np.isnan(values), axis=1)

        self.model.fit(times[not_nan_mask, :], values[not_nan_mask, :])

        if num_samples == 1:
            filtered_values = self.model.predict(times)
        else:
            filtered_values = self.model.sample_y(times, n_samples=num_samples)

        filtered_values = filtered_values.reshape(len(times), -1, num_samples)

        return series.with_values(filtered_values)
Esempio n. 5
0
    def filter(
        self,
        series: TimeSeries,
        covariates: Optional[TimeSeries] = None,
        num_samples: int = 1,
    ) -> TimeSeries:
        """
        Sequentially applies the Kalman filter on the provided series of observations.

        Parameters
        ----------
        series : TimeSeries
            The series of outputs (observations) used to infer the underlying outputs according to the specified Kalman
            process. This must be a deterministic series (containing one sample).
        covariates : Optional[TimeSeries]
            An optional series of inputs (control signal), necessary if the Kalman filter was initialized with
            covariates. This must be a deterministic series (containing one sample).
        num_samples : int, default: 1
            The number of samples to generate from the inferred distribution of the output z. If this is set to 1, the
            output is a `TimeSeries` containing a single sample using the mean of the distribution.

        Returns
        -------
        TimeSeries
            A (stochastic) `TimeSeries` of the inferred output z, of the same width as the input series.
        """
        super().filter(series)

        raise_if(
            self.kf is None,
            "The Kalman filter has not been fitted yet. Call `fit()` first "
            "or provide Kalman filter in constructor.",
        )

        raise_if_not(
            series.width == self.dim_y,
            "The provided TimeSeries dimensionality does not match "
            "the output dimensionality of the Kalman filter.",
        )

        raise_if(
            covariates is not None and not self._expect_covariates,
            "Covariates were provided, but the Kalman filter was not fitted with covariates.",
        )

        if self._expect_covariates:
            raise_if(
                covariates is None,
                "The Kalman filter was fitted with covariates, but these were not provided.",
            )

            raise_if_not(
                covariates.is_deterministic,
                "The covariates must be deterministic (observations).",
            )

            covariates = covariates.slice_intersect(series)
            raise_if_not(
                series.has_same_time_as(covariates),
                "The number of timesteps in the series and the covariates must match.",
            )

        kf = deepcopy(self.kf)

        y_values = series.values(copy=False)
        if self._expect_covariates:
            u_values = covariates.values(copy=False)

            # set control signal to 0 if it contains NaNs:
            u_values = np.nan_to_num(u_values, copy=True, nan=0.0)
        else:
            u_values = np.zeros((len(y_values), 0))

        # For each time step, we'll sample "n_samples" from a multivariate Gaussian
        # whose mean vector and covariance matrix come from the Kalman filter.
        sampled_outputs = np.zeros((len(y_values), self.dim_y, num_samples))

        for i in range(len(y_values)):
            y = y_values[i, :].reshape(-1, 1)
            u = u_values[i, :].reshape(-1, 1)

            if np.isnan(y).any():
                y = None

            kf.step(y, u)
            mean_vec = kf.y_filtereds[-1].reshape(self.dim_y, )

            if num_samples == 1:
                sampled_outputs[i, :, 0] = mean_vec
            else:
                # The measurement covariance matrix is given by the sum of the covariance matrix of the
                # state estimate (transformed by C) and the covariance matrix of the measurement noise.
                cov_matrix = (
                    kf.state_space.c @ kf.p_filtereds[-1] @ kf.state_space.c.T
                    + kf.r)
                sampled_outputs[i, :, :] = np.random.multivariate_normal(
                    mean_vec, cov_matrix, size=num_samples).T

        return series.with_values(sampled_outputs)