Source code for ts_benchmark.evaluation.metrics.regression_metrics

# -*- coding: utf-8 -*-

import numpy as np

__all__ = ["mae", "mse", "rmse", "mape", "smape", "mase", 'wape', 'msmape', "mae_norm", "mse_norm", "rmse_norm", "mape_norm", "smape_norm", "mase_norm", 'wape_norm', 'msmape_norm']


def _error(actual: np.ndarray, predicted: np.ndarray, **kwargs):
    """ Simple error """
    return actual - predicted


def _percentage_error(actual: np.ndarray, predicted: np.ndarray, **kwargs):
    """ Percentage error """
    return (actual - predicted) / actual


[docs] def mse(actual: np.ndarray, predicted: np.ndarray, **kwargs): """ Mean Squared Error """ return np.mean(np.square(_error(actual, predicted)))
[docs] def rmse(actual: np.ndarray, predicted: np.ndarray, **kwargs): """ Root Mean Squared Error """ return np.sqrt(mse(actual, predicted))
[docs] def mae(actual: np.ndarray, predicted: np.ndarray, **kwargs): """ Mean Absolute Error """ return np.mean(np.abs(_error(actual, predicted)))
[docs] def mase( actual: np.ndarray, predicted: np.ndarray, hist_data: np.ndarray, seasonality: int = 2, **kwargs ): """ Mean Absolute Scaled Error Baseline (benchmark) is computed with naive forecasting (shifted by @seasonality) """ if seasonality == 2: return -1 scale = len(predicted) / (len(hist_data) - seasonality) dif = 0 for i in range((seasonality + 1), len(hist_data)): dif = dif + abs(hist_data[i] - hist_data[i - seasonality]) scale = scale * dif return (sum(abs(actual - predicted)) / scale)[0]
[docs] def mape(actual: np.ndarray, predicted: np.ndarray, **kwargs): """ Mean Absolute Percentage Error Properties: + Easy to interpret + Scale independent - Biased, not symmetric - Undefined when actual[t] == 0 """ return np.mean(np.abs(_percentage_error(actual, predicted))) * 100
[docs] def smape(actual: np.ndarray, predicted: np.ndarray, **kwargs): """ Symmetric Mean Absolute Percentage Error """ return ( np.mean( 2.0 * np.abs(actual - predicted) / ((np.abs(actual) + np.abs(predicted))) ) * 100 )
[docs] def wape(actual: np.ndarray, predicted: np.ndarray, **kwargs): """Masked weighted absolute percentage error (WAPE) :param predicted: Predicted values. :param actual: Ground truth labels. :return: Masked mean absolute error. """ loss = np.sum(np.abs(actual - predicted)) / np.sum(np.abs(actual)) * 100 return loss
[docs] def msmape(actual: np.ndarray, predicted: np.ndarray, epsilon: float = 0.1, **kwargs): """ Function to calculate series wise smape values :param actual: Array of actual values. :param predicted: Array of predicted values. :param epsilon: Small constant to avoid division by zero. :return: Mean symmetric mean absolute percentage error (MSMAPE) as a percentage. """ comparator = np.full_like(actual, 0.5 + epsilon) denom = np.maximum(comparator, np.abs(predicted) + np.abs(actual) + epsilon) msmape_per_series = np.mean(2 * np.abs(predicted - actual) / denom) * 100 return msmape_per_series
def _error_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Simple error """ return scaler.transform(actual) - scaler.transform(predicted) def _percentage_error_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Percentage error """ return (scaler.transform(actual) - scaler.transform(predicted)) / scaler.transform(actual)
[docs] def mse_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Mean Squared Error """ return np.mean(np.square(_error_norm(actual, predicted, scaler)))
[docs] def rmse_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Root Mean Squared Error """ return np.sqrt(mse_norm(actual, predicted, scaler))
[docs] def mae_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Mean Absolute Error """ return np.mean(np.abs(_error_norm(actual, predicted, scaler)))
[docs] def mase_norm( actual: np.ndarray, predicted: np.ndarray, scaler: object, hist_data: np.ndarray, seasonality: int = 2, **kwargs ): """ Mean Absolute Scaled Error Baseline (benchmark) is computed with naive forecasting (shifted by @seasonality) """ actual = scaler.transform(actual) predicted = scaler.transform(predicted) hist_data = scaler.transform(hist_data) if seasonality == 2: return -1 scale = len(predicted) / (len(hist_data) - seasonality) dif = 0 for i in range((seasonality + 1), len(hist_data)): dif = dif + abs(hist_data[i] - hist_data[i - seasonality]) scale = scale * dif return (sum(abs(actual - predicted)) / scale)[0]
[docs] def mape_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Mean Absolute Percentage Error Properties: + Easy to interpret + Scale independent - Biased, not symmetric - Undefined when actual[t] == 0 """ return np.mean(np.abs(_percentage_error_norm(actual, predicted, scaler))) * 100
[docs] def smape_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Symmetric Mean Absolute Percentage Error """ actual = scaler.transform(actual) predicted = scaler.transform(predicted) return ( np.mean( 2.0 * np.abs(actual - predicted) / ((np.abs(actual) + np.abs(predicted))) ) * 100 )
[docs] def wape_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, **kwargs): """ Masked weighted absolute percentage error (WAPE) :param actual: Array of actual values. :param predicted: Array of predicted values. :param scaler: Object used to scale the actual and predicted values. :return: Weighted absolute percentage error (WAPE) as a percentage. """ actual = scaler.transform(actual) predicted = scaler.transform(predicted) loss = np.sum(np.abs(actual - predicted)) / np.sum(np.abs(actual)) * 100 return loss
[docs] def msmape_norm(actual: np.ndarray, predicted: np.ndarray, scaler: object, epsilon: float = 0.1, **kwargs): """ Function to calculate series wise smape values :param actual: Array of actual values. :param predicted: Array of predicted values. :param scaler: Object used to scale the actual and predicted values. :param epsilon: Small constant to avoid division by zero. :return: Mean symmetric mean absolute percentage error (MSMAPE) as a percentage. """ actual = scaler.transform(actual) predicted = scaler.transform(predicted) comparator = np.full_like(actual, 0.5 + epsilon) denom = np.maximum(comparator, np.abs(predicted) + np.abs(actual) + epsilon) msmape_per_series = np.mean(2 * np.abs(predicted - actual) / denom) * 100 return msmape_per_series