Volume II · Part III · Chapter 14

Seasonal Variation

Timothy O’Brien 17 min read Free online

When someone asks for a better capacity forecast, I’d first want to understand what’s wrong with the one they have. Perhaps the model handles seasonality poorly, or perhaps the organization keeps changing the conditions the model was supposed to describe. If the launch moved, the promotion expanded, or a new feature changed the kind of work each customer performs, those are different problems from failing to recognize a recurring pattern in the measurements.

I want a good model, and I want to know how well it performs, but I also want access to the people who can explain what the business intends to do. Otherwise we can spend a lot of time improving our estimate of what would have happened if the plan had stayed the same. The model may be doing an excellent job within its assumptions while the capacity team prepares for the wrong workload.

There is real mathematical work here, and we’ll do some of it. A forecast earns trust when it is scored against what was known on the day it was made, in the unit of the decision it served, with the business’s information kept beside the model.

How to read this chapter

This chapter is about forecasting demand that repeats: the seasonal patterns, the benchmarks that expose them, and the error measures that fit a capacity decision.

  1. First decide what you are forecasting — the work unit, interval and evidence behind the number.
  2. Start with a comparison we can understand — seasonal-naive and matching-weekday benchmarks.
  3. Recreate what you could have known — rolling origins, decision horizons, and evidence dates.
  4. Read errors in the unit of the decision — bias, scaled and percentage errors, and the quantile a purchase needs.
  5. A calendar is business information — holidays, calendar alignment, and how rarely an annual peak is observed.
  6. Put the conversation next to the model — judgmental adjustments and how to score them.
  7. What the uncertainty changes — scenarios versus calibrated intervals, and what can be bought ahead.

The lesson to carry: measure a forecast against what happened, using only what was known when it was made, and weigh the error by what it does to the decision it served.

First decide what you are forecasting

Our web-service baseline of 10,000 requests per second is the daily maximum of one-minute average offered request rates, not an instantaneous burst or a monthly average. Finance may also need a view of the billing month, and the product team may work in customer counts. Moving between those views means explaining what a customer does and when: ten thousand users making one request create different work from ten thousand users opening an AI feature that calls several services while they wait. A forecast of user growth can stay accurate while its relationship to resource demand changes substantially.

The people supplying those views should be able to trace the translation: the work unit and interval, which customers are included, the service behavior assumed, and when the estimate was made. During a migration, falling demand on the old service can look like an improvement until we count the work now arriving at its replacement. History becomes useful only once we understand changes like that in what we’re measuring.

For an Azure workload, keep the Azure Monitor resource scope, metric, aggregation, and time grain with that history. When nobody sets a time grain, metrics explorer picks one from the displayed range, so a wider view can smooth away the peak we need to plan for. Count tallies measurements while Sum adds their values, and an interval with no measurement may be stored as NULL or as zero, depending on the metric.1 If our instrumentation supplies complete one-minute totals of offered requests, a minute containing 600,000 requests represents 600,000 / 60 = 10,000 requests per second, and each day’s largest one-minute rate is the quantity our fixture forecasts. An hourly average, or a count of collected measurements, would answer a different question under the same chart title.

Our own pipeline faces the same choice. A blank interval could mean no demand, a failed collector, a shut-down service, or a changed identifier; replacing every blank with zero makes one claim about what happened, and carrying the last observation forward makes another. I don’t want that choice buried in data preparation, where everybody downstream assumes they’re looking at measurements. The companion simply stops with an error if a required matching weekday is missing; a production pipeline needs a real treatment of gaps and enough of the original evidence to tell an observed value from one supplied to make the series usable.

Start with a comparison we can understand

A seasonal-naive forecast gives us a useful starting point: it repeats the latest observation from the matching season, so next Monday’s forecast is the most recently observed Monday. Hyndman and Athanasopoulos treat it as a standard benchmark in Forecasting: Principles and Practice, with a blunt rule: a new method that can’t beat these simple alternatives isn’t worth considering.2

For daily observations with a weekly period of seven, the forecast made on day TT for hh days ahead is:

