Skip to content

Forecast bias

Do we systematically forecast too much or too little?

Current value (inventory case data): -2.1% - ✓ On target. Open the case.

Field Value
Definition (Sum of forecast - sum of actuals) / sum of actuals. Positive = over-forecast.
Formula (sum(F) - sum(A)) / sum(A)
Unit %
Granularity SKU x week; rolled up by SKU class and month.
Direction Inside a band ↔ (too high and too low are both bad)
Target and thresholds -5.0% to 5.0% (amber -10.0% to 10.0%)
Parameters –
Owner Demand Planner
Source Demand (UCI Online Retail II) + baseline forecast computed in this repo
Input table forecast, columns actual_units, forecast_units
Recommended chart bar - Diverging bars by month around zero with the green band shaded.
Related KPIs Forecast error (WAPE), Obsolete stock share, Stockout rate (SKU-days)

How to read it

Error you can fix. Accuracy (WAPE) says how big the miss is; bias says in which direction. Persistent positive bias builds excess and obsolete stock; negative bias builds stockouts.

Common misreadings

  • A bias near zero can hide large errors that cancel out; never read it without WAPE.

Worked example (from the test suite)

actual_units forecast_units
100 90
10 20
0 5

Expected result: 4.55%. (115 - 110) / 110 = +0.04545 -> 4.5% over-forecast, inside the +/-5% band.

This example is asserted in tests/test_formulas.py against the Python function and in tests/test_sql.py against the SQL below.

Implementations

Python function (the single implementation used by the site):

@kpi("forecast_bias")
def forecast_bias(df: pd.DataFrame) -> float:
    actual = df["actual_units"].sum()
    return safe_ratio(df["forecast_units"].sum() - actual, actual)

Reference SQL (tested on SQLite):

SELECT (SUM(forecast_units) - SUM(actual_units)) * 1.0 / SUM(actual_units) FROM forecast