Почему метрика MAPE асимметрична?

Ответ

MAPE (Mean Absolute Percentage Error) асимметрична из-за своей формулы, где ошибка нормируется на фактическое значение:

MAPE = (100% / n) * Σ |(Actual - Forecast) / Actual|

Причина асимметрии:

  1. Нижняя граница ошибки: Когда прогноз (Forecast) превышает фактическое значение (Actual), максимальное значение MAPE стремится к 100% (если Forecast >> Actual, то дробь (F - A)/A может быть большой, но это все еще одна сторона).
  2. Верхняя граница ошибки отсутствует: Когда прогноз меньше фактического значения, и особенно если Actual близко к нулю, знаменатель становится очень маленьким, что может привести к неограниченно большим значениям MAPE (например, 1000% и более).

Практический пример:

import numpy as np

def mape(actual, forecast):
    return np.mean(np.abs((actual - forecast) / actual)) * 100

# Случай 1: Завышенный прогноз
actual = 100
forecast_over = 150  # Ошибка: (100-150)/100 = -0.5 -> |0.5| -> 50%
print(f'MAPE (over): {mape(actual, forecast_over):.1f}%')

# Случай 2: Заниженный прогноз (симметричный случай)
forecast_under = 50   # Ошибка: (100-50)/100 = 0.5 -> 50%
print(f'MAPE (under): {mape(actual, forecast_under):.1f}%')

# Случай 3: Заниженный прогноз при малом actual (проблема асимметрии)
actual_small = 10
forecast_zero = 0     # Ошибка: (10-0)/10 = 1 -> 100%
# А если actual = 1, а forecast = 0, то ошибка уже 1000%
print(f'MAPE (small actual): {mape(actual_small, forecast_zero):.1f}%')

Вывод: Из-за этой асимметрии MAPE сильно штрафует заниженные прогнозы для малых фактических значений и не подходит для данных, содержащих нули или близкие к нулю значения. В таких случаях лучше использовать симметричную sMAPE, MAE или масштабированную ошибку, например, MASE.

Ответ 18+ 🔞

Э, слушай, вот эта ваша MAPE — вообще хитрая жопа, ей-богу. С виду вроде простая формула, а подвох там овердохуища.

Смотри, в чём прикол. Она же ошибку на фактическое значение делит: (100% / n) * Σ |(Actual - Forecast) / Actual|. Ну, типа, в процентах всё понятно будет. А фишка в том, что у неё границы — хуй с горы, а не ровные.

Где собака зарыта:

  1. Если переоценил (прогноз больше факта): Ну, допустим, накосячил в два раза. Ошибка будет, скажем, 100%. Вроде много, но это ещё цветочки.
  2. А вот если недооценил, да ещё и факт маленький: Вот тут начинается ёперный театр. Потому что если Actual близок к нулю, то знаменатель в дроби — просто пиздец какой маленький. И эта дробь взлетает до небес. Может быть и 1000%, и 10000% — предела-то нет! Полная асимметрия, доверия к такой метрике — ноль ебать.

Ну, чтобы совсем понятно было, накидаю кода:

import numpy as np

def mape(actual, forecast):
    return np.mean(np.abs((actual - forecast) / actual)) * 100

# Ситуация первая: Напрогнозировал с запасом
actual = 100
forecast_over = 150  # Ошибка: (100-150)/100 = -0.5 -> модуль 0.5 -> 50%
print(f'MAPE (переоценил): {mape(actual, forecast_over):.1f}%')

# Ситуация вторая: Не доложил (симметричный случай, для приличия)
forecast_under = 50   # Ошибка: (100-50)/100 = 0.5 -> тоже 50%
print(f'MAPE (недооценил): {mape(actual, forecast_under):.1f}%')

# Ситуация третья: А вот теперь ловушка
actual_small = 10
forecast_zero = 0     # Ошибка: (10-0)/10 = 1 -> 100%
# А представь, actual = 1, а forecast = 0? Ошибка уже 1000%, Карл!
print(f'MAPE (маленький факт и ноль): {mape(actual_small, forecast_zero):.1f}%')

Итог, чувак: Из-за этой ебаной асимметрии MAPE просто вмандяривает нереальные штрафы, если ты промахнулся мимо маленьких значений или, не дай бог, там нули в данных есть. Получается, что она не штрафует, а просто издевается. Поэтому если в твоих рядах есть нули или значения околонулевые — беги от MAPE как от огня. Лучше посмотри в сторону sMAPE, MAE или той же MASE. С ними хоть волнение ебать не будет, что из-за одного нуля вся статистика накрылась медным тазом.