ŷT+h∣T=yT+h−7(k+1),k=⌊h−17⌋. \hat y_{T+h\mid T}=y_{T+h-7(k+1)},\qquad k=\left\lfloor\frac{h-1}{7}\right\rfloor.

The hat marks an estimate, and kk counts the whole weeks of the forecast period before the target day, so every forecast reaches back to the last observed week: we can’t use observations we don’t have yet. Our launch forecast, made on Sunday, June 28, for Monday, July 6, looks eight days ahead, so k=1k=1 and the estimate is the observation from Monday, June 22.

The companion’s sixteen weeks of constructed daily peaks rise gradually, with small variations, to 10,000 requests per second on that Monday, so the seasonal-naive estimate for July 6 is 10,000. The data are deliberately transparent so we can follow the calculations; they are not evidence about how either method will perform on your services.

For an alternative, we can average the latest four matching weekdays. If the most recent matching observation is yty_t, the calculation is:

ŷ=yt+yt−7+yt−14+yt−214. \hat y=\frac{y_t+y_{t-7}+y_{t-14}+y_{t-21}}{4}.

The final four Mondays in the fixture are 9,860, 9,910, 9,940, and 10,000, giving 39,710 / 4 = 9,927.5. Averaging reduces the influence of any one observation, but while this workload is growing it also brings older, lower demand into the estimate. Whether that helps is something we can evaluate.

We could go on to trend models, regression on business drivers, or multiple seasonal periods, but first I want a way to judge whether the extra work is useful; it’s easy to get interested in the modeling and lose sight of the decision.

Recreate what you could have known

The evaluation has to recreate what we knew when each forecast would have been made: choose a date in the past, forecast using only the information available then, compare the result with what happened, then move the date forward and repeat. Each starting date is a forecast origin; the repeated comparison, which can test tomorrow’s forecast or one made weeks ahead, is rolling-origin evaluation.3

Our companion starts after four weeks of history, advances the origin weekly, and compares both methods at one, seven, eight, fourteen, and forty-two days. Eight days corresponds to the constructed launch decision; forty-two days corresponds to the initial supply estimate. I’d want to see the latter before relying on the model for purchasing: predicting tomorrow well says little about a decision whose supply consequence arrives six weeks later. That horizon also has the fewest completed cases, seven, and their overlapping six-week windows make them far from independent.

Recreating what we knew has a further complication. An observation has a date, but the organization may receive it later: a delayed billing record can describe last month without having been available at last month’s review, and a product plan can arrive after the launch it describes. To evaluate the planning process, we need both the date of the activity and the date its evidence became available. Database designers call this bitemporal history, one timeline for when something happened and another for when we learned it;4 the companion’s date and available_on columns are a minimal version.

The fixture’s rollout record has a second revision, learned on July 8, two days after the Monday it concerns, that raises the staged increment from 2,000 to 2,800. The program keeps it out of the June 28 forecast. If it leaked in, the staged forecast would become 12,800 and match the favorable outcome later in this chapter exactly: a perfect forecast nobody could have made. We’d want the revision for today’s plan, but to judge the June 28 decision, the original version has to survive. When a team is judged by its forecast accuracy, that apparently procedural choice about version history decides whether the score says anything about the team’s work.

Read errors in the unit of the decision

Let forecast error be actual demand minus forecast demand:

eT+h=yT+h−ŷT+h∣T. e_{T+h}=y_{T+h}-\hat y_{T+h\mid T}.

With that convention, positive error means we underestimated. Mean absolute error, or MAE, averages the error magnitudes; root mean squared error, or RMSE, averages their squares and takes the square root, so large misses count for more. Both stay in requests per second, and they aim at different targets: minimizing MAE leads to forecasts of the median, minimizing RMSE to forecasts of the mean. For comparing services of very different sizes, Hyndman and Koehler proposed the mean absolute scaled error, or MASE, which divides each error by the seasonal-naive method’s average absolute error on the training data.5

Percentage errors are the familiar alternative and, for capacity, the riskiest. They’re undefined at zero demand and unstable near it, and the mean absolute percentage error, or MAPE, leans one way: an underforecast can’t miss by more than 100 percent of what happened, while an overforecast can miss by any amount. Gneiting showed that the forecast that scores best on MAPE “tends to support severe underforecasts, as compared to the mean or median.”6 A capacity team scored on MAPE is being nudged toward running short.

