Skip to content

Demand Forecasting in Python: A Practical Starter

By Newtown Analytics · · 7 min read

For finance, fp&a & accounting managers

Python demand forecasting is not about using the most sophisticated model. It is about building a repeatable, testable process that turns sales history into forecasts, measures how good they are and runs the same way every month without someone rebuilding a spreadsheet. For finance and planning teams with a few thousand items, Python can read data from several sources, apply the same method to every item, compare methods fairly and write the results back to a file or database. This guide is a practical starter. It covers the setup, the shape of the data, simple baseline methods you should always build first, a worked example with code whose output has been checked against hand calculations, how to test on a holdout period, the libraries available when you need more, and the habits that keep a forecasting script reliable. It is part of demand planning and inventory optimization, follows demand forecasting in Excel and planning automation, leads to when your ERP forecast isn't enough and the demand planning template, and builds on Python vs. Excel for business analysis and machine learning for forecasting. Related finance context is in cash flow management.

Setup and the shape of the data

You need Python 3 and two widely used libraries: pandas for tables and time series, and numpy for numerical work. Install them with pip in a virtual environment so the project has its own dependencies. A notebook is convenient for exploring, and a plain script is better for the monthly run. Keep your code and data in a project folder under version control, with a requirements file listing the library versions you used.

The data should be in a long format: one row per item and period, with columns for the period, the item identifier and the units sold. Pandas works naturally with this shape, and you can pivot it to wide format for display. Check three things before modeling. Are the periods complete, with no missing months? Are there negative values from returns that need handling? Are there periods of stockout where sales understate demand? Fix or flag these before the forecast, because the model will learn whatever the data shows. See how to build a clean data foundation for planning.

Always build baselines first

Before any advanced model, build simple baselines and keep them in the workflow permanently. They tell you whether sophistication is adding value. Three baselines cover most needs: the naive forecast, which repeats the last value; the seasonal naive forecast, which repeats the value from the same period last year; and the moving average. If a complex model cannot beat these on a fair test, it is not helping. This is the same logic as forecast value added. See forecast value added.

A worked example

Use the same 12 months of demand as the Excel guide (illustrative): 100, 110, 105, 120, 115, 125, 130, 128, 135, 140, 138, 150. The code below defines a moving average, simple exponential smoothing and a scoring function, then compares them on months 4 to 12.

import pandas as pd
import numpy as np

demand = pd.Series(
    [100, 110, 105, 120, 115, 125, 130, 128, 135, 140, 138, 150],
    index=pd.period_range("2025-01", periods=12, freq="M"),
    name="units",
)

def moving_average(series, window=3):
    """One-step-ahead forecast: mean of the previous `window` periods."""
    return series.rolling(window).mean().shift(1)

def simple_exp_smoothing(series, alpha=0.3):
    """One-step-ahead forecast; first forecast set to the first actual."""
    forecast = [series.iloc[0]]
    for actual in series.iloc[:-1]:
        forecast.append(alpha*actual + (1 - alpha)*forecast[-1])
    return pd.Series(forecast, index=series.index)

def score(actual, forecast):
    both = pd.concat([actual, forecast], axis=1).dropna()
    a, f = both.iloc[:, 0], both.iloc[:, 1]
    err = a - f
    return {"MAPE": (err.abs() / a).mean(), "bias": err.mean()}

ma = moving_average(demand, 3)
print("MA3", score(demand.iloc[3:], ma.iloc[3:]))
for alpha in (0.1, 0.3, 0.5, 0.7, 0.9):
    ses = simple_exp_smoothing(demand, alpha)
    s = score(demand.iloc[3:], ses.iloc[3:])
    print(alpha, round(s["MAPE"]*100, 1), round(s["bias"], 1))

Running this gives the following results for months 4 to 12 (the output was run and checked against the hand calculations in the Excel guide). The three-month moving average has a MAPE of 6.5 percent and a bias of +8.6 units. Simple exponential smoothing gives a MAPE of 16.6 percent and bias of +22.1 for alpha of 0.1, 9.6 percent and +12.6 for 0.3, 6.5 percent and +8.5 for 0.5, 5.0 percent and +6.5 for 0.7, and 5.2 percent and +5.4 for 0.9. The next-period forecast is 142.7 from the moving average and 137.7 from smoothing with alpha of 0.3. A straight-line fit through the 12 points has a slope of 4.08 units a month and gives 151.2 for month 13.

Reading the results

