def fit(self, series: TimeSeries): super().fit(series) series._assert_univariate() series = self.training_series if self.version == "tsb": self.forecast_val = self.method( series.values(copy=False), h=1, future_xreg=None, alpha_d=self.alpha_d, alpha_p=self.alpha_p, ) elif self.version == "sba": try: self.forecast_val = self.method(series.values(copy=False), h=1, future_xreg=None) except errors.TypingError: raise_if( True, '"sba" version is not supported with this version of statsforecast.', ) else: self.forecast_val = self.method(series.values(copy=False), h=1, future_xreg=None) return self
def ts_inverse_transform(series: TimeSeries, transformer, *args, **kwargs) -> TimeSeries: return TimeSeries.from_times_and_values( times=series.time_index, values=transformer.inverse_transform(series.values().reshape( (-1, series.width))), fill_missing_dates=False)
def fit(self, series: TimeSeries): super().fit(series) series = self.training_series # if the model was initially created with `self.seasonal_periods=None`, make sure that # the model will try to automatically infer the index, otherwise it should use the # provided `seasonal_periods` value seasonal_periods_param = ( None if self.infer_seasonal_periods else self.seasonal_periods ) # set the seasonal periods paramter to a default value if it was not provided explicitly # and if it cannot be inferred due to the lack of a datetime index if self.seasonal_periods is None and series.has_range_index: seasonal_periods_param = 12 hw_model = hw.ExponentialSmoothing( series.values(), trend=self.trend if self.trend is None else self.trend.value, damped_trend=self.damped, seasonal=self.seasonal if self.seasonal is None else self.seasonal.value, seasonal_periods=seasonal_periods_param, freq=series.freq if series.has_datetime_index else None, dates=series.time_index if series.has_datetime_index else None, ) hw_results = hw_model.fit(**self.fit_kwargs) self.model = hw_results if self.infer_seasonal_periods: self.seasonal_periods = hw_model.seasonal_periods return self
def _fit(self, series: TimeSeries, future_covariates: Optional[TimeSeries] = None): super()._fit(series, future_covariates) series = self.training_series self.model.fit( series.values(), X=future_covariates.values() if future_covariates else None) return self
def fit(self, series: TimeSeries): super().fit(series) series = self.training_series if self.infer_seasonal_periods: seasonality = _seasonality_from_freq(series) self.kwargs["seasonal_periods"] = seasonality self.seasonal_periods = seasonality model = self._create_model() fitted_model = model.fit(series.values()) self.model = fitted_model return self
def find_peak_indices(series: TimeSeries, peak_params: PeakParams) -> Peaks: """List the timestamps at which channel activity peaks.""" peak_params = calculate_distance_wlen(series, peak_params) # pandas-vet thinks `series` is a pandas data structure with # ambiguous behavior for values() indices: np.ndarray properties: Mapping[str, np.array] indices, properties = sp.signal.find_peaks( series.values().flatten(), # noqa: PD011 distance=peak_params.distance, wlen=peak_params.wlen, height=series.mean(), ) return Peaks(indices, properties)
def fit(self, series: TimeSeries) -> 'Scaler': """ Fits this scaler to the provided time series data Parameters ---------- series The time series to fit the scaler on Returns ------- Fitted scaler (self) """ super().fit(series) self.transformer.fit(series.values().reshape((-1, series.width))) self.train_series = series return self
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 : TimeSeries 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, instead the mean values will be returned. Returns ------- TimeSeries A stochastic `TimeSeries` sampled from the Gaussian Process, or its mean if `num_samples` is set to 1. """ raise_if_not(series.is_deterministic, 'The input series for the Gaussian Process filter must be ' 'deterministic (observations).') 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) return TimeSeries.from_times_and_values(series.time_index, filtered_values)
def inverse_transform(self, series: TimeSeries, *args, **kwargs) -> TimeSeries: """ Performs the inverse transformation on a time series Parameters ---------- series The time series to inverse transform Returns ------- TimeSeries The inverse transform """ super().inverse_transform(series, *args, **kwargs) return TimeSeries.from_times_and_values( series.time_index(), self.transformer.inverse_transform(series.values().reshape( (-1, series.width))), series.freq())
def transform(self, series: TimeSeries, *args, **kwargs) -> TimeSeries: """ Returns a new time series, transformed with this (fitted) scaler. This does not handle series with confidence intervals - the intervals are discarded. Parameters ---------- series The time series to transform Returns ------- TimeSeries A new time series, transformed with this (fitted) scaler. """ super().transform(series, *args, **kwargs) return TimeSeries.from_times_and_values( series.time_index(), self.transformer.transform(series.values().reshape( (-1, series.width))), series.freq())
def select_best_model( ts: TimeSeries, thetas: Optional[List[int]] = None, m: Optional[int] = None, normalization: bool = True, n_jobs: int = 1, ) -> "FourTheta": """ Performs a grid search over all hyper parameters to select the best model, using the fitted values on the training series `ts`. Uses 'ForecastingModel.gridsearch' with 'use_fitted_values=True' and 'metric=metrics.mae`. Parameters ---------- ts The TimeSeries on which the model will be tested. thetas A list of thetas to loop over. Defaults to [1, 2, 3]. m Optionally, the season used to decompose the time series. normalization If `True`, the data is normalized so that the mean is 1. Defaults to `True`. n_jobs The number of jobs to run in parallel. Parallel jobs are created only when there are two or more theta values to be evaluated. Each job will instantiate, train, and evaluate a different instance of the model. Defaults to `1` (sequential). Setting the parameter to `-1` means using all the available cores. Returns ------- FourTheta The best performing model on the time series. """ # Only import if needed from darts.metrics import mae if thetas is None: thetas = [1, 2, 3] if (ts.values(copy=False) <= 0).any(): drift_mode = [TrendMode.LINEAR] model_mode = [ModelMode.ADDITIVE] season_mode = [SeasonalityMode.ADDITIVE] logger.warning( "The given TimeSeries has negative values. The method will only test " "linear trend and additive modes." ) else: season_mode = [season for season in SeasonalityMode] model_mode = [model for model in ModelMode] drift_mode = [trend for trend in TrendMode] theta = FourTheta.gridsearch( { "theta": thetas, "model_mode": model_mode, "season_mode": season_mode, "trend_mode": drift_mode, "seasonality_period": [m], "normalization": [normalization], }, ts, use_fitted_values=True, metric=mae, n_jobs=n_jobs, ) return theta
def ts_fit(series: TimeSeries, transformer, *args, **kwargs) -> Any: # fit_parameter will receive the transformer object instance scaler = transformer.fit(series.values().reshape((-1, series.width))) return scaler
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)
def ts_inverse_transform(series: TimeSeries, transformer, *args, **kwargs) -> TimeSeries: return TimeSeries.from_times_and_values( series.time_index(), transformer.inverse_transform(series.values().reshape( (-1, series.width))), series.freq())
def ts_transform(series: TimeSeries, transformer) -> TimeSeries: return TimeSeries.from_times_and_values( series.time_index(), transformer.transform(series.values().reshape((-1, series.width))), series.freq())