Skip to content

Demand Forecasting for FMCG Marketing: A Production Playbook

Practical guide to demand forecasting using Prophet, ARIMA, and machine learning approaches for FMCG marketing — handling promotions, seasonality, hierarchical forecasting, and translating forecasts into marketing action.

Demand Forecasting for FMCG Marketing: A Production Playbook

Demand forecasting in Fast-Moving Consumer Goods (FMCG) is one of the most challenging and impactful applications of data science in marketing. Unlike e-commerce where demand signals are rich and real-time, FMCG demand is mediated through distributors, retailers, and trade promotions — making the signal noisier, the data sparser, and the stakes higher. A 5% improvement in forecast accuracy can translate to millions in reduced waste, optimized promotions, and improved on-shelf availability.

After years of building demand forecasting systems for FMCG companies, I have learned that the forecasting model itself is perhaps 30% of the solution. The other 70% is data preparation, promotion modeling, hierarchical reconciliation, and — most critically — integrating forecasts into marketing decision-making.

The FMCG Demand Forecasting Challenge

FMCG demand forecasting has several unique characteristics that make it fundamentally different from other forecasting problems:

Intermittent demand: Many SKUs, especially in emerging markets or niche categories, have sporadic demand patterns with many zero-demand periods. Traditional time series methods assume continuous demand and fail spectacularly on intermittent series.

Promotion dominance: In FMCG, promotions can account for 20–40% of total volume. A forecast that ignores promotions is useless. But promotion effects are non-linear, interact with each other, and vary by retailer and region.

Hierarchical structure: Demand exists at multiple levels — SKU, brand, category, region, national — and forecasts must be consistent across levels. A marketing team planning a national promotion needs a national forecast, while a regional sales team needs regional forecasts that add up to the national total.

Long supply chains: FMCG supply chains have lead times of weeks to months. This means forecasts need to be accurate further into the future than in e-commerce, where same-day fulfillment is possible.

Data quality issues: Retail audit data (from Nielsen, Kantar) has sampling errors. Distributor sell-in data does not reflect true consumer demand. POS data is available only from modern trade retailers. Reconciling these data sources is a major challenge.

Data Preparation: The Foundation

Data Sources

I work with three primary data sources:

  1. Sell-in data (shipments to distributors/retailers): Available internally, granular, but reflects trade buying patterns rather than consumer demand
  2. Sell-out data (actual retail sales): From POS systems or retail audit panels, closer to true demand but sparser and delayed
  3. Syndicated data (Nielsen, Kantar): Market-level estimates with coverage gaps, available monthly with 4–6 week delay

For most marketing applications, I model sell-out data as the primary demand signal, using sell-in data to fill gaps and syndicated data for market context.

Data Cleaning

FMCG data requires extensive cleaning:

import pandas as pd
import numpy as np

def clean_demand_series(df, sku_col='sku', date_col='date', value_col='demand'):
    """Clean a demand time series for a single SKU."""
    
    # 1. Handle missing dates (fill with zero for FMCG)
    date_range = pd.date_range(df[date_col].min(), df[date_col].max(), freq='W')
    df = df.set_index(date_col).reindex(date_range).fillna(0).reset_index()
    df.columns = [date_col, value_col]
    
    # 2. Detect and handle outliers (likely data errors)
    # Use Hampel filter for robust outlier detection
    median = df[value_col].rolling(window=5, center=True).median()
    mad = (df[value_col] - median).abs().rolling(window=5, center=True).median()
    outlier_mask = (df[value_col] - median).abs() > 3 * 1.4826 * mad
    df.loc[outlier_mask, value_col] = median[outlier_mask]
    
    # 3. Split regular vs. promotion demand
    # (requires promotion calendar data)
    
    return df

Feature Engineering

Beyond the time series itself, I engineer features that capture the drivers of FMCG demand:

Calendar features: Week of year, month, quarter, holiday flags, Ramadan/Eid (critical in Indonesia), Chinese New Year, payday periods

Promotion features: Promotion type (price cut, BOGO, display, leaflet), promotion depth (% discount), promotion duration, concurrent promotions on competing products

Economic features: CPI index, consumer confidence index, commodity price indices relevant to the category

Weather features: Temperature, rainfall — particularly relevant for beverage and seasonal food categories

Distribution features: Numeric distribution (number of stores stocking the item), weighted distribution (proportion of category sales covered), out-of-stock rate

Modeling Approaches

ARIMA/SARIMA: The Classical Baseline