Three things stand out. First, accuracy improves as alpha rises, and the best values, 0.7 and 0.9, are very high. A high alpha means the model is chasing the latest value, which is what you want when the series is trending and the model has no trend component. The result is a hint that a method with a trend term would fit better. Second, every method has a positive bias. All the forecasts are below the actuals, which is the signature of a rising series forecast with a model that lags. Third, the best alpha chosen on nine points is not trustworthy. Choosing parameters on the same data used to score the method flatters the result. With so little data, the safer conclusion is that a trend-aware method is needed, and that the choice should be tested on a longer history.

Testing properly: the holdout

The honest test of a forecast is how it performs on data it has not seen. Split the history into a training period and a holdout period, for example the last three or six months. Fit the method on the training data, forecast the holdout, and score the forecast against what happened. Better still, use rolling-origin evaluation: forecast one period ahead from several different cut-off points and average the scores, which gives more evidence than a single split. Always evaluate at the lead time that matters for the decision. A forecast used to place an order eight weeks ahead should be scored on its eight-week-ahead accuracy, not its one-step accuracy. Keep the scores by item group so you can see where each method works.

Adding trend and seasonality

Once the baselines are in place, add methods that capture structure. Exponential smoothing with trend and seasonality, often called Holt-Winters, is available in the statsmodels library. Libraries such as statsforecast offer fast implementations of many classical methods for thousands of series, and Prophet is a model designed for business series with holidays and changing trends. These are examples, not recommendations: check the documentation and the current state of each library, and test them against your baselines on your own data. For items with intermittent demand, with many zero periods, methods such as Croston's are designed for that pattern and are available in several libraries. Gradient boosting and other machine learning methods can use extra variables such as price, promotion flags and weather, but they need more data and more care. See machine learning for forecasting.

From item to portfolio

A real run covers every item. Structure the code as a function that takes one series and returns a forecast, and apply it to each item in a loop or with a grouped operation. Log the method used and the scores for each item. Segment the items before running: steady items get the automatic method, intermittent items get a method designed for them, and new items are left for human judgment. Save the output as a table with the item, the period, the forecast and the method, and write it to a file or database where the rest of the planning process can use it. Keep a history of each month's forecast, because you will need it to measure accuracy at the right lead time.

Habits that keep a script reliable

Put parameters such as the window length and alpha in a configuration section, not inside the functions. Write small tests for the functions using data where you know the answer, such as the hand-calculated figures above. Add checks that stop the run if the data looks wrong: missing periods, negative sales, a sudden drop in row count. Log what ran, when and on which version of the data. Avoid hard-coded file paths. Document how to run it so that a colleague can. If the script becomes important to the business, treat it like any other system: review changes, keep versions and assign an owner.

Where Python fits with Excel and planning tools

Python is a good fit for automating the data preparation, running many forecasts, testing methods and producing outputs that Excel, Power BI or a planning tool can display. Excel remains the interface for many planners, and a good pattern is for Python to write forecasts to a sheet that planners review and adjust. For teams without programming skills, the maintenance burden can outweigh the benefits, and a packaged tool may be more sensible. See demand planning software and analytics automation: what to automate first.

Common mistakes

Choosing parameters on the same data used for scoring flatters the result. Skipping baselines hides whether complexity helps. Scoring only at one-step-ahead when the decision is eight weeks out overstates accuracy. Ignoring stockouts in history teaches the model to under-forecast. Running scripts that nobody else can read or rerun creates risk. Forgetting to keep each month's forecast prevents accuracy measurement later.

FAQs

Is Python good for demand forecasting?

Yes, especially for running the same method across many items, testing methods fairly and automating data preparation. It needs someone to maintain the code.

Which Python library should I use for forecasting?

Start with pandas and numpy for baselines. Then consider statsmodels, statsforecast or Prophet, and test each against your baselines. Check current documentation.

How do I test a forecast in Python?

Hold back recent periods, forecast them from earlier data and score the errors. Use rolling-origin evaluation for more evidence.

Do I need machine learning?

Not to begin. Simple methods are often hard to beat for stable items. Machine learning helps when you have many series and useful extra variables.

Should I use Python or Excel?

Excel suits small catalogs and quick work. Python suits larger catalogs, repeated runs and testing many methods. Many teams use both.

This article is for general information. It is not accounting, tax, legal or investment advice, and examples use illustrative numbers rather than client data. Confirm decisions that carry financial or legal consequences with a qualified professional.

Better forecasts. Healthier inventory. More working capital.

Newtown Analytics advises growing consumer-product companies on demand planning and inventory optimization.