For the companion’s fixed methods, selected rolling results are:

Horizon Cases Seasonal-naive MAE (bias) Four-week mean MAE (bias)
1 day 12 63.33 (45.00) 116.25 (116.25)
8 days 11 94.55 (89.09) 160.68 (160.68)
42 days 7 298.57 (298.57) 367.50 (367.50)

The errors are in requests per second and can be regenerated from the companion’s CSV output, where the 7- and 14-day rows repeat the 1- and 8-day results because the fixture moves one fixed weekday profile by a weekly offset. On this rising series, the four-week mean lags enough to do worse.

Bias, the mean signed error, appears in parentheses because it belongs beside the size of the misses. Errors of plus 1,000 and minus 1,000 average to zero, although neither planning period was right. Where bias equals MAE, as it does for both methods at forty-two days and for the four-week mean throughout, every miss was an underforecast. That’s the signature of a method that can’t see the growth: change the model, find the source of the growth, or hold more room, but don’t wait for the misses to cancel.

The remaining room connects accuracy to the capacity decision. An 800-request-per-second miss may be tolerable against 10,000 of spare tested capacity and urgent against 900, and the same percentage accuracy reported for both would hide the difference. A team can improve its forecast and still be approaching an exposure it cannot tolerate.

Purchasing makes the misses asymmetric. Buying too early can create an avoidable obligation; buying too late can leave us without supply at any acceptable price. When the decision needs a high quantile, say a level next Monday’s peak should stay below 95 times in 100, the matching score is the quantile score, or pinball loss, which weights a shortfall by pp and an excess by 1−p1-p.7 At p=0.95p=0.95, a request per second of shortfall counts 0.95 / 0.05 = 19 times as much as one of idle supply. Choosing the quantile is a statement about what running short costs, and it belongs to the people who carry that cost, not to whoever configures the forecast.

We should be equally careful about how often we revisit the comparison. If we keep choosing whichever model performs best on the same history, that history has become part of the fitting, and a strong claim about the winner needs later, untouched periods.

A calendar is business information

The matching-weekday baseline handles the difference between Mondays and Sundays in our fixture. It has no information about which Monday is a holiday in a customer’s market, whether a school term changes demand, or when the business plans a promotion. Some of that can eventually become part of a model; some will stay conditional because we lack comparable history or the business is still deciding what it will do.

Annual patterns bring alignment problems of their own. A year is 52 weeks and a day, so a date falls one weekday later each year, or two after a February 29. A fixed-date holiday such as December 25 changes weekday; one defined by weekday, such as the Friday after US Thanksgiving, changes date; and Easter, Lunar New Year and Eid move against the Gregorian calendar altogether. No fixed seasonal lag lines them up, so they enter a model as calendar variables, the way Hyndman and Athanasopoulos treat Easter.8 The harder limit is the count. If the peak that sizes the capacity comes once a year, three years of history hold three observations of it, each under a different product, customer base and pricing. That’s where business knowledge carries the most weight.

Consider two customers using the same messaging platform in different markets. One is preparing for a major holiday while the other’s peak occurs at another time. If we add their individual maxima, we’re planning for those maxima to coincide; if we expect one customer’s quiet period to make room for the other, we need evidence for that expectation. I’d look at their demand on aligned calendars before deciding how much shared capacity they need.

Then I’d ask somebody familiar with the business what makes this year’s event comparable with last year’s: more customers eligible for the promotion, a changed payment process, a campaign in a different channel. Any of those changes the relationship between last year’s curve and this year’s work, even though the holiday has the same name, and the platform specialists may not be the first to learn of it.

Our sixteen weeks of history can’t establish an annual pattern at all. I don’t think the capacity team should refuse to help until the data become ideal. We use whatever comparable evidence we can defend, say where we’re making a judgment and what would make us reconsider it, and look for options that let the organization proceed while it learns more.

Put the conversation next to the model

