43
$\begingroup$

How can we calculate the Mean absolute percentage error (MAPE) of our predictions using Python and scikit-learn?

From the docs, we have only these 4 metric functions for Regressions:

  • metrics.explained_variance_score(y_true, y_pred)
  • metrics.mean_absolute_error(y_true, y_pred)
  • metrics.mean_squared_error(y_true, y_pred)
  • metrics.r2_score(y_true, y_pred)
$\endgroup$
1
46
$\begingroup$

As noted (for example, in Wikipedia), MAPE can be problematic. Most pointedly, it can cause division-by-zero errors. My guess is that this is why it is not included in the sklearn metrics.

However, it is simple to implement.

from sklearn.utils import check_arrays
def mean_absolute_percentage_error(y_true, y_pred): 
    y_true, y_pred = check_arrays(y_true, y_pred)

    ## Note: does not handle mix 1d representation
    #if _is_1d(y_true): 
    #    y_true, y_pred = _check_1d_array(y_true, y_pred)

    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

Use like any other metric...:

> y_true = [3, -0.5, 2, 7]; y_pred = [2.5, -0.3, 2, 8]
> mean_absolute_percentage_error(y_true, y_pred)
Out[19]: 17.738095238095237

(Note that I'm multiplying by 100 and returning a percentage.)

... but with caution:

> y_true = [3, 0.0, 2, 7]; y_pred = [2.5, -0.3, 2, 8]
> #Note the zero in y_pred
> mean_absolute_percentage_error(y_true, y_pred)
-c:8: RuntimeWarning: divide by zero encountered in divide
Out[21]: inf
$\endgroup$
4
  • 1
    $\begingroup$ There's an error in this answer. Should be (replace y_pred with y_true in denominator): return np.mean(np.abs((y_true - y_pred) / y_true)) * 100 $\endgroup$ – 404pio Jan 18 '14 at 23:36
  • 2
    $\begingroup$ check_arrays was ditched by scipy. There's check_array in the current sklearn but it doesn't seem like it works the same way. $\endgroup$ – kilojoules Mar 30 '16 at 0:36
  • 1
    $\begingroup$ check_arrays method is removed from .16. $\endgroup$ – Arpit Sisodia May 1 '17 at 7:15
  • 1
    $\begingroup$ stackoverflow.com/questions/42250958/… $\endgroup$ – Arpit Sisodia May 1 '17 at 7:20
36
$\begingroup$

here is an updated version:

import numpy as np

def mean_absolute_percentage_error(y_true, y_pred): 
    y_true, y_pred = np.array(y_true), np.array(y_pred)
    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
$\endgroup$
4
  • 4
    $\begingroup$ What if one of y_true is 'zero' ? Divide by zero error ? $\endgroup$ – Akshay Tilekar Apr 22 '20 at 13:43
  • $\begingroup$ Add a very small number to the denominator to avoid infinity $\endgroup$ – Jack Daniel May 13 '20 at 9:20
  • $\begingroup$ @JackDaniel isn't this going to overly penalise the model? imagine the real value is 0 and the predicted 2 (in many contexts that would be good prediction). but if you divide 2 by a very small number you will get a huge error estimate $\endgroup$ – LetsPlayYahtzee Oct 22 '20 at 17:11
  • $\begingroup$ @LetsPlayYahtzee Yeah, agreed. I did face the issue. I moved to MAAPE Error instead of MAPE. $\endgroup$ – Jack Daniel Oct 26 '20 at 6:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.