ARIMA remains a strong baseline for FMCG demand forecasting, especially for mature SKUs with stable demand patterns.

from statsmodels.tsa.statespace.sarimax import SARIMAX

# SARIMA with promotion exogenous variables
model = SARIMAX(
    train_demand,
    exog=train_promotions,
    order=(1, 1, 1),           # (p, d, q)
    seasonal_order=(1, 1, 1, 52),  # weekly data, annual seasonality
    enforce_stationarity=False,
    enforce_invertibility=False
)
results = model.fit(disp=False)
forecast = results.get_forecast(steps=12, exog=test_promotions)

Strengths: Well-understood statistical properties, confidence intervals, handles seasonality naturally.

Weaknesses: Assumes linear relationships, struggles with promotion effects, requires stationarity, does not handle intermittent demand well.

When I use it: As a baseline and for SKUs with clean, stable demand patterns. Also useful for short-term forecasting (1–4 weeks) where recent patterns are most predictive.

Prophet: The Marketing-Friendly Model

Facebook’s Prophet has become my go-to model for FMCG demand forecasting because it handles the specific challenges of FMCG data elegantly.

from prophet import Prophet

# Prepare data for Prophet
df_prophet = pd.DataFrame({
    'ds': demand_dates,
    'y': demand_values,
    'promo_intensity': promotion_depth,
    'ramadan': ramadan_flag,
    'price_index': relative_price
})

model = Prophet(
    yearly_seasonality=True,
    weekly_seasonality=False,  # FMCG is typically weekly data
    changepoint_prior_scale=0.05,  # regularization
    seasonality_prior_scale=10,
    holidays_prior_scale=10
)

# Add custom seasonality and regressors
model.add_seasonality(name='monthly', period=30.5, fourier_order=5)
model.add_regressor('promo_intensity')
model.add_regressor('ramadan')
model.add_regressor('price_index')

model.fit(df_prophet)
forecast = model.predict(future_df)

Strengths: Handles holidays and special events natively, robust to missing data, provides uncertainty intervals, easy to add regressors, decomposable (trend, seasonality, holidays, regressors).

Weaknesses: Can overfit with too many changepoints, does not handle intermittent demand well, additive seasonality may not capture multiplicative patterns.

When I use it: For most SKUs in the portfolio, especially those with strong seasonal and promotion patterns. I tune the changepoint_prior_scale carefully — too high and it overfits noise, too low and it misses genuine demand shifts.

Machine Learning: XGBoost for Complex Patterns

For SKUs where classical methods underperform — typically those with complex promotion interactions, many external drivers, or structural breaks — I use gradient-boosted trees.

import xgboost as xgb

# Feature matrix with lags, rolling stats, promotions, calendar
features = [
    'lag_1', 'lag_2', 'lag_3', 'lag_4',  # lagged demand
    'rolling_mean_4w', 'rolling_std_4w',   # rolling statistics
    'promo_type', 'promo_depth',           # promotion features
    'month', 'week_of_year',               # calendar
    'is_ramadan', 'is_holiday',            # events
    'price_ratio_to_category',             # pricing
    'distribution_numeric',                # distribution
]

model = xgb.XGBRegressor(
    n_estimators=300,
    max_depth=5,
    learning_rate=0.05,
    subsample=0.8,
    colsample_bytree=0.8,
    min_child_samples=20
)

Strengths: Captures non-linear promotion effects, handles feature interactions naturally, robust to outliers, works well with mixed feature types.

Weaknesses: Requires more feature engineering, no native uncertainty quantification (use quantile regression or conformal prediction), less interpretable.

When I use it: For high-value SKUs where the extra accuracy justifies the complexity, and for promotion-heavy categories where non-linear effects dominate.

Promotion Modeling: The Critical Differentiator

Promotion modeling deserves special attention because it is the single most impactful component for marketing decision-making.

Promotion Effect Decomposition

I decompose promotion effects into:

  1. Uplift: The incremental volume during the promotion period
  2. Pre-promotion dip: Consumers stocking up before the promotion, reducing pre-promotion demand
  3. Post-promotion dip: Consumers consuming their stockpile, reducing post-promotion demand
  4. Permanent baseline shift: Did the promotion bring in new repeat buyers, permanently lifting baseline demand?

The net promotion effect is: Net = Uplift - Pre-dip - Post-dip + Permanent lift

In my experience, many promotions show a positive gross uplift but a near-zero or negative net effect once you account for the pre/post dips. This insight alone has saved clients millions in wasted promotion spend.