Forecasting literature already has a place for this conversation. Hyndman and Athanasopoulos treat judgmental adjustment as the way to bring in what the model can’t see, such as a promotion, a holiday, or a recent event, and they set limits: adjust sparingly, not to chase a pattern you suspect the model missed, and document and justify each change. Their tourism case study, in which a committee’s published forecasts stayed optimistic, asks whether forecasts and targets had been confused.9 In more than 60,000 supply-chain forecasts, Fildes and colleagues found that larger adjustments tended to improve accuracy while smaller ones often damaged it, and that upward adjustments were much less likely to help than downward ones.10

For our web service, the product lead supplies the conditional increments from Volume I, Chapter 4: 2,000 requests per second for staging and 4,000 for full rollout. By that evidence, a 20 percent increase tied to a specific launch is large enough to be the kind that helps, and upward, the kind most exposed to optimism. We leave the historical baseline at 10,000 and attach the source, date, and launch conditions to the increments, so that we can later distinguish a modeling problem from a changed business plan. Volume I, Chapter 4 followed the staged forecast of 12,000 through two constructed outcomes:

Outcome Actual Baseline error Adjusted error Change in absolute error Margin after transfer
Staged launch proceeds 12,800 +2,800 +800 −2,000 700
Launch delayed 10,200 +200 −1,800 +1,600 3,300

Each error is the actual minus 10,000 or 12,000, and the margin is the 13,500 requests per second that the transfer configuration serves after losing a failure group, minus the actual. In the first outcome, the adjustment helped and still left only 700 of degraded headroom; in the second, the condition behind it didn’t occur on schedule. These are alternative constructed histories, so averaging them would tell us nothing about a real success rate.

The same event adjustment reduces error when the rollout proceeds and increases error when it is delayed. The bars show two alternative constructed outcomes.Open full-size diagram

When an adjustment misses, I’d use the review to understand which part of the reasoning needs to change. If the launch moved after the forecast, we need to understand how that decision reached us. If an update was already available and we missed it, the information path needs attention. If the event happened on schedule but produced a different request mix, we need to revisit the translation from business activity to technical demand. Treating all three as an unreliable product forecast would save us some analysis and teach us very little.

Across many events, score the unadjusted baseline and the adjusted forecast against what happened, split by the size and direction of the adjustment; demand planners call this forecast value added.11 A few launches won’t show whether a team’s adjustments help, but a year of them starts to show whether the conversations add information or optimism.

Finance’s forecast needs the same treatment. Azure Cost Analysis projects spending from historical usage with a time-series linear regression. It looks back at most 90 days, so even a year-ahead projection can’t have learned last year’s seasonal peak, and it knows nothing about our launch.12 It is Finance’s baseline in the way seasonal-naive is ours. I’d preserve its scope and forecast date, then add the launch and any change in purchasing terms as separate, dated adjustments. The two forecasts need to agree about the business plan, but they measure different consequences: a discount can lower expected spending while the busiest minute still needs more workers.

What the uncertainty changes

A prediction interval gives a range with a stated probability under a model and its assumptions. We can check whether a claimed 90 percent interval contains roughly 90 percent of later outcomes at the horizon we care about. A low-demand and a high-demand business scenario give us a different kind of range.13 Both can help a decision, but our staged 12,000 and full-rollout 14,000 cases don’t become the 50th and 95th percentiles merely because those labels would make the chart easier to present. We haven’t established those probabilities.

Checking coverage needs more evidence than it sounds. Coverage is easy to satisfy with an interval too wide to be useful, so width has to be judged alongside it, and sample size is the harder problem. With seven forty-two-day cases, an interval claimed at 90 percent that actually covered 70 percent would still contain six or seven outcomes about a third of the time, 7(0.7)6(0.3)+0.77≈0.337(0.7)^6(0.3)+0.7^7\approx0.33, and overlapping cases carry less information than independent ones. Until the history is long enough, a stated probability at the purchasing horizon is an assumption, not a measurement.

I also want to know what could make the plan wrong: ordinary error within a stable workload, a change in the workload that makes the model less applicable, a late delivery, or a shared dependency that reduces what the resources already in place can accomplish. Each needs a different response, which a wider error band alone won’t tell the decision owner.

