Skip to content
Preptima
mediumConceptScenarioMidSeniorStaff

Walk me through what you check for stationarity and seasonality, and what you do about what you find.

Plot the series first, then use a decomposition and an ADF or KPSS test to separate trend from seasonality from noise. Difference or transform away a trend, use Fourier terms when several seasonal periods coexist, and treat holidays and calendar structure as features rather than outliers.

5 min readUpdated 2026-07-28
Practice answering out loud

What the interviewer is scoring

  • Does the candidate look at the plot before reaching for a test
  • Whether stationarity is stated in terms of mean, variance and autocovariance rather than as a vague notion of stability
  • That over-differencing is recognised as a cost, not just under-differencing as a fault
  • Whether multiple simultaneous seasonalities are handled with a method that scales, not with more dummy variables
  • Can the candidate distinguish a fixed-date holiday from a moving one operationally

Answer

Look at the series before testing anything

The first check is a plot, and it is not a formality. A visible upward drift, a variance that widens as the level rises, a step change at a known date, a repeating weekly shape, a run of zeros where a sensor was offline — all of these are obvious in thirty seconds and all of them change what you do next. A test statistic reduces the series to one number and will not tell you that the trend reversed halfway through.

Plot the autocorrelation function alongside it. Slow, near-linear decay across many lags indicates a trend or a unit root. Spikes at regular multiples of a lag indicate seasonality and tell you the period. A single spike at lag one that then collapses suggests a series already close to stationary.

What stationarity is and why it is required

A stationary series has a constant mean, a constant variance, and an autocovariance that depends only on the separation between two points rather than on where in the series they sit. Weak stationarity is what practice means by the term, and it is the assumption underneath ARIMA-family models: they estimate coefficients on the assumption that the relationship between a point and its lags is the same everywhere in the series.

If the series has a trend, that assumption fails and the estimates are not meaningful. Two unrelated series that both trend upwards will appear correlated, which is the spurious-regression problem, and it is why the check comes before the model rather than after a disappointing result.

Two tests are worth knowing and they are complementary because their null hypotheses are opposites. The augmented Dickey-Fuller test has non-stationarity as its null, so a small p-value is evidence for stationarity. The KPSS test has stationarity as its null, so a small p-value is evidence against it. Running both is the standard practice, and the informative case is when they disagree: that usually means the series is trend-stationary rather than containing a unit root, which is a different remedy — detrend rather than difference.

Differencing, transforming and decomposition

Differencing replaces each value with the change since the previous value, which removes a linear trend. Doing it once is usually enough, and twice is occasionally justified for a series whose trend itself accelerates. A seasonal difference subtracts the value from one full period earlier, which removes a stable seasonal pattern along with any trend that is constant across periods.

The under-discussed direction is over-differencing. Each difference amplifies noise and injects artificial negative autocorrelation at lag one, so a series differenced more than it needed is harder to forecast than the original. The symptom is an ACF with a large negative spike at lag one where the undifferenced series had none. Difference the minimum amount that passes your tests and no more.

Variance is a separate problem from mean. If the series fans out as its level rises, differencing will not fix it, because the issue is multiplicative. A log transform converts multiplicative growth into additive growth and stabilises the variance, which is why so many demand and revenue series are modelled in logs. The consequence to remember is that a forecast made in log space and exponentiated back is a median rather than a mean, so if you are aggregating forecasts into a budget total you have to correct for that rather than sum them naively.

Decomposition splits the series into trend, seasonal and remainder components, additively or multiplicatively. Its main use is diagnostic: the remainder is where you look for the anomalies and structural breaks that the level and the seasonal shape were hiding. STL decomposition handles a seasonal shape that changes gradually over the years, which classical decomposition assumes away.

Multiple seasonalities at once

Hourly and daily series routinely carry several periods simultaneously. Electricity demand has a daily profile, a weekly profile because weekends differ, and an annual profile driven by temperature and daylight. A single seasonal difference cannot represent that, and a classical seasonal ARIMA term handles one period.

Dummy variables are the naive answer and they scale badly. Hour-of-week alone is 167 indicators, annual day-of-year is 365, and the interaction is unusable — each dummy is estimated from very few observations, so the fit is noisy and does not generalise.

The scalable answer is Fourier terms: for each seasonal period, add a small number of sine and cosine pairs at that period and its harmonics as regressors. Three or four pairs will describe a smooth daily shape with eight parameters rather than twenty-four, several periods can coexist because each simply contributes its own pairs, and the number of pairs is a tunable smoothness control chosen by backtest. This is the mechanism behind the seasonality components of the widely used additive forecasting models, and it composes with any regression-based approach.

# One Fourier pair per harmonic k, for a period of 168 hours (one week).
for k in range(1, 4):
    df[f"wk_sin{k}"] = np.sin(2 * np.pi * k * df["hour_index"] / 168)
    df[f"wk_cos{k}"] = np.cos(2 * np.pi * k * df["hour_index"] / 168)

Holidays and the calendar are features, not outliers

The most common practical error is treating calendar effects as noise. Christmas, a bank holiday weekend, or a national election produces a large residual, and excluding it as an outlier throws away information that will recur on a known future date. It is knowable in advance, so it belongs in the model as a regressor.

Fixed-date holidays are straightforward. Moving ones are where the work is: Easter shifts by more than a month across years, Diwali and Eid move against the Gregorian calendar, and a bank holiday that falls on a Monday shifts trade into the preceding Saturday. So an indicator on the day itself is rarely enough — you need a window around it, and separate indicators for the days before and after, because demand usually pulls forward and then collapses rather than simply spiking.

The rest of the calendar deserves the same treatment. Month-end and quarter-end drive business processes. Paydays drive consumer spending. The number of trading days in a month varies and will otherwise show up as unexplained monthly variation. Whether a holiday fell midweek or adjacent to a weekend changes its effect substantially. Each of these is a cheap feature that removes a residual you would otherwise be trying to model as seasonality, and getting them right usually improves accuracy more than swapping model families does.

Likely follow-ups

  • ADF says stationary and KPSS says not. What do you conclude?
  • Why would you use a log transform rather than a seasonal difference?
  • How would you encode Easter, and why is it harder than Christmas?
  • Which of these steps become unnecessary if you use a gradient-boosted model on lag features?

Related questions

Further reading

stationarityseasonalitydifferencingtime-seriesfeature-engineering