Promotion Features

The features I use for promotion modeling:

  • Promotion type: Price cut, BOGO (buy one get one), bundle, display only, leaflet only, combined
  • Promotion depth: Percentage discount, absolute discount, effective price per unit
  • Promotion duration: Number of weeks
  • Competitor promotions: Is a competing brand also running a promotion in the same week?
  • Promotion frequency: How many times has this SKU been promoted in the last 12 weeks? (Diminishing returns)
  • Retailer: Promotion effectiveness varies dramatically by retailer

Modeling Promotion Effects

For Prophet, I add promotion features as regressors. For ARIMA, I use SARIMAX with promotion variables. For XGBoost, promotions are just features.

The key insight is that promotion effects are non-linear. A 10% discount might generate 20% uplift, but a 20% discount might generate 60% uplift (not 40%). XGBoost captures this naturally; for linear models, I engineer promotion depth buckets (5%, 10%, 15%, 20%+) as categorical features.

Hierarchical Forecasting

FMCG companies need forecasts at multiple levels: SKU, brand, category, region, national. The challenge is consistency — the sum of SKU forecasts should equal the brand forecast.

Bottom-Up Approach

Forecast at the most granular level (SKU-region) and aggregate up. Simple but noisy — individual SKU forecasts have high variance.

Top-Down Approach

Forecast at the national level and disaggregate down using historical proportions. Stable but loses SKU-level signal.

Optimal Reconciliation (My Preferred Approach)

I use the MinT (Minimum Trace) reconciliation method, which finds the optimal combination of forecasts at all levels to minimize the total forecast variance while maintaining consistency.

from sktime.forecasting.reconcile import MinTReconciler
from sktime.forecasting.naive import NaiveForecaster

# Generate base forecasts at each level
# ... (forecast at each level of the hierarchy)

# Reconcile using MinT
reconciler = MinTReconciler(method='ols')
reconciled_forecasts = reconciler.fit_transform(base_forecasts)

This approach consistently outperforms both bottom-up and top-down approaches in my experience, with 10–15% improvement in forecast accuracy at the national level and 5–10% improvement at the SKU level.

Translating Forecasts Into Marketing Action

A demand forecast is only valuable if it changes marketing decisions. Here is how I connect forecasts to action:

Promotion planning: Use the forecast model to simulate “what-if” scenarios. What happens to demand if we run a 15% price cut in week 35 vs. week 40? The promotion effect decomposition tells us the net impact.

Media planning: Demand forecasts inform media weight allocation. If we expect demand to peak in week 45 (pre-holiday), media spend should peak in weeks 42–44 to build awareness before the purchase window.

Budget allocation across brands/categories: Forecasted demand growth by category informs where to allocate marketing investment. Growing categories deserve more budget; declining categories need defensive spending or managed decline.

Trade spend optimization: The largest marketing spend for most FMCG companies is trade spend (retailer promotions). Demand forecasts with promotion modeling enable optimization of trade spend allocation across retailers and time periods.

Evaluation and Monitoring

Forecast Accuracy Metrics

I use multiple metrics:

  • WAPE (Weighted Absolute Percentage Error): The industry standard for FMCG. Weighted by volume so high-volume SKUs dominate.
  • MAE (Mean Absolute Error): Less sensitive to outliers than MAPE
  • Forecast Bias: Systematic over or under-forecasting. I track this separately because bias has different corrective actions than random error.
  • Service Level: Does the forecast support the target service level (e.g., 95% in-stock rate)?

Monitoring in Production

  • Weekly accuracy review: Compare last week’s forecast against actuals
  • Monthly trend analysis: Is forecast accuracy improving or degrading?
  • Quarterly model refresh: Retrain models with updated data
  • Annual model review: Evaluate whether the modeling approach needs fundamental changes

Conclusion

Demand forecasting for FMCG marketing is a complex, multi-faceted challenge that goes far beyond fitting a time series model. It requires clean data from multiple sources, promotion modeling that accounts for non-linear effects and cannibalization, hierarchical reconciliation for consistency, and tight integration with marketing planning processes.

The models — ARIMA, Prophet, XGBoost — are well-established. The differentiation comes from promotion modeling, hierarchical reconciliation, and most importantly, from building the organizational processes that translate forecasts into better marketing decisions.

A 5% improvement in forecast accuracy is achievable with the approaches I have described. In FMCG, that translates to millions in reduced waste, optimized promotions, and improved customer satisfaction. The investment in building a proper demand forecasting capability pays for itself many times over.