Skip to content

Commit 71ba880

Browse files
committed
Implement MAPE and SMAPE
1 parent e827ff2 commit 71ba880

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

Orange/evaluation/scoring.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -423,14 +423,29 @@ class MAE(RegressionScore):
423423

424424

425425
class MAPE(RegressionScore):
426-
__wraps__ = skl_metrics.mean_absolute_percentage_error
427426
name = "MAPE"
428427
long_name = "Mean absolute percentage error"
429428
priority = 45
430429

431-
def compute_score(self, results):
432-
res = super().compute_score(results)
433-
return res * 100
430+
@staticmethod
431+
def __wraps__(actual, predicted):
432+
if np.any(actual == 0):
433+
return np.inf
434+
return np.sum(np.abs((actual - predicted) / actual)) / len(actual) * 100
435+
436+
437+
class SMAPE(RegressionScore):
438+
name = "sMAPE"
439+
long_name = "Symmetric mean absolute percentage error"
440+
priority = 45
441+
442+
@staticmethod
443+
def __wraps__(actual, predicted):
444+
diff = np.abs(actual - predicted)
445+
summ = np.abs(actual) + np.abs(predicted)
446+
error = diff / summ
447+
error[summ == 0] = 0.0 # Define 0/0 is correct prediction
448+
return 2 * np.sum(error) / len(actual) * 100
434449

435450

436451
# pylint: disable=invalid-name
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import unittest
2+
3+
import numpy as np
4+
5+
from Orange.evaluation import MAPE
6+
from Orange.evaluation.scoring import SMAPE
7+
8+
9+
class TestScoring(unittest.TestCase):
10+
def test_mape(self):
11+
f = MAPE.__wraps__
12+
exp = np.array([100, -200, 300, 60])
13+
pred = np.array([110, -180, 340, 60])
14+
self.assertEqual(f(exp, pred), (10 / 100 + 20 / 200 + 40 / 300) / 4 * 100)
15+
16+
exp = np.array([0, 200, 300])
17+
self.assertEqual(f(exp, pred), np.inf)
18+
19+
def test_smape(self):
20+
f = SMAPE.__wraps__
21+
exp = np.array([100, -200, 300, 60, 80])
22+
pred = np.array([110, -180, -340, 60, 50])
23+
self.assertEqual(
24+
f(exp, pred),
25+
2 * (10 / 210 + 20 / 380 + 640 / 640 + 0 / 120 + 30 / 130) / 5 * 100)
26+
27+
exp = np.array([0, -200, 300, 60, 80])
28+
self.assertEqual(
29+
f(exp, pred),
30+
2 * (110 / 110 + 20 / 380 + 640 / 640 + 0 / 120 + 30 / 130) / 5 * 100)
31+
32+
33+
if __name__ == '__main__':
34+
unittest.main()

i18n/si/msgs.jaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,9 @@ evaluation/scoring.py:
22542254
class `MAPE`:
22552255
MAPE: true
22562256
Mean absolute percentage error: Povprečna absolutna odstotna napaka
2257+
class `SMAPE`:
2258+
sMAPE: true
2259+
Symmetric mean absolute percentage error: Simetrična povprečna absolutna odstotna napaka
22572260
class `R2`:
22582261
R2: true
22592262
# Je to OK?

0 commit comments

Comments
 (0)