The discussion becomes useful when we connect those mechanisms to options. A delayed rollout may let us defer the purchase. Delayed supply may mean staging longer, if the business and batch owner can accept the consequences. A changed request mix requires someone qualified to reassess the service rate. Where we have defensible probability estimates, they can inform those choices. Where we don’t, the alternatives and their conditions still deserve to be examined.

I sometimes call forecasting magic, partly because of how much judgment can disappear behind the final number. I’d rather let the reader see that judgment: why we chose the historical comparison, what we learned from the business, and where we still have to make an assumption before the decision deadline. That doesn’t eliminate guessing. It gives us something specific to revisit when the world behaves differently.

Uncertainty also changes what we can buy. Volume I, Chapter 2 showed that on scarce hardware, an elastic swing large enough to matter turns back into a reservation somebody pays for around the clock. A predictable, dated peak such as a launch week can instead be bought as dated supply, and the booking terms set the horizon the forecast has to reach. AWS takes future-dated capacity reservations 5 to 120 days ahead, recommends at least eight weeks’ notice, assesses each request against its own supply forecast and can decline it, and holds most to a fourteen-day minimum.14 Recurring windows are harder: AWS no longer sells Scheduled Reserved Instances for daily, weekly, or monthly windows, saying it has no capacity for them.15 An eight-week booking needs a forecast tested at eight weeks, beyond our forty-two-day row, and whatever the forecast can’t see at that distance has to be funded as standing headroom, which Chapter 18 takes up, or accepted as a shortfall.

As we widen the view to a portfolio, we also need to ask what makes customers change together. Good individual estimates won’t rescue the aggregate plan if a shared event invalidates many of them at once, and that dependence is where the next chapter’s calculations begin.

