Python中的MAPE计算

11

我想计算预测值和真实值的平均绝对百分比误差(MAPE)。我从这里找到了解决方案,但这会导致错误,并在mask = a <> 0行显示语法无效。

    def mape_vectorized_v2(a, b): 
    mask = a <> 0
    return (np.fabs(a - b)/a)[mask].mean() 

   def mape_vectorized_v2(a, b): 
       File "<ipython-input-5-afa5c1162e83>", line 1
         def mape_vectorized_v2(a, b):
                                       ^
     SyntaxError: unexpected EOF while parsing
我正在使用Spyder3。我的预测值是np.array类型,而真实值是dataframe。
type(predicted)
Out[7]: numpy.ndarray
type(y_test)
Out[8]: pandas.core.frame.DataFrame

我该如何清除这个错误并继续进行MAPE计算?

编辑:

predicted.head()
Out[22]: 
   Total_kWh
0   7.163627
1   6.584960
2   6.638057
3   7.785487
4   6.994427

y_test.head()
Out[23]: 
     Total_kWh
79         7.2
148        6.7
143        6.7
189        7.2
17         6.4

np.abs(y_test[['Total_kWh']] - predicted[['Total_kWh']]).head()
Out[24]: 
   Total_kWh
0        NaN
1        NaN
2        NaN
3        NaN
4   0.094427

2
你需要 mask = a != 0 - jezrael
7个回答

38

在Python中,如果要比较不等,需要使用!=而不是<>

因此需要:

def mape_vectorized_v2(a, b): 
    mask = a != 0
    return (np.fabs(a - b)/a)[mask].mean()

来自 stats.stackexchange 的另一个解决方案:

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

5
给我返回 NaN,你知道什么时候会产生这样的值吗?我的第二个数组包含为零的值,我该如何修改后续的解决方案以包括这些情况? - Ehrendil
3
第一个函数不会导致在a为负数时出现负的MAPE值吗?难道计算公式不应该是(np.fabs((a - b))/np.fabs(a))[mask].mean(),其中分母也是绝对值吗? - Robbie Cronin

8

scikit-learn(v0.24)新版本提供了一个可以计算MAPE的函数。

sklearn.metrics.mean_absolute_percentage_error

你需要的只是两个类似数组的变量:y_true,用于存储实际/真实值,以及 y_pred,用于存储预测值。

您可以参考官方文档这里


2
sklearn的mean_absolute_percentage_error函数会给出错误的值,即使在官方文档中给出的示例中,也会得到112589990684262.48这样的异常结果。 - sareek

8

两种解决方案都不能处理零值。这个对我有效:

def percentage_error(actual, predicted):
    res = np.empty(actual.shape)
    for j in range(actual.shape[0]):
        if actual[j] != 0:
            res[j] = (actual[j] - predicted[j]) / actual[j]
        else:
            res[j] = predicted[j] / np.mean(actual)
    return res

def mean_absolute_percentage_error(y_true, y_pred): 
    return np.mean(np.abs(percentage_error(np.asarray(y_true), np.asarray(y_pred)))) * 100

我希望这有所帮助。


np.mean(actual) 可以替换为其他标准,如非常小的浮点数等。 - Pablo Andrés Castañeda

0

由于实际值也可能为零,因此我将分母中的实际值取平均值,而不是实际值本身:

Error = np.sum(np.abs(np.subtract(data_4['y'],data_4['pred'])))
Average = np.sum(data_4['y'])
MAPE = Error/Average

0

这里有一种可以解决“0”分母的MAPE计算方法,而且速度很快。

def mod_my_MAPE(y, pred):
    y = y[:][y[:]!=0]
    pred = pred[:][y[:]!=0]
    summ = np.sum(abs((y[:] - pred[:])/y[:]))
    return summ/len(y)

0

自从scikit-learn版本0.24以来,我们可以使用sklearn.metrics.mean_absolute_percentage_error

这里是他们GitHub仓库上的实现链接。

我刚刚在本地尝试了最新版本(1.0.2)。

这里有一个例子(源代码

>>> from sklearn.metrics import mean_absolute_percentage_error
>>> y_true = [[0.5, 1], [-1, 1], [7, -6]]
>>> y_pred = [[0, 2], [-1, 2], [8, -5]]
>>> mean_absolute_percentage_error(y_true, y_pred)
0.5515...

注意:如果y_true的值之一为零,MAPE可能会出现问题。在Scikit-learn中,这将导致一个任意高的数字。

请参考此示例(源代码

>>> from sklearn.metrics import mean_absolute_percentage_error
>>> y_true = [1., 0., 2.4, 7.]
>>> y_pred = [1.2, 0.1, 2.4, 8.]
>>> mean_absolute_percentage_error(y_true, y_pred)
112589990684262.48

0

这里是一个改进版,考虑到了零的情况:

    #Mean Absolute Percentage error 
def mape(y_true, y_pred,sample_weight=None,multioutput='uniform_average'):
    y_type, y_true, y_pred, multioutput = _check_reg_targets(y_true, y_pred, multioutput)
    epsilon = np.finfo(np.float64).eps
    mape = np.abs(y_pred - y_true) / np.maximum(np.abs(y_true), epsilon)
    output_errors = np.average(mape,weights=sample_weight, axis=0)
    if isinstance(multioutput, str):
        if multioutput == 'raw_values':
            return output_errors
        elif multioutput == 'uniform_average':
            # pass None as weights to np.average: uniform mean
            multioutput = None
    return np.average(output_errors, weights=multioutput)

def _check_reg_targets(y_true, y_pred, multioutput, dtype="numeric"):
    if y_true.ndim == 1:
        y_true = y_true.reshape((-1, 1))

    if y_pred.ndim == 1:
        y_pred = y_pred.reshape((-1, 1))

    if y_true.shape[1] != y_pred.shape[1]:
        raise ValueError("y_true and y_pred have different number of output "
                         "({0}!={1})".format(y_true.shape[1], y_pred.shape[1]))

    n_outputs = y_true.shape[1]
    allowed_multioutput_str = ('raw_values', 'uniform_average',
                               'variance_weighted')
    if isinstance(multioutput, str):
        if multioutput not in allowed_multioutput_str:
            raise ValueError("Allowed 'multioutput' string values are {}. "
                             "You provided multioutput={!r}".format(
                                 allowed_multioutput_str,
                                 multioutput))
    elif multioutput is not None:
        multioutput = check_array(multioutput, ensure_2d=False)
        if n_outputs == 1:
            raise ValueError("Custom weights are useful only in "
                             "multi-output cases.")
        elif n_outputs != len(multioutput):
            raise ValueError(("There must be equally many custom weights "
                              "(%d) as outputs (%d).") %
                             (len(multioutput), n_outputs))
    y_type = 'continuous' if n_outputs == 1 else 'continuous-multioutput'

    return y_type, y_true, y_pred, multioutput

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接