Most forecasts I see in small and mid-sized companies live in a spreadsheet. Someone takes last year's number, adds a growth percentage that feels about right, and everyone nods. It works until it doesn't, usually in the month a promotion lands badly or a supplier slips.
You don't need a data science team to do better than that. You need a baseline, a fair way to test it, and the patience to stop before the model gets fancy.
Start with the dumbest forecast you can think of
Before anything clever, write down two simple forecasts.
- Same as last period. Next week will look like this week.
- Same as the same period last year. Next week will look like this week twelve months ago.
These are called naive and seasonal naive forecasts, and they are your yardstick. If a cleverer method can't beat them, it isn't earning its keep. You'd be surprised how often that happens. Seasonal naive in particular is hard to beat for products with a strong yearly pattern.
Test it the way you'd actually use it
This is the part people skip. Don't judge a forecast on the data it learned from, because almost any method looks good there.
Instead, hide the most recent stretch of data, say the last twelve weeks. Build the forecast using everything before that, then compare it with what really happened. If you plan to forecast three months ahead in real life, hide three months. The test should look like the job.
For the score, I like weighted absolute percentage error (WAPE): add up the absolute errors across all periods and divide by total actual sales. It's easy to explain ("we were off by 14 percent of volume") and, unlike the more common MAPE, it doesn't blow up when a slow week has two units in it.
A first model in a few lines of Python
If you have two or more years of weekly data, exponential smoothing with a seasonal pattern (often called Holt-Winters) is a good next step. It's old, it's quick, and it's easy to inspect.
import pandas as pd
from statsmodels.tsa.holtwinters import ExponentialSmoothing
sales = pd.read_csv("weekly_sales.csv", parse_dates=["week"], index_col="week")["units"]
sales = sales.asfreq("W-MON") # one row per week, no gaps
train, test = sales[:-12], sales[-12:]
same_week_last_year = sales.shift(52).loc[test.index]
model = ExponentialSmoothing(
train, trend="add", seasonal="add", seasonal_periods=52
).fit()
holt_winters = model.forecast(12)
def wape(actual, pred):
return (actual - pred).abs().sum() / actual.abs().sum()
print("last year :", round(wape(test, same_week_last_year), 3))
print("holt-winters:", round(wape(test, holt_winters), 3))
Two things to watch. The seasonal version needs at least two full years of history to learn a yearly pattern. And it expects a regular series, so fill in missing weeks first. A week with no sales and a week with no data are not the same thing.
Look at where it's wrong
An overall error number hides a lot. Break it down by product, by region or by month, and look at the biggest misses. Usually the pattern is obvious once you see it: a product that was out of stock (so sales understated demand), a promotion nobody told you about, a launch with no history at all.
That list of misses is more valuable than the model. It tells you what extra information is worth adding, and it's often information the business already has, such as a promotion calendar or stock levels.
Give a range, not a single number
Single-number forecasts invite false confidence. If your test shows you're typically off by 15 percent, say so. "We expect around 4,000 units, and between 3,400 and 4,600 is normal" lets the people ordering stock make a sensible call, because they can weigh the cost of running out against the cost of holding too much.
When to stop
A decent rule: stop adding complexity when the next idea improves the test score by less than the usual noise from one period to the next. Past that point you're tuning to the past.
Also, be honest about what a forecast can't do. It won't see a competitor's price cut or a change in your own marketing that has no history behind it. Those are for people to judge, ideally with the forecast as the starting point rather than the final word.
If you want a hand setting up a first forecast and a way to track how well it does, that's the kind of work we do under predictive modelling.