Demand Forecasting
Predicting demand to plan production, inventory and staffing. Learn qualitative vs quantitative forecasting, time-series components (level, trend, seasonality, noise), naive, moving average and weighted moving average, exponential smoothing and choosing α, Holt's trend and Holt–Winters seasonal methods, causal regression, error measures (MAD, MSE, MAPE, bias and tracking signal), and machine-learning forecasting — with Python comparing three methods on real-looking data.
Every plan starts with a forecast: how many units will customers buy next month, how many patients will arrive tomorrow, how much electricity will be needed at 6 pm? Forecasts are always wrong — the goal is to be less wrong, know how wrong, and plan for the error.
Choosing the method that matches the demand pattern (stable, trending, seasonal) and monitoring accuracy continuously matters more than sophisticated algorithms.
An analogy
Forecasting is like weather prediction for a business: recent days (smoothing) plus known patterns (seasons, trends) give a best guess, and a good forecaster also reports how confident they are.
Forecasting approaches
Qualitative: expert judgement, Delphi method, market surveys, sales-force composites — for new products or disruptions. Quantitative time-series: use past demand patterns. Causal: relate demand to drivers (price, promotions, weather, GDP) using regression. Most organisations combine them in a sales & operations planning (S&OP) process.
Time-series methods
Match method to pattern:
- Stable level — moving average, simple exponential smoothing (α 0.1–0.3)
- Trend — Holt's double exponential smoothing, linear regression on time
- Seasonality — seasonal indices, Holt–Winters (additive or multiplicative)
- Intermittent demand — Croston's method for spare parts
- Complex patterns — ARIMA, and ML models (gradient boosting, LSTMs) with many features
Measuring accuracy
Evaluate on data not used to fit (hold-out). MAD is in units, MAPE is scale-free (but explodes near zero demand), MSE penalises large errors, bias (mean error) reveals systematic over/under-forecasting. The tracking signal flags bias drift. Forecast error drives safety stock: σ of forecast error × z × √lead time.
Forecasting in practice
Forecast at the right aggregation (families are more accurate than SKUs; use top-down/bottom-up reconciliation), shorten horizons where possible, clean data for stock-outs and promotions, and combine methods (ensembles). Probabilistic forecasts (quantiles, prediction intervals) feed better inventory decisions than point forecasts. Demand sensing uses near-real-time data (POS, web traffic).
Formulas
- Moving average:
F_{t+1} = (D_t + D_{t−1} + … + D_{t−n+1})/n - Exponential smoothing:
F_{t+1} = αD_t + (1 − α)F_t - Holt (trend):
L_t = αD_t + (1−α)(L_{t−1}+T_{t−1}); T_t = β(L_t − L_{t−1}) + (1−β)T_{t−1}; F_{t+1} = L_t + T_t - Error measures:
MAD = Σ|e|/n; MSE = Σe²/n; MAPE = Σ|e/D|/n × 100 - Tracking signal:
TS = Σe / MAD (alarm if |TS| > 4)
Worked example: Exponential smoothing
Given: F_t = 150, D_t = 160, α = 0.3
Find: F_{t+1}.
- 0.3 × 160 + 0.7 × 150
Answer: 153
Worked example: MAPE
Given: Errors 10, −5, 8 on demands 100, 125, 160
Find: MAPE.
- (10% + 4% + 5%)/3
Answer: 6.33%
Worked example: Seasonal index
Given: Q4 average 260, overall quarterly average 200
Find: Index and Q4 forecast if next year's annual forecast is 1000.
- Index = 1.30
- (1000/4) × 1.30
Answer: 1.30; Q4 forecast 325
Moving average vs exponential smoothing vs Holt's trend
# Forecasting monthly demand: moving average vs exponential smoothing, with MAD and MAPE
demand = [120, 132, 128, 140, 151, 147, 160, 158, 171, 169, 180, 186]
def errors(fc):
pairs = [(d, f) for d, f in zip(demand, fc) if f is not None]
mad = sum(abs(d - f) for d, f in pairs) / len(pairs)
mape = sum(abs(d - f) / d for d, f in pairs) / len(pairs) * 100
return mad, mape
ma3 = [None] * 3 + [sum(demand[i-3:i]) / 3 for i in range(3, len(demand))]
alpha = 0.4
es = [demand[0]]
for d in demand[:-1]:
es.append(alpha * d + (1 - alpha) * es[-1])
es_eval = [None] * 3 + es[3:]
# Holt's linear trend (alpha 0.4, beta 0.3)
a, b = 0.4, 0.3
level, trend = demand[0], demand[1] - demand[0]
holt = [None, None]
for t in range(1, len(demand) - 1):
level, prev = a * demand[t] + (1 - a) * (level + trend), level
trend = b * (level - prev) + (1 - b) * trend
holt.append(level + trend)
holt_eval = [None] * 3 + holt[3:]
for name, fc in (("3-month MA", ma3), ("exp. smoothing", es_eval), ("Holt trend", holt_eval)):
mad, mape = errors(fc)
print(f"{name:15s}: MAD {mad:5.2f}, MAPE {mape:4.1f}%")
print(f"Holt forecast for month 13: {level + trend:.1f}")
# 3-month MA : MAD 11.81, MAPE 7.3%
# exp. smoothing : MAD 14.01, MAPE 8.6%
# Holt trend : MAD 5.61, MAPE 3.6%
# Holt forecast for month 13: 183.8With a clear upward trend, moving averages and simple exponential smoothing always lag behind; Holt's method models the trend and halves the error. (The month-13 forecast uses the level and trend updated only through month 11 here — a production implementation would also update with month 12.)
Common mistakes
- Wrong: Evaluating accuracy on training data. — Right: Use hold-out periods or rolling-origin evaluation.
- Wrong: Using simple smoothing on trending data. — Right: Model trend (Holt) and seasonality (Holt–Winters).
- Wrong: Forecasting sales instead of demand. — Right: Correct for stock-outs that censored sales.
Applications
- Retail & e-commerce: SKU-store forecasts for replenishment.
- Manufacturing: Master production scheduling and S&OP.
- Utilities: Hourly load forecasting.
- Healthcare: Admissions and staffing forecasts.
Key takeaways
- Match method to pattern: level, trend, season.
- F_{t+1} = αD_t + (1 − α)F_t.
- Measure MAD, MAPE, bias on hold-out data.
- Forecast error sizes safety stock.
Going further
- Hierarchical reconciliation: MinT and top-down/bottom-up consistent forecasts.
- ARIMA & SARIMA: Box–Jenkins models.
- Deep learning forecasting: DeepAR, temporal fusion transformers.