Average Absolute Error (AAE)

Average absolute error is the mean of the absolute differences between actuals and forecasts:

\[ \text{AAE} = \frac{1}{n}\sum_{t=1}^{n}|y_t - \hat{y}_t| \]

This is the same quantity as mean absolute error. Two names, one formula — which is worth saying plainly, because a glossary with both can imply a distinction that does not exist.

The absolute value is the whole content

import numpy as np

actual = np.array([100.0, 120.0, 130.0])
forecast = np.array([90.0, 115.0, 140.0])
errors = actual - forecast
print(f"  errors {errors.tolist()}")
print(f"  mean error (ME)          {errors.mean():>8.4f}   direction survives, size cancels")
print(f"  average absolute error   {np.abs(errors).mean():>8.4f}   size survives, direction is gone")
print("  AAE is the same quantity as MAE - two names, one formula")
"""Taking absolute values first is the whole difference, and it is the reason
   a model can have mean error near zero while every forecast is wrong."""

rng = np.random.default_rng(0)
truth = rng.normal(500, 50, size=20_000)
biased = truth + 40
noisy = truth + rng.normal(0, 60, size=20_000)
print(f"\n{'forecast':>26}{'mean error':>13}{'AAE':>10}")
for name, f in (("always 40 units too high", biased), ("unbiased but scattered", noisy)):
    e = truth - f
    print(f"{name:>26}{e.mean():>13.4f}{np.abs(e).mean():>10.4f}")
print("  report only the mean error and the second model looks flawless;")
print("  report only AAE and the first model's fixable bias is invisible")

print(f"\n  what minimizing each one aims at, on a skewed target:")
heavy = np.concatenate([rng.normal(100, 10, 9_500), rng.normal(900, 50, 500)])
grid = np.linspace(80, 400, 3_201)
aae = np.array([np.abs(heavy - c).mean() for c in grid])
mse = np.array([((heavy - c) ** 2).mean() for c in grid])
print(f"    the constant minimizing AAE is {grid[aae.argmin()]:.2f}"
      f"   (the median is {np.median(heavy):.2f})")
print(f"    the constant minimizing squared error is {grid[mse.argmin()]:.2f}"
      f"   (the mean is {heavy.mean():.2f})")
print("  choosing AAE over squared error is choosing to forecast the median.")
print("  on a skewed demand series those two targets are 40 units apart")
#   errors [10.0, 5.0, -10.0]
#   mean error (ME)            1.6667   direction survives, size cancels
#   average absolute error     8.3333   size survives, direction is gone
#   AAE is the same quantity as MAE - two names, one formula
#
#                   forecast   mean error       AAE
#   always 40 units too high     -40.0000   40.0000
#     unbiased but scattered       0.0093   48.1484
#   report only the mean error and the second model looks flawless;
#   report only AAE and the first model's fixable bias is invisible
#
#   what minimizing each one aims at, on a skewed target:
#     the constant minimizing AAE is 100.70   (the median is 100.70)
#     the constant minimizing squared error is 140.10   (the mean is 140.05)
#   choosing AAE over squared error is choosing to forecast the median.
#   on a skewed demand series those two targets are 40 units apart

The first block separates the two things people conflate. On errors of +10, +5 and −10, the mean error is 1.6667 and the average absolute error is 8.3333. Taking absolute values first is the entire difference: mean error keeps direction and cancels size, AAE keeps size and discards direction.

The second block shows why reporting only one of them misleads. A forecast that is always 40 units too high has mean error −40.0000 and AAE 40.0000. An unbiased but scattered forecast has mean error 0.0093 and AAE 48.1484. Judged on mean error the second model looks flawless; judged on AAE the first model's bias — the part that is trivially fixable — is invisible.

The practical rule follows directly: report both. A large AAE with near-zero mean error can reflect scattered errors, offsetting segment biases, or outcome variability that available inputs cannot explain. Inspect conditional errors, uncertainty, and data quality before choosing a remedy. A mean error similar in magnitude to AAE suggests substantial directional bias; validate any offset on separate data rather than assuming it will resolve every case.

What minimizing it aims at

The last block is the property that decides when to choose it. On a skewed series — mostly around 100 with a heavy upper cluster — the constant that minimizes AAE is 100.70, which is the median. The constant that minimizes squared error is 140.10, which is the mean. The two targets sit 40 units apart on the same data.

So choosing AAE over a squared measure is not a preference about how to summarize errors; it is a decision about what the forecast should aim at. If half your demand days should fall on each side of the forecast, AAE is the right objective. If the total over a period has to be right, the mean is what you want and a squared measure targets it.

The same property makes AAE robust: one extreme day moves the median-seeking target very little, where it moves a mean-seeking one a great deal. Robustness and target selection are the same fact seen from two sides, not two separate advantages.

Reading it

AAE is in the units of the target, which makes it readable and makes it uncomparable across series with different scales. An AAE of 40 units is good for an item selling 10,000 and catastrophic for one selling 50, and a single AAE across a mixed catalog is dominated by the largest items.

For cross-series comparison the number has to be scaled — by the actuals, as WAPE does, or by a baseline's error, as MASE does. Within one series against one baseline, AAE in raw units is often the clearest thing you can put in front of a planner.

References

  • NumPy documentation, numpy.abs and numpy.median. numpy.org

Discover more from Insightful Data Lab

Subscribe to get the latest posts sent to your email.

Similar Posts

Questions, corrections, or additional insights?

This site uses Akismet to reduce spam. Learn how your comment data is processed.