def _run_holts_trend_corrected_exponential_smoothing( self, individual: tuple): f = Forecast(self.__orders, self.__average_order) holts_trend_corrected_smoothing = [] demand = [{ 't': index, 'demand': order } for index, order in enumerate(self.__orders, 1)] stats = LinearRegression(demand) log_stats = stats.least_squared_error(slice_end=6) for sm_lvl in individual: p = [ i for i in f.holts_trend_corrected_exponential_smoothing( alpha=sm_lvl[0], gamma=sm_lvl[1], intercept=log_stats.get('intercept'), slope=log_stats.get('slope')) ] # print(p) holts_trend_corrected_smoothing.append(p) appraised_individual = {} for smoothing_level in individual: sum_squared_error = f.sum_squared_errors_indi_htces( squared_error=holts_trend_corrected_smoothing, alpha=smoothing_level[0], gamma=smoothing_level[1]) standard_error = f.standard_error(sum_squared_error, len(self.__orders), smoothing_level) appraised_individual.update({smoothing_level: standard_error}) # print('The standard error as a trait has been calculated {}'.format(appraised_individual)) return appraised_individual
def test_htces(self): forecast_demand = Forecast(self.__orders_ex) ses_forecast = [ i for i in forecast_demand.simple_exponential_smoothing( *(self.__smoothing_level_constant, )) ] sum_squared_error = forecast_demand.sum_squared_errors( ses_forecast, self.__smoothing_level_constant) standard_error = forecast_demand.standard_error( sum_squared_error, len(self.__orders_ex), self.__smoothing_level_constant) total_orders = 0 for order in self.__orders_ex[:self.__initial_estimate_period]: total_orders += order avg_orders = total_orders / self.__initial_estimate_period evo_mod = OptimiseSmoothingLevelGeneticAlgorithm( orders=self.__orders_ex, average_order=avg_orders, smoothing_level=self.__smoothing_level_constant, population_size=10, standard_error=standard_error, recombination_type='two_point') ses_evo_forecast = evo_mod.simple_exponential_smoothing_evo( smoothing_level_constant=self.__smoothing_level_constant, initial_estimate_period=self.__initial_estimate_period) self.assertEqual(7, len(ses_evo_forecast))
def _ses_forecast(smoothing_level_constant: float, forecast_demand: Forecast, forecast_length: int, orders_length: int) -> dict: """ Private function for executing the simple exponential smoothing forecast. """ forecast_breakdown = [ i for i in forecast_demand.simple_exponential_smoothing( smoothing_level_constant) ] ape = LinearRegression(forecast_breakdown) mape = forecast_demand.mean_aboslute_percentage_error_opt( forecast_breakdown) stats = ape.least_squared_error() simple_forecast = forecast_demand.simple_exponential_smoothing_forecast( forecast=forecast_breakdown, forecast_length=forecast_length) sum_squared_error = forecast_demand.sum_squared_errors( simple_forecast, smoothing_level_constant) standard_error = forecast_demand.standard_error(sum_squared_error, orders_length, smoothing_level_constant) regression_line = _regr_ln(stats=stats) log.log( logging.WARNING, "A STANDARD simple exponential smoothing forecast has been completed.") return { 'forecast_breakdown': forecast_breakdown, 'mape': mape, 'statistics': stats, 'forecast': simple_forecast, 'alpha': smoothing_level_constant, 'standard_error': standard_error, 'regression': [i for i in regression_line.get('regression')] }
def test_mean_absolute_deviation(self): forecast = Forecast(self.__orders) forecast.weighted_moving_average_forecast(weights=self.__weights, average_period=3, forecast_length=9, base_forecast=True, start_position=3) k = Forecast(self.__orders) k.moving_average_forecast(forecast_length=9, base_forecast=True, start_position=3, average_period=3) result_array = k.mean_absolute_deviation(forecast.weighted_moving_average) result_array2 = forecast.mean_absolute_deviation(k.moving_average) self.assertNotEqual(result_array, result_array2)
def test_holts_trend_corrected_exponential_smoothing_len(self): total_orders = 0 for order in self.__orders_ex[:12]: total_orders += order avg_orders = total_orders / 12 f = Forecast(self.__orders_ex) p = [i for i in f.holts_trend_corrected_exponential_smoothing(0.5, 0.5, 155.88, 0.8369)] self.assertEqual(len(p), 36)
def test_simple_exponential_smoothing(self): total_orders = 0 for order in self.__orders_ex[:12]: total_orders += order avg_orders = total_orders / 12 f = Forecast(self.__orders_ex, avg_orders) alpha = [0.2, 0.3, 0.4, 0.5, 0.6] s = [i for i in f.simple_exponential_smoothing(*alpha)] sum_squared_error = f.sum_squared_errors(s, 0.5) self.assertEqual(28447.178137569197, sum_squared_error[0.5])
def test_standard_error(self): total_orders = 0 for order in self.__orders_ex[:12]: total_orders += order avg_orders = total_orders / 12 f = Forecast(self.__orders_ex, avg_orders) alpha = [0.2, 0.3, 0.4, 0.5, 0.6] s = [i for i in f.simple_exponential_smoothing(*alpha)] sum_squared_error = f.sum_squared_errors(s, 0.5) standard_error = f.standard_error(sum_squared_error, len(self.__orders_ex), 0.5) self.assertEqual(29, round(standard_error))
def test_holts_trend_corrected_exponential_smoothing_forecast(self): total_orders = 0 for order in self.__orders_ex[:12]: total_orders += order f = Forecast(self.__orders_ex) p = [i for i in f.holts_trend_corrected_exponential_smoothing(0.5, 0.5, 155.88, 0.8369)] holts_forecast = f.holts_trend_corrected_forecast(forecast=p, forecast_length=4) self.assertEqual(round(holts_forecast[0]), 281) self.assertEqual(round(holts_forecast[1]), 307) self.assertEqual(round(holts_forecast[2]), 334) self.assertEqual(round(holts_forecast[3]), 361)
def test_mean_absolute_deviation_(self): orders1 = [1, 3, 5, 67, 4, 65, 44, 50, 48, 24, 34, 20] orders2 = [1, 3, 5, 67, 4, 65, 44, 50, 48, 24, 34, 20] weights = [.5, .3, .2] forecast = Forecast(orders1) forecast.weighted_moving_average_forecast(weights=weights, average_period=3, forecast_length=9, start_position=3) # d.moving_average(forecast_length=3, base_forecast=True, start_position=3) # print(d.moving_average_forecast) k = Forecast(orders2) k.moving_average_forecast(forecast_length=9, start_position=3, average_period=3) result_array = k.mean_absolute_deviation(forecast.weighted_moving_average) result_array2 = forecast.mean_absolute_deviation(k.moving_average) self.assertEqual(result_array, result_array2)
def _run_exponential_smoothing_forecast(self, individual: tuple) -> dict: f = Forecast(self.__orders, self.__average_order) simple_expo_smoothing = [] for sm_lvl in individual: p = [i for i in f.simple_exponential_smoothing(sm_lvl)] # print(p) simple_expo_smoothing.append(p) appraised_individual = {} for smoothing_level in individual: sum_squared_error = f.sum_squared_errors_indi( simple_expo_smoothing, smoothing_level) standard_error = f.standard_error(sum_squared_error, len(self.__orders), smoothing_level) appraised_individual.update({smoothing_level: standard_error}) # print('The standard error as a trait has been calculated {}'.format(appraised_individual)) return appraised_individual
def test_optimise_smoothing_level_genetic_algorithm(self): total_orders = 0 for order in self.__orders_ex[:12]: total_orders += order avg_orders = total_orders / 12 f = Forecast(self.__orders_ex, avg_orders) alpha = [0.2, 0.3, 0.4, 0.5, 0.6] s = [i for i in f.simple_exponential_smoothing(*alpha)] sum_squared_error = f.sum_squared_errors(s, 0.5) standard_error = f.standard_error(sum_squared_error, len(self.__orders_ex), 0.5, 2) evo_mod = OptimiseSmoothingLevelGeneticAlgorithm(orders=self.__orders_ex, average_order=avg_orders, smoothing_level=0.5, population_size=10, standard_error=standard_error, recombination_type='single_point') pop = evo_mod.initial_population() self.assertGreaterEqual(len(pop), 2) self.assertNotAlmostEqual(pop[0], 20.72, places=3) self.assertNotAlmostEqual(pop[1], 0.73, places=3)
def simple_exponential_smoothing_forecast( demand: list, smoothing_level_constant: float = 0.5, optimise: bool = True, forecast_length: int = 5, initial_estimate_period: int = 6, **kwargs) -> dict: """ Performs a simple exponential smoothing forecast on historical demand. Args: forecast_length (int): Number of periods to extend the forecast. demand (list): Original historical demand. smoothing_level_constant (float): Alpha value initial_estimate_period (int): Number of period to use to derive an average for the initial estimate. **ds (pd.DataFrame): Data frame with raw data. **optimise (bool) Optimisation flag for exponential smoothing forecast. Returns: dict: Simple exponential forecast Examples: >>> from supplychainpy.model_demand import simple_exponential_smoothing_forecast >>> orders = [165, 171, 147, 143, 164, 160, 152, 150, 159, 169, 173, 203, 169, 166, 162, 147, 188, 161, 162, ... 169, 185, 188, 200, 229, 189, 218, 185, 199, 210, 193, 211, 208, 216, 218, 264, 304] >>> ses = simple_exponential_smoothing_forecast(demand=orders, alpha=0.5, forecast_length=6, initial_period=18) """ try: ds = kwargs.get('ds', 'UNKNOWN') if ds is not UNKNOWN: orders = list(kwargs.get('ds', "UNKNOWN")) else: orders = [int(i) for i in demand] forecast_demand = Forecast(orders) log.log(logging.INFO, "Started simple exponential smoothing") # optimise, population_size, genome_length, mutation_probability, recombination_types if optimise: log.log(logging.INFO, "Using solver version to find alpha.") ses_forecast = [ i for i in forecast_demand.simple_exponential_smoothing( *(smoothing_level_constant, )) ] sum_squared_error = forecast_demand.sum_squared_errors( ses_forecast, smoothing_level_constant) standard_error = forecast_demand.standard_error( sum_squared_error, len(orders), smoothing_level_constant) total_orders = 0 for order in orders[:initial_estimate_period]: total_orders += order avg_orders = total_orders // initial_estimate_period evo_mod = OptimiseSmoothingLevelGeneticAlgorithm( orders=orders, average_order=avg_orders, smoothing_level=smoothing_level_constant, population_size=10, standard_error=standard_error, recombination_type='single_point') ses_evo_forecast = evo_mod.simple_exponential_smoothing_evo( smoothing_level_constant=smoothing_level_constant, initial_estimate_period=initial_estimate_period) return ses_evo_forecast else: orders = [int(i) for i in demand] return _ses_forecast( smoothing_level_constant=smoothing_level_constant, forecast_demand=forecast_demand, forecast_length=forecast_length, orders_length=len(orders)) except TypeError as e: if demand is None: print( "Please supply a list of demand values. Use the keyword \'demand=\'\n{}" .format(e)) except OSError as e: print(e)
def test_weighted_moving_average_list_err(self): with self.assertRaises(expected_exception=ValueError): forecast = Forecast(self.__orders) forecast.weighted_moving_average_forecast(weights=self.__weights[:2], average_period=2, forecast_length=3)
def test_moving_average_value_err(self): with self.assertRaises(expected_exception=ValueError): d = Forecast(self.__orders) d.moving_average_forecast(forecast_length=6, base_forecast=True, start_position=1)
def simple_exponential_smoothing_forecast(demand: list = None, smoothing_level_constant: float = 0.5, forecast_length: int = 5, initial_estimate_period: int = 6, **kwargs) -> dict: """ Performs a simple exoponential smoothing forecast on Args: forecast_length (int): Number of periods to extend the forecast. demand (list): Original historical demand. smoothing_level_constant (float): Alpha value initial_estimate_period (int): Number of period to use to derive an average for the initial estimate. **ds (pd.DataFrame): Data frame with raw data. **optimise (bool) Optimisation flag for exponential smoothing forecast. Returns: dict: Simple exponential forecast Examples: >>> from supplychainpy.model_demand import simple_exponential_smoothing_forecast >>> orders = [165, 171, 147, 143, 164, 160, 152, 150, 159, 169, 173, 203, 169, 166, 162, 147, 188, 161, 162, ... 169, 185, 188, 200, 229, 189, 218, 185, 199, 210, 193, 211, 208, 216, 218, 264, 304] >>> ses = simple_exponential_smoothing_forecast(demand=orders, alpha=0.5, forecast_length=6, initial_period=18) """ ds = kwargs.get('ds', 'UNKNOWN') if ds is not UNKNOWN: orders = list(kwargs.get('ds', "UNKNOWN")) else: orders = [int(i) for i in demand] forecast_demand = Forecast(orders) # optimise, population_size, genome_length, mutation_probability, recombination_types if len(kwargs) != 0: optimise_flag = kwargs.get('optimise', "UNKNOWN") if optimise_flag is not UNKNOWN: ses_forecast = [i for i in forecast_demand.simple_exponential_smoothing(*(smoothing_level_constant,))] sum_squared_error = forecast_demand.sum_squared_errors(ses_forecast, smoothing_level_constant) standard_error = forecast_demand.standard_error(sum_squared_error, len(orders), smoothing_level_constant) total_orders = 0 for order in orders[:initial_estimate_period]: total_orders += order avg_orders = total_orders / initial_estimate_period evo_mod = OptimiseSmoothingLevelGeneticAlgorithm(orders=orders, average_order=avg_orders, smoothing_level=smoothing_level_constant, population_size=10, standard_error=standard_error, recombination_type='single_point') ses_evo_forecast = evo_mod.simple_exponential_smoothing_evo( smoothing_level_constant=smoothing_level_constant, initial_estimate_period=initial_estimate_period) return ses_evo_forecast else: return _ses_forecast(smoothing_level_constant=smoothing_level_constant, forecast_demand=forecast_demand, forecast_length=forecast_length) else: return _ses_forecast(smoothing_level_constant=smoothing_level_constant, forecast_demand=forecast_demand, forecast_length=forecast_length)
def holts_trend_corrected_exponential_smoothing_forecast( demand: list, alpha: float, gamma: float, forecast_length: int = 4, initial_period: int = 6, optimise: bool = True) -> dict: """ Performs a holt's trend corrected exponential smoothing forecast on known demand Args: demand (list): Original historical demand. alpha (float): smoothing constant gamma (float): forecast_length (int): initial_period (int): optimise (bool): Flag for using solver. Default is set to True. Returns: dict: Simple exponential forecast. """ if optimise: total_orders = 0 for order in demand[:initial_period]: total_orders += order avg_orders = total_orders // initial_period forecast_demand = Forecast(demand) processed_demand = [{ 't': index, 'demand': order } for index, order in enumerate(demand, 1)] stats = LinearRegression(processed_demand) log_stats = stats.least_squared_error(slice_end=6) htces_forecast = [ i for i in forecast_demand.holts_trend_corrected_exponential_smoothing( alpha=alpha, gamma=gamma, intercept=log_stats.get('intercept'), slope=log_stats.get('slope')) ] sum_squared_error = forecast_demand.sum_squared_errors_indi_htces( squared_error=[htces_forecast], alpha=alpha, gamma=gamma) standard_error = forecast_demand.standard_error( sum_squared_error, len(demand), (alpha, gamma), 2) evo_mod = OptimiseSmoothingLevelGeneticAlgorithm( orders=demand, average_order=avg_orders, population_size=10, standard_error=standard_error, recombination_type='single_point') optimal_alpha = evo_mod.initial_population(individual_type='htces') log.log( logging.WARNING, 'An optimal alpha {} and optimal gamma {} have been found.'.format( optimal_alpha[1][0], optimal_alpha[1][1])) htces_forecast = [ i for i in forecast_demand.holts_trend_corrected_exponential_smoothing( alpha=optimal_alpha[1][0], gamma=optimal_alpha[1][1], intercept=log_stats.get('intercept'), slope=log_stats.get('slope')) ] holts_forecast = forecast_demand.holts_trend_corrected_forecast( forecast=htces_forecast, forecast_length=forecast_length) log.log( logging.INFO, 'An OPTIMAL Holts trend exponential smoothing forecast has been generated.' ) sum_squared_error_opt = forecast_demand.sum_squared_errors_indi_htces( squared_error=[htces_forecast], alpha=optimal_alpha[1][0], gamma=optimal_alpha[1][1]) standard_error_opt = forecast_demand.standard_error( sum_squared_error_opt, len(demand), (optimal_alpha[1][0], optimal_alpha[1][1]), 2) ape = LinearRegression(htces_forecast) mape = forecast_demand.mean_aboslute_percentage_error_opt( htces_forecast) stats = ape.least_squared_error() regression_line = deepcopy(_regr_ln(stats=stats)) return { 'forecast_breakdown': htces_forecast, 'forecast': holts_forecast, 'mape': mape, 'statistics': stats, 'optimal_alpha': optimal_alpha[1][0], 'optimal_gamma': optimal_alpha[1][1], 'SSE': sum_squared_error_opt, 'standard_error': standard_error_opt, 'original_standard_error': standard_error, 'regression': [i for i in regression_line.get('regression')] } else: forecast_demand = Forecast(demand) processed_demand = [{ 't': index, 'demand': order } for index, order in enumerate(demand, 1)] stats = LinearRegression(processed_demand) log_stats = stats.least_squared_error(slice_end=6) htces_forecast = [ i for i in forecast_demand.holts_trend_corrected_exponential_smoothing( alpha=alpha, gamma=gamma, intercept=log_stats.get('intercept'), slope=log_stats.get('slope')) ] holts_forecast = forecast_demand.holts_trend_corrected_forecast( forecast=htces_forecast, forecast_length=forecast_length) log.log( logging.INFO, 'A STANDARD Holts trend exponential smoothing forecast has been generated.' ) sum_squared_error = forecast_demand.sum_squared_errors_indi_htces( squared_error=[htces_forecast], alpha=alpha, gamma=gamma) ape = LinearRegression(htces_forecast) mape = forecast_demand.mean_aboslute_percentage_error_opt( htces_forecast) stats = ape.least_squared_error() regression_line = _regr_ln(stats=stats) log.log( logging.WARNING, "A STANDARD Holts trend exponential smoothing forecast has been completed." ) return { 'forecast_breakdown': htces_forecast, 'forecast': holts_forecast, 'mape': mape, 'statistics': stats, 'sum_squared_errors': sum_squared_error, 'regression': [i for i in regression_line.get('regression')] }
def simple_exponential_smoothing_evo( self, smoothing_level_constant: float, initial_estimate_period: int, recombination_type: str = 'single_point', population_size: int = 10, forecast_length: int = 5) -> dict: """ Simple exponential smoothing using evolutionary algorithm for optimising smoothing level constant (alpha value) Args: initial_estimate_period (int): The number of previous data points required for initial level estimate. smoothing_level_constant (float): Best guess at smoothing level constant appropriate for forecast. Returns: dict: Example: """ log.log( logging.INFO, "Executing simple exponential smoothing. " "SMOOTHING_LEVEL: {} " "INITIAL_ESTIMATE_PERIOD: {} " "RECOMBINATION_TYPE: {} " "POPULATION_SIZE: {} " "FORECAST_LENGTH: {}".format(smoothing_level_constant, initial_estimate_period, recombination_type, population_size, forecast_length)) if None != self.__recombination_type: recombination_type = self.__recombination_type sum_orders = 0 for demand in self.__orders[:initial_estimate_period]: sum_orders += demand avg_orders = sum_orders / initial_estimate_period forecast_demand = Forecast(self.__orders, avg_orders) #calls simple_exponential_smoothing method from Forecast object ses_forecast = [ i for i in forecast_demand.simple_exponential_smoothing( *(smoothing_level_constant, )) ] sum_squared_error = forecast_demand.sum_squared_errors( ses_forecast, smoothing_level_constant) standard_error = forecast_demand.standard_error( sum_squared_error, len(self.__orders), smoothing_level_constant) evo_mod = OptimiseSmoothingLevelGeneticAlgorithm( orders=self.__orders, average_order=avg_orders, smoothing_level=smoothing_level_constant, population_size=population_size, standard_error=standard_error, recombination_type=recombination_type) optimal_alpha = evo_mod.initial_population() optimal_ses_forecast = [ i for i in forecast_demand.simple_exponential_smoothing( optimal_alpha[1]) ] ape = LinearRegression(optimal_ses_forecast) mape = forecast_demand.mean_aboslute_percentage_error_opt( optimal_ses_forecast) stats = ape.least_squared_error() simple_forecast = forecast_demand.simple_exponential_smoothing_forecast( forecast=optimal_ses_forecast, forecast_length=forecast_length) sum_squared_error = forecast_demand.sum_squared_errors( optimal_ses_forecast, optimal_alpha[1]) standard_error = forecast_demand.standard_error( sum_squared_error, len(self.__orders), optimal_alpha[1]) regression = { 'regression': [(stats.get('slope') * i) + stats.get('intercept') for i in range(0, 12)] } log.log( logging.INFO, "An OPTIMISED simple exponential smoothing forecast has been completed" ) return { 'forecast_breakdown': optimal_ses_forecast, 'mape': mape, 'statistics': stats, 'forecast': simple_forecast, 'optimal_alpha': optimal_alpha[1], 'standard_error': standard_error, 'regression': [i for i in regression.get('regression')] }
def holts_trend_corrected_exponential_smoothing_forecast(demand: list, alpha: float, gamma: float, forecast_length: int = 4, initial_period: int = 6, **kwargs): if len(kwargs) != 0: if kwargs['optimise']: total_orders = 0 for order in demand[:initial_period]: total_orders += order avg_orders = total_orders / initial_period forecast_demand = Forecast(demand) processed_demand = [{'t': index, 'demand': order} for index, order in enumerate(demand, 1)] stats = LinearRegression(processed_demand) log_stats = stats.least_squared_error(slice_end=6) htces_forecast = [i for i in forecast_demand.holts_trend_corrected_exponential_smoothing(alpha=alpha, gamma=gamma, intercept=log_stats.get( 'intercept'), slope=log_stats.get( 'slope'))] sum_squared_error = forecast_demand.sum_squared_errors_indi_htces(squared_error=[htces_forecast], alpha=alpha, gamma=gamma) standard_error = forecast_demand.standard_error(sum_squared_error, len(demand), (alpha, gamma), 2) evo_mod = OptimiseSmoothingLevelGeneticAlgorithm(orders=demand, average_order=avg_orders, population_size=10, standard_error=standard_error, recombination_type='single_point') optimal_alpha = evo_mod.initial_population(individual_type='htces') log.log(logging.WARNING, 'An optimal alpha {} and optimal gamma {} have been found.'.format(optimal_alpha[1][0], optimal_alpha[1][1])) htces_forecast = [i for i in forecast_demand.holts_trend_corrected_exponential_smoothing(alpha=optimal_alpha[1][0], gamma=optimal_alpha[1][1], intercept=log_stats.get( 'intercept'), slope=log_stats.get('slope'))] holts_forecast = forecast_demand.holts_trend_corrected_forecast(forecast=htces_forecast, forecast_length=forecast_length) log.log(logging.INFO, 'An OPTIMAL Holts trend exponential smoothing forecast has been generated.') sum_squared_error_opt = forecast_demand.sum_squared_errors_indi_htces(squared_error=[htces_forecast], alpha=optimal_alpha[1][0], gamma=optimal_alpha[1][1]) standard_error_opt = forecast_demand.standard_error(sum_squared_error_opt, len(demand), (optimal_alpha[1][0], optimal_alpha[1][1]), 2) ape = LinearRegression(htces_forecast) mape = forecast_demand.mean_aboslute_percentage_error_opt(htces_forecast) stats = ape.least_squared_error() regression_line = deepcopy(regr_ln(stats=stats)) return {'forecast_breakdown': htces_forecast, 'forecast': holts_forecast, 'mape': mape, 'statistics': stats, 'optimal_alpha': optimal_alpha[1][0], 'optimal_gamma': optimal_alpha[1][1], 'SSE': sum_squared_error_opt, 'standard_error': standard_error_opt, 'original_standard_error': standard_error, 'regression': [i for i in regression_line.get('regression')]} else: forecast_demand = Forecast(demand) processed_demand = [{'t': index, 'demand': order} for index, order in enumerate(demand, 1)] stats = LinearRegression(processed_demand) log_stats = stats.least_squared_error(slice_end=6) htces_forecast = [i for i in forecast_demand.holts_trend_corrected_exponential_smoothing(alpha=alpha, gamma=gamma, intercept=log_stats.get( 'intercept'), slope=log_stats.get( 'slope'))] holts_forecast = forecast_demand.holts_trend_corrected_forecast(forecast=htces_forecast, forecast_length=forecast_length) log.log(logging.INFO, 'A STANDARD Holts trend exponential smoothing forecast has been generated.') sum_squared_error = forecast_demand.sum_squared_errors_indi_htces(squared_error=[htces_forecast], alpha=alpha, gamma=gamma) ape = LinearRegression(htces_forecast) mape = forecast_demand.mean_aboslute_percentage_error_opt(htces_forecast) stats = ape.least_squared_error() regression_line = regr_ln(stats=stats) log.log(logging.WARNING, "A STANDARD Holts trend exponential smoothing forecast has been completed.") return {'forecast_breakdown': htces_forecast, 'forecast': holts_forecast, 'mape': mape, 'statistics': stats, 'sum_squared_errors': sum_squared_error, 'regression': [i for i in regression_line.get('regression')]}