def __init__( self, freq: str, prediction_length: int, method_name: str = "ets", period: int = None, trunc_length: Optional[int] = None, params: Optional[Dict] = None, ) -> None: super().__init__(freq=freq, prediction_length=prediction_length) try: from rpy2 import robjects, rinterface import rpy2.robjects.packages as rpackages from rpy2.rinterface import RRuntimeError except ImportError as e: raise ImportError(str(e) + USAGE_MESSAGE) from e self._robjects = robjects self._rinterface = rinterface self._rinterface.initr() self._rpackages = rpackages this_dir = os.path.dirname(os.path.realpath(__file__)) this_dir = this_dir.replace("\\", "/") # for windows r_files = [ n[:-2] for n in os.listdir(f"{this_dir}/R/") if n[-2:] == ".R" ] for n in r_files: try: path = Path(this_dir, "R", f"{n}.R") robjects.r(f'source("{path}")'.replace("\\", "\\\\")) except RRuntimeError as er: raise RRuntimeError(str(er) + USAGE_MESSAGE) from er supported_methods = ["ets", "arima", "tbats", "croston", "mlp"] assert ( method_name in supported_methods ), f"method {method_name} is not supported please use one of {supported_methods}" self.method_name = method_name self._stats_pkg = rpackages.importr("stats") self._r_method = robjects.r[method_name] self.prediction_length = prediction_length self.freq = freq self.period = period if period is not None else get_seasonality(freq) self.trunc_length = trunc_length self.params = { "prediction_length": self.prediction_length, "output_types": ["samples"], "frequency": self.period, } if params is not None: self.params.update(params)
def __init__( self, freq: str, prediction_length: int, method_name: str = "ets", period: int = None, num_eval_samples: int = 100, trunc_length: Optional[int] = None, params: Optional[Dict] = None, ) -> None: try: from rpy2 import robjects, rinterface import rpy2.robjects.packages as rpackages from rpy2.rinterface import RRuntimeError except ImportError as e: raise ImportError(str(e) + USAGE_MESSAGE) from e self._robjects = robjects self._rinterface = rinterface self._rinterface.initr() self._rpackages = rpackages this_dir = os.path.dirname(os.path.realpath(__file__)) r_files = [ n[:-2] for n in os.listdir(f"{this_dir}/R/") if n[-2:] == ".R" ] for n in r_files: try: robjects.r(f'source("{this_dir}/R/{n}.R")') except RRuntimeError as er: raise RRuntimeError(str(er) + USAGE_MESSAGE) from er supported_methods = ["ets", "arima", "tbats", "croston", "mlp"] assert ( method_name in supported_methods ), f"method {method_name} is not supported please use one of {supported_methods}" self.method_name = method_name self._stats_pkg = rpackages.importr('stats') self._r_method = robjects.r[method_name] self.prediction_length = prediction_length self.freq = freq self.period = period if period is not None else get_seasonality(freq) self.num_samples = num_eval_samples self.trunc_length = trunc_length self.params = { 'prediction_length': self.prediction_length, 'output_types': ['samples'], 'num_samples': self.num_samples, 'frequency': self.period, } if params is not None: self.params.update(params)
def naive_2( past_ts_data: np.ndarray, prediction_length: int, freq: Optional[str] = None, season_length: Optional[int] = None, ) -> np.ndarray: """ Make seasonality adjusted time series prediction. If specified, `season_length` takes precedence. As described here: https://www.m4.unic.ac.cy/wp-content/uploads/2018/03/M4-Competitors-Guide.pdf Code based on: https://github.com/Mcompetitions/M4-methods/blob/master/Benchmarks%20and%20Evaluation.R """ assert freq is not None or season_length is not None, ( "Either the frequency or season length of the time series " "has to be specified. " ) season_length = ( season_length if season_length is not None else get_seasonality(freq) ) has_seasonality = False if season_length > 1: has_seasonality = seasonality_test(past_ts_data, season_length) # it has seasonality, then calculate the multiplicative seasonal component if has_seasonality: # TODO: think about maybe only using past_ts_data[- max(5*season_length, 2*prediction_length):] for speedup seasonal_decomposition = sm.tsa.seasonal_decompose( x=past_ts_data, period=season_length, model="multiplicative" ).seasonal seasonality_normed_context = past_ts_data / seasonal_decomposition last_period = seasonal_decomposition[-season_length:] num_required_periods = (prediction_length // len(last_period)) + 1 multiplicative_seasonal_component = np.tile( last_period, num_required_periods )[:prediction_length] else: seasonality_normed_context = past_ts_data multiplicative_seasonal_component = np.ones( prediction_length ) # i.e. no seasonality component # calculate naive forecast: (last value prediction_length times) naive_forecast = ( np.ones(prediction_length) * seasonality_normed_context[-1] ) forecast = np.mean(naive_forecast) * multiplicative_seasonal_component return forecast
def __init__(self, loss_function: str, freq: str, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.loss_function = loss_function self.freq = freq # Covert frequency string like "2H" to whats called the periodicity m. # E.g. 12 in case of "2H" because of 12 times two hours in a day. self.periodicity = get_seasonality(self.freq) if self.loss_function == "MASE": assert ( self.periodicity < self.context_length + self.prediction_length ), ("If the 'periodicity' of your data is less than 'context_length' + 'prediction_length' " "the seasonal_error cannot be calculated and thus 'MASE' cannot be used for optimization." )
def __init__( self, freq: str, prediction_length: int, season_length: Optional[int] = None, ) -> None: super().__init__(prediction_length, freq) assert ( season_length is None or season_length > 0), "The value of `season_length` should be > 0" self.freq = freq self.prediction_length = prediction_length self.season_length = (season_length if season_length is not None else get_seasonality(freq))
def test_get_seasonality(freq, expected_seasonality): assert get_seasonality(freq) == expected_seasonality