Skip to content

Commit a6ee9b7

Browse files
authored
Fixes #10 (#13355)
1 parent aa1855f commit a6ee9b7

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

machine_learning/loss_functions.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,46 @@ def kullback_leibler_divergence(y_true: np.ndarray, y_pred: np.ndarray) -> float
671671
return np.sum(kl_loss)
672672

673673

674+
def symmetric_mean_absolute_percentage_error(
675+
y_true: np.ndarray, y_pred: np.ndarray, epsilon: float = 1e-15
676+
) -> float:
677+
"""
678+
Calculate the Symmetric Mean Absolute Percentage Error (SMAPE) between y_true and
679+
y_pred.
680+
681+
SMAPE is an accuracy measure based on percentage (or relative) errors. It is
682+
symmetric and treats over- and under- predictions equally.
683+
684+
SMAPE = (1/n) * Σ( |y_true - y_pred| / ((|y_true| + |y_pred|) / 2) )
685+
686+
Reference: https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error
687+
688+
Parameters:
689+
- y_true: The true values (ground truth)
690+
- y_pred: The predicted values
691+
- epsilon: Small constant to avoid division by zero
692+
693+
>>> true_values = np.array([100, 200, 300, 400])
694+
>>> predicted_values = np.array([110, 190, 310, 420])
695+
>>> float(symmetric_mean_absolute_percentage_error(true_values, predicted_values))
696+
0.05702187989273155
697+
>>> true_labels = np.array([100, 200, 300])
698+
>>> predicted_probs = np.array([110, 190, 310, 420])
699+
>>> symmetric_mean_absolute_percentage_error(true_labels, predicted_probs)
700+
Traceback (most recent call last):
701+
...
702+
ValueError: Input arrays must have the same length.
703+
"""
704+
if len(y_true) != len(y_pred):
705+
raise ValueError("Input arrays must have the same length.")
706+
707+
denominator = (np.abs(y_true) + np.abs(y_pred)) / 2.0
708+
denominator = np.where(denominator == 0, epsilon, denominator)
709+
710+
smape_loss = np.abs(y_true - y_pred) / denominator
711+
return np.mean(smape_loss)
712+
713+
674714
if __name__ == "__main__":
675715
import doctest
676716

0 commit comments

Comments
 (0)