def transform(self, Z, X=None): """Transform data. Parameters ---------- Z : pd.Series Series to transform. X : pd.DataFrame, optional (default=None) Exogenous data used in transformation. Returns ------- theta_lines: ndarray or pd.DataFrame Transformed series: single Theta-line or a pd.DataFrame of shape: len(Z)*len(self.theta). """ self.check_is_fitted() z = check_series(Z, enforce_univariate=True) theta = _check_theta(self.theta) forecaster = PolynomialTrendForecaster() forecaster.fit(z) fh = ForecastingHorizon(z.index, is_relative=False) trend = forecaster.predict(fh) theta_lines = np.zeros((z.shape[0], len(theta))) for i, theta in enumerate(theta): theta_lines[:, i] = _theta_transform(z, trend, theta) if isinstance(self.theta, (float, int)): return pd.Series(theta_lines.flatten(), index=z.index) else: return pd.DataFrame(theta_lines, columns=self.theta, index=z.index)
def _transform(self, X, y=None): """Transform X and return a transformed version. private _transform containing the core logic, called from transform Parameters ---------- X : pd.Series or pd.DataFrame Data to be transformed y : ignored argument for interface compatibility Additional data, e.g., labels for transformation Returns ------- theta_lines: pd.Series or pd.DataFrame Transformed series pd.Series, with single Theta-line, if self.theta is float pd.DataFrame of shape: [len(X), len(self.theta)], if self.theta is tuple """ z = X theta = _check_theta(self.theta) forecaster = PolynomialTrendForecaster() forecaster.fit(z) fh = ForecastingHorizon(z.index, is_relative=False) trend = forecaster.predict(fh) theta_lines = np.zeros((z.shape[0], len(theta))) for i, theta in enumerate(theta): theta_lines[:, i] = _theta_transform(z, trend, theta) if isinstance(self.theta, (float, int)): return pd.Series(theta_lines.flatten(), index=z.index) else: return pd.DataFrame(theta_lines, columns=self.theta, index=z.index)
def check_trend(degree, with_intercept): """Helper function to check trend""" y = load_airline() f = PolynomialTrendForecaster(degree=degree, with_intercept=with_intercept) f.fit(y) a = f.regressor_.steps[-1][1].coef_[ ::-1] # intercept is added in reverse order b = compute_expected_coefs(y, degree, with_intercept) np.testing.assert_allclose(a, b)
def _test_trend(degree, with_intercept): """Helper function to check trend""" y = make_forecasting_problem() forecaster = PolynomialTrendForecaster(degree=degree, with_intercept=with_intercept) forecaster.fit(y) # check coefficients # intercept is added in reverse order actual = forecaster.regressor_.steps[-1][1].coef_[::-1] expected = get_expected_polynomial_coefs(y, degree, with_intercept) np.testing.assert_allclose(actual, expected)
def test_constant_trend(): y = pd.Series(np.arange(30)) fh = -np.arange(30) # in-sample fh forecaster = PolynomialTrendForecaster(degree=1) y_pred = forecaster.fit(y).predict(fh) np.testing.assert_array_almost_equal(y, y_pred)
def transform(self, Z, X=None): """Transform data. Returns a transformed version of Z. Parameters ---------- Z : pd.Series Returns ------- z : pd.Series Transformed time series. """ self.check_is_fitted() self._check_method() z = check_series(Z, enforce_univariate=True) # replace missing_values with np.nan if self.missing_values: z = z.replace(to_replace=self.missing_values, value=np.nan) if self.method == "random": z = z.apply(lambda x: self._get_random(z) if np.isnan(x) else x) elif self.method == "constant": z = z.fillna(value=self.value) elif self.method in ["backfill", "bfill", "pad", "ffill"]: z = z.fillna(method=self.method) elif self.method in ["drift", "forecaster"]: if self.method == "forecaster": forecaster = self.forecaster else: forecaster = PolynomialTrendForecaster(degree=1) # in-sample forecasting horizon fh_ins = -np.arange(len(z)) # fill NaN before fitting with ffill and backfill (heuristic) z_pred = forecaster.fit( z.fillna(method="ffill").fillna(method="backfill")).predict( fh=fh_ins) # fill with trend values z = z.fillna(value=z_pred) elif self.method == "mean": z = z.fillna(value=z.mean()) elif self.method == "median": z = z.fillna(value=z.median()) elif self.method in ["nearest", "linear"]: z = z.interpolate(method=self.method) else: raise ValueError(f"method {self.method} not available") return z
# In[86]: from sktime.forecasting.compose import TransformedTargetForecaster from sktime.transformers.single_series.detrend import Detrender, Deseasonalizer from sktime.forecasting.trend import PolynomialTrendForecaster # ### Detrending # In[126]: model = PolynomialTrendForecaster(degree=1) transformer = Detrender(model) yt = transformer.fit_transform(train) trendline = model.fit(train).predict(fh=-np.arange(len(train))) plot_ys(train, trendline, yt, labels=['series', 'trend', 'detrended']) # ### Pipelining # In[130]: forecaster = TransformedTargetForecaster([ ("deseasonalise", Deseasonalizer(model="multiplicative", sp=12)), ("detrend", Detrender(forecaster=PolynomialTrendForecaster(degree=1))), ("forecast", ReducedRegressionForecaster(regressor=regressor, window_length=12, strategy="recursive")) ])
def transform(self, Z, X=None): """Transform data. Returns a transformed version of Z. Parameters ---------- Z : pd.Series, pd.DataFrame Returns ------- Z : pd.Series, pd.DataFrame Transformed time series(es). """ self.check_is_fitted() self._check_method() Z = check_series(Z) # replace missing_values with np.nan if self.missing_values: Z = Z.replace(to_replace=self.missing_values, value=np.nan) if self.method == "random": if isinstance(Z, pd.DataFrame): for col in Z: Z[col] = Z[col].apply(lambda i: self._get_random(Z[col]) if np.isnan(i) else i) else: Z = Z.apply(lambda i: self._get_random(Z) if np.isnan(i) else i) elif self.method == "constant": Z = Z.fillna(value=self.value) elif self.method in ["backfill", "bfill", "pad", "ffill"]: Z = Z.fillna(method=self.method) elif self.method in ["drift", "forecaster"]: if self.method == "forecaster": forecaster = self.forecaster else: forecaster = PolynomialTrendForecaster(degree=1) # in-sample forecasting horizon fh_ins = -np.arange(len(Z)) # fill NaN before fitting with ffill and backfill (heuristic) Z = Z.fillna(method="ffill").fillna(method="backfill") # multivariate if isinstance(Z, pd.DataFrame): for col in Z: forecaster.fit(y=Z[col]) Z_pred = forecaster.predict(fh=fh_ins) Z[col] = Z[col].fillna(value=Z_pred) # univariate else: forecaster.fit(y=Z) Z_pred = forecaster.predict(fh=fh_ins) Z = Z.fillna(value=Z_pred) elif self.method == "mean": Z = Z.fillna(value=Z.mean()) elif self.method == "median": Z = Z.fillna(value=Z.median()) elif self.method in ["nearest", "linear"]: Z = Z.interpolate(method=self.method) else: raise ValueError(f"method {self.method} not available") # fill first/last elements of series, # as some methods (e.g. "linear") cant impute those Z = Z.fillna(method="ffill").fillna(method="backfill") return Z