sktime.transformations.series.theta 源代码
# !/usr/bin/env python3 -u
# copyright: sktime developers, BSD-3-Clause License (see LICENSE file).
"""Implements Theta-lines transformation for use with Theta forecasting."""
__author__ = ["GuzalBulatova", "mloning"]
__all__ = ["ThetaLinesTransformer"]
import numpy as np
import pandas as pd
from sktime.forecasting.base import ForecastingHorizon
from sktime.forecasting.trend import PolynomialTrendForecaster
from sktime.transformations.base import BaseTransformer
[文档]class ThetaLinesTransformer(BaseTransformer):
"""Decompose the original data into two or more Theta-lines.
Implementation of decomposition for Theta-method [1]_ as described in [2]_.
Overview: Input :term:`univariate series <Univariate time series>` of length
"n" and ThetaLinesTransformer modifies the local curvature of the time series
using Theta-coefficient values passed through the parameter ``theta``.
Each Theta-coefficient is applied directly to the second differences of the input
series. The resulting transformed series (Theta-lines) are returned as a
pd.DataFrame of shape ``len(input series) * len(theta)``.
Parameters
----------
theta : sequence of float, default=(0,2)
Theta-coefficients to use in transformation.
Notes
-----
Depending on the value of the Theta-coefficient, Theta-lines either augment the
long-term trend (0 < Theta < 1) or the the short-term behaviour (Theta > 1).
Special cases:
- Theta == 0 : deflates input data to linear trend
- Theta == 1 : returns data unchanged
- Theta < 0 : transforms time series and mirrors it along the linear trend.
References
----------
.. [1] V.Assimakopoulos et al., "The theta model: a decomposition approach
to forecasting", International Journal of Forecasting, vol. 16, pp. 521-530,
2000.
.. [2] E.Spiliotis et al., "Generalizing the Theta method for
automatic forecasting ", European Journal of Operational
Research, vol. 284, pp. 550-558, 2020.
Examples
--------
>>> from sktime.transformations.series.theta import ThetaLinesTransformer
>>> from sktime.datasets import load_airline
>>> y = load_airline()
>>> transformer = ThetaLinesTransformer([0, 0.25, 0.5, 0.75])
>>> y_thetas = transformer.fit_transform(y)
"""
_tags = {
# packaging info
# --------------
"authors": ["GuzalBulatova", "mloning"],
# estimator type
# --------------
"scitype:transform-input": "Series",
# what is the scitype of X: Series, or Panel
"scitype:transform-output": "Series",
# what scitype is returned: Primitives, Series, Panel
"scitype:instancewise": True, # is this an instance-wise transform?
"X_inner_mtype": ["pd.DataFrame", "pd.Series"],
# which mtypes do _fit/_predict support for X?
"y_inner_mtype": "None", # which mtypes do _fit/_predict support for y?
"transform-returns-same-time-index": True,
"univariate-only": True,
"fit_is_empty": True,
}
def __init__(self, theta=(0, 2)):
self.theta = theta
super().__init__()
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
"""
theta = _check_theta(self.theta)
forecaster = PolynomialTrendForecaster()
forecaster.fit(y=X)
fh = ForecastingHorizon(X.index, is_relative=False)
trend = forecaster.predict(fh=fh)
theta_lines = np.zeros((X.shape[0], len(theta)))
for i, theta_i in enumerate(theta):
theta_lines[:, i] = _theta_transform(X, trend, theta_i)
if isinstance(self.theta, (float, int)):
return pd.Series(theta_lines.flatten(), index=X.index)
else:
return pd.DataFrame(theta_lines, columns=self.theta, index=X.index)
def _theta_transform(Z, trend, theta):
# obtain one Theta-line
theta_line = Z * theta + (1 - theta) * trend
theta_line = theta_line.values.flatten()
return theta_line
def _check_theta(theta):
valid_theta_types = (list, int, float, tuple)
if not isinstance(theta, valid_theta_types):
raise ValueError(f"invalid input, please use one of {valid_theta_types}")
if isinstance(theta, (int, float)):
theta = [theta]
if isinstance(theta, tuple):
theta = list(theta)
return theta