Notes and sources

  1. Microsoft Learn, “Azure Monitor metrics aggregation and display explained”, accessed October 3, 2026. Documents automatic time-grain selection, smoothing at coarser grains, the Sum and Count aggregations, and NULL versus zero, which each resource provider chooses for its platform metrics. The request-rate calculation is a constructed example, not a claim that every Azure service exposes that metric.↩︎

  2. Rob J. Hyndman and George Athanasopoulos, Forecasting: Principles and Practice, third edition, section 5.2, “Some simple forecasting methods,” https://otexts.com/fpp3/simple-methods.html, accessed October 3, 2026. Defines the seasonal-naive method, including its general form for horizons beyond one season, and says a new method that does not beat these benchmarks is not worth considering. The four-week matching-weekday mean and numerical fixture are constructed for this book.↩︎

  3. Hyndman and Athanasopoulos, Forecasting: Principles and Practice, section 5.10, “Time series cross-validation,” https://otexts.com/fpp3/tscv.html, accessed October 3, 2026. Describes evaluation on a rolling forecasting origin, including multi-step horizons. The companion’s weekly origins and evidence-availability dates are this book’s adaptation.↩︎

  4. Martin Fowler, “Bitemporal History”, April 7, 2021, accessed October 3, 2026. Distinguishes actual history from record history, also known as valid time and transaction time. Applying the idea to forecast evaluation is the author’s analysis.↩︎

  5. Hyndman and Athanasopoulos, Forecasting: Principles and Practice, section 5.8, “Evaluating point forecast accuracy,” https://otexts.com/fpp3/accuracy.html, checked October 4, 2026. Defines forecast errors, MAE, RMSE, and the seasonal form of MASE, which it attributes to Hyndman and Koehler (2006); notes that minimizing MAE leads to forecasts of the median and minimizing RMSE to forecasts of the mean; and describes the limitations of percentage errors. The consequences for this portfolio are the author’s analysis.↩︎

  6. Tilmann Gneiting, “Making and Evaluating Point Forecasts,” Journal of the American Statistical Association 106, no. 494 (2011): 746–762, https://doi.org/10.1198/jasa.2011.r10138; preprint https://arxiv.org/abs/0912.0902, checked October 4, 2026. Shows that the absolute percentage error is consistent for a non-standard functional, the median of order −1, rather than for the mean or median; the quoted phrase is from the preprint. The consequence for how capacity teams are scored is the author’s inference.↩︎

  7. Hyndman and Athanasopoulos, Forecasting: Principles and Practice, section 5.9, “Evaluating distributional forecast accuracy,” https://otexts.com/fpp3/distaccuracy.html, accessed October 3, 2026. Defines the quantile score, or pinball loss, which penalizes an observation above the forecast quantile in proportion to pp and one below it in proportion to 1−p1-p. Reading the 19-to-1 ratio as a cost ratio is the author’s interpretation and assumes costs that grow linearly with the miss.↩︎

  8. Hyndman and Athanasopoulos, Forecasting: Principles and Practice, section 7.4, “Some useful predictors,” https://otexts.com/fpp3/useful-predictors.html, accessed October 3, 2026. Uses dummy variables for public holidays and for Easter, whose date moves from year to year. The weekday arithmetic and the point about annual peaks are the author’s.↩︎

  9. Hyndman and Athanasopoulos, Forecasting: Principles and Practice, section 6.7, “Judgmental adjustments,” https://otexts.com/fpp3/judgmental-adjustments.html, checked October 4, 2026. Recommends adjusting sparingly, for important information the model lacks and not to correct a pattern it is thought to have missed; reports that small adjustments, especially upward ones, hinder accuracy; recommends documenting and justifying adjustments; and presents the Tourism Forecasting Committee example. It does not establish that every relationship-derived adjustment improves a forecast.↩︎

  10. Robert Fildes, Paul Goodwin, Michael Lawrence, and Konstantinos Nikolopoulos, “Effective Forecasting and Judgmental Adjustments: An Empirical Evaluation and Strategies for Improvement in Supply-Chain Planning,” International Journal of Forecasting 25, no. 1 (2009): 3–23, https://doi.org/10.1016/j.ijforecast.2008.11.010, accessed October 3, 2026. More than 60,000 forecasts from three manufacturers and a retailer; adjustments improved average accuracy in three of the four companies, and upward adjustments were more often in the wrong direction, consistent with optimism. The data describe product demand, not computing workloads.↩︎

  11. Michael Gilliland, “FVA: A Reality Check on Forecasting Practices,” Foresight: The International Journal of Applied Forecasting, no. 29 (Spring 2013): 14–18, https://forecasters.org/wp-content/uploads/FVA_A-Reality-Check_Foresight29.pdf, accessed October 3, 2026. Defines forecast value added as the change in a forecasting performance metric attributable to a particular step or participant in the process, starting from a naive forecast. Applying it to capacity adjustments is the author’s suggestion.↩︎

  12. Microsoft Learn, “Quickstart: Start using Cost Analysis,” section “Forecasting costs in Cost Analysis”, checked October 4, 2026. The forecast uses historical usage and a time-series linear regression model, changes with the period and filters selected, and looks back 28 days for forecasts up to 28 days, the forecast’s own length up to 90 days, and 90 days beyond that. That it cannot learn an annual peak is the author’s inference from the lookback.↩︎

  13. Hyndman and Athanasopoulos, Forecasting: Principles and Practice, section 5.5, “Distributional forecasts and prediction intervals,” https://otexts.com/fpp3/prediction-intervals.html, accessed October 3, 2026. Supports the distinction between point forecasts, forecast distributions, and prediction intervals; this book’s rollout scenarios are not calibrated intervals.↩︎

  14. Amazon Web Services, “Concepts for Amazon EC2 Capacity Reservations”, checked October 4, 2026. Future-dated requests 5 to 120 days ahead, at least 56 days recommended, assessed partly against forecast supply and possibly unsupported; minimum commitment 14 days for most instance types and 12 weeks for U and X; minimum 32 vCPUs. Eligible instance types and terms change over time.↩︎

  15. Jeff Barr, “New – Scheduled Reserved Instances”, AWS News Blog, January 13, 2016, with an update dated September 3, 2024, accessed October 3, 2026. The original offer covered recurring daily, weekly, or monthly windows on a one-year term; the update says they can no longer be purchased and that AWS has no capacity available or plans to make it